def test_function_symbol_array(ctx_factory, array_type): ctx = ctx_factory() queue = cl.CommandQueue(ctx) actx = PyOpenCLArrayContext(queue) from meshmode.mesh.generation import generate_regular_rect_mesh dim = 2 mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(8, ) * dim, order=4) discr = DGDiscretizationWithBoundaries(actx, mesh, order=4) volume_discr = discr.discr_from_dd(sym.DD_VOLUME) ndofs = sum(grp.ndofs for grp in volume_discr.groups) import pyopencl.clrandom # noqa: F401 if array_type == "scalar": sym_x = sym.var("x") x = unflatten(actx, volume_discr, cl.clrandom.rand(queue, ndofs, dtype=np.float)) elif array_type == "vector": sym_x = sym.make_sym_array("x", dim) x = make_obj_array([ unflatten(actx, volume_discr, cl.clrandom.rand(queue, ndofs, dtype=np.float)) for _ in range(dim) ]) else: raise ValueError("unknown array type") norm = bind(discr, sym.norm(2, sym_x))(x=x) assert isinstance(norm, float)
def test_flatten_unflatten(actx_factory): actx = actx_factory() ambient_dim = 2 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim, b=(+0.5, ) * ambient_dim, n=(3, ) * ambient_dim, order=1) discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(3)) a = np.random.randn(discr.ndofs) from meshmode.dof_array import flatten, unflatten a_round_trip = actx.to_numpy( flatten(unflatten(actx, discr, actx.from_numpy(a)))) assert np.array_equal(a, a_round_trip) from meshmode.dof_array import flatten_to_numpy, unflatten_from_numpy a_round_trip = flatten_to_numpy(actx, unflatten_from_numpy(actx, discr, a)) assert np.array_equal(a, a_round_trip) x = thaw(discr.nodes(), actx) avg_mass = DOFArray( actx, tuple([(np.pi + actx.zeros((grp.nelements, 1), a.dtype)) for grp in discr.groups])) c = MyContainer(name="flatten", mass=avg_mass, momentum=make_obj_array([x, x, x]), enthalpy=x) from meshmode.dof_array import unflatten_like c_round_trip = unflatten_like(actx, flatten(c), c) assert flat_norm(c - c_round_trip) < 1.0e-8
def unflatten_from_numpy(actx, discr, ary): from pytools.obj_array import obj_array_vectorize from meshmode.dof_array import unflatten ary = obj_array_vectorize(actx.from_numpy, ary) if discr is None: return ary else: return unflatten(actx, discr, ary)
def finish(self): self.recv_req.Wait() actx = self.array_context remote_dof_array = unflatten(self.array_context, self.bdry_discr, actx.from_numpy(self.remote_data_host)) bdry_conn = self.discrwb.get_distributed_boundary_swap_connection( sym.as_dofdesc(sym.DTAG_BOUNDARY(self.remote_btag))) swapped_remote_dof_array = bdry_conn(remote_dof_array) self.send_req.Wait() return TracePair(self.remote_btag, self.local_dof_array, swapped_remote_dof_array)
def plot_partition_indices(actx, discr, indices, **kwargs): try: import matplotlib.pyplot as pt except ImportError: return indices = indices.get(actx.queue) args = [ kwargs.get("tree_kind", "linear").replace("-", "_"), kwargs.get("discr_stage", "stage1"), discr.ambient_dim ] pt.figure(figsize=(10, 8), dpi=300) pt.plot(np.diff(indices.ranges)) pt.savefig("test_partition_{1}_{3}d_ranges_{2}.png".format(*args)) pt.clf() from pytential.utils import flatten_to_numpy if discr.ambient_dim == 2: sources = flatten_to_numpy(actx, discr.nodes()) pt.figure(figsize=(10, 8), dpi=300) if indices.indices.shape[0] != discr.ndofs: pt.plot(sources[0], sources[1], 'ko', alpha=0.5) for i in range(indices.nblocks): isrc = indices.block_indices(i) pt.plot(sources[0][isrc], sources[1][isrc], 'o') pt.xlim([-1.5, 1.5]) pt.ylim([-1.5, 1.5]) pt.savefig("test_partition_{1}_{3}d_{2}.png".format(*args)) pt.clf() elif discr.ambient_dim == 3: from meshmode.discretization.visualization import make_visualizer marker = -42.0 * np.ones(discr.ndofs) for i in range(indices.nblocks): isrc = indices.block_indices(i) marker[isrc] = 10.0 * (i + 1.0) from meshmode.dof_array import unflatten marker = unflatten(actx, discr, actx.from_numpy(marker)) vis = make_visualizer(actx, discr, 10) filename = "test_partition_{0}_{1}_{3}d_{2}.vtu".format(*args) vis.write_vtk_file(filename, [("marker", marker)])
def unflatten(self, ary): # Convert a flat version of *ary* into a structured version. components = [] for discr, (start, end) in zip(self.discrs, self.starts_and_ends): component = ary[start:end] from meshmode.discretization import Discretization if isinstance(discr, Discretization): from meshmode.dof_array import unflatten component = unflatten(self.array_context, discr, component) components.append(component) if self._operator_uses_obj_array: from pytools.obj_array import make_obj_array return make_obj_array(components) else: return components[0]
def exec_compute_potential_insn_direct(self, actx: PyOpenCLArrayContext, insn, bound_expr, evaluate): kernel_args = {} from pytential.utils import flatten_if_needed from meshmode.dof_array import flatten, thaw, unflatten for arg_name, arg_expr in insn.kernel_arguments.items(): kernel_args[arg_name] = flatten_if_needed(actx, evaluate(arg_expr)) from pytential import bind, sym waa = bind(bound_expr.places, sym.weights_and_area_elements( self.ambient_dim, dofdesc=insn.source))(actx) strengths = [waa * evaluate(density) for density in insn.densities] flat_strengths = [flatten(strength) for strength in strengths] results = [] p2p = None for o in insn.outputs: target_discr = bound_expr.places.get_discretization( o.target_name.geometry, o.target_name.discr_stage) if p2p is None: p2p = self.get_p2p(actx, source_kernels=insn.source_kernels, target_kernels=insn.target_kernels) evt, output_for_each_kernel = p2p(actx.queue, flatten_if_needed(actx, target_discr.nodes()), flatten(thaw(actx, self.density_discr.nodes())), flat_strengths, **kernel_args) from meshmode.discretization import Discretization result = output_for_each_kernel[o.target_kernel_index] if isinstance(target_discr, Discretization): result = unflatten(actx, target_discr, result) results.append((o.name, result)) timing_data = {} return results, timing_data
def test_array_context_np_workalike(actx_factory): actx = actx_factory() from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(-0.5,)*2, b=(0.5,)*2, n=(8,)*2, order=3) discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(3)) for sym_name, n_args in [ ("sin", 1), ("exp", 1), ("arctan2", 2), ("minimum", 2), ("maximum", 2), ("where", 3), ("conj", 1), ]: args = [np.random.randn(discr.ndofs) for i in range(n_args)] ref_result = getattr(np, sym_name)(*args) # {{{ test DOFArrays actx_args = [unflatten(actx, discr, actx.from_numpy(arg)) for arg in args] actx_result = actx.to_numpy( flatten(getattr(actx.np, sym_name)(*actx_args))) assert np.allclose(actx_result, ref_result) # }}} # {{{ test object arrays of DOFArrays obj_array_args = [make_obj_array([arg]) for arg in actx_args] obj_array_result = actx.to_numpy( flatten(getattr(actx.np, sym_name)(*obj_array_args)[0])) assert np.allclose(obj_array_result, ref_result)
def exec_compute_potential_insn(self, actx, insn, bound_expr, evaluate, return_timing_data): if return_timing_data: from warnings import warn warn("Timing data collection not supported.", category=UnableToCollectTimingData) p2p = None kernel_args = {} for arg_name, arg_expr in insn.kernel_arguments.items(): kernel_args[arg_name] = evaluate(arg_expr) strengths = evaluate(insn.density) # FIXME: Do this all at once results = [] for o in insn.outputs: target_discr = bound_expr.places.get_discretization( o.target_name.geometry, o.target_name.discr_stage) # no on-disk kernel caching if p2p is None: p2p = self.get_p2p(actx, insn.kernels) from pytential.utils import flatten_if_needed evt, output_for_each_kernel = p2p( actx.queue, flatten_if_needed(actx, target_discr.nodes()), self._nodes, [strengths], **kernel_args) from meshmode.discretization import Discretization result = output_for_each_kernel[o.kernel_index] if isinstance(target_discr, Discretization): from meshmode.dof_array import unflatten result = unflatten(actx, target_discr, result) results.append((o.name, result)) timing_data = {} return results, timing_data
def test_sphere_eigenvalues(ctx_factory, mode_m, mode_n, qbx_order, fmm_backend): logging.basicConfig(level=logging.INFO) special = pytest.importorskip("scipy.special") cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) target_order = 8 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource from pytools.convergence import EOCRecorder s_eoc_rec = EOCRecorder() d_eoc_rec = EOCRecorder() sp_eoc_rec = EOCRecorder() dp_eoc_rec = EOCRecorder() def rel_err(comp, ref): return (norm(density_discr, comp - ref) / norm(density_discr, ref)) for nrefinements in [0, 1]: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) from meshmode.mesh.refinement import Refiner refiner = Refiner(mesh) for i in range(nrefinements): flags = np.ones(mesh.nelements, dtype=bool) refiner.refine(flags) mesh = refiner.get_current_mesh() pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=6, fmm_backend=fmm_backend, ) places = GeometryCollection(qbx) from meshmode.dof_array import flatten, unflatten, thaw density_discr = places.get_discretization(places.auto_source.geometry) nodes = thaw(actx, density_discr.nodes()) r = actx.np.sqrt(nodes[0] * nodes[0] + nodes[1] * nodes[1] + nodes[2] * nodes[2]) phi = actx.np.arccos(nodes[2] / r) theta = actx.np.arctan2(nodes[0], nodes[1]) ymn = unflatten( actx, density_discr, actx.from_numpy( special.sph_harm(mode_m, mode_n, actx.to_numpy(flatten(theta)), actx.to_numpy(flatten(phi))))) from sumpy.kernel import LaplaceKernel lap_knl = LaplaceKernel(3) # {{{ single layer s_sigma_op = bind( places, sym.S(lap_knl, sym.var("sigma"), qbx_forced_limit=+1)) s_sigma = s_sigma_op(actx, sigma=ymn) s_eigval = 1 / (2 * mode_n + 1) h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx) s_eoc_rec.add_data_point(h_max, rel_err(s_sigma, s_eigval * ymn)) # }}} # {{{ double layer d_sigma_op = bind( places, sym.D(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) d_sigma = d_sigma_op(actx, sigma=ymn) d_eigval = -1 / (2 * (2 * mode_n + 1)) d_eoc_rec.add_data_point(h_max, rel_err(d_sigma, d_eigval * ymn)) # }}} # {{{ S' sp_sigma_op = bind( places, sym.Sp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) sp_sigma = sp_sigma_op(actx, sigma=ymn) sp_eigval = -1 / (2 * (2 * mode_n + 1)) sp_eoc_rec.add_data_point(h_max, rel_err(sp_sigma, sp_eigval * ymn)) # }}} # {{{ D' dp_sigma_op = bind( places, sym.Dp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) dp_sigma = dp_sigma_op(actx, sigma=ymn) dp_eigval = -(mode_n * (mode_n + 1)) / (2 * mode_n + 1) dp_eoc_rec.add_data_point(h_max, rel_err(dp_sigma, dp_eigval * ymn)) # }}} print("Errors for S:") print(s_eoc_rec) required_order = qbx_order + 1 assert s_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D:") print(d_eoc_rec) required_order = qbx_order assert d_eoc_rec.order_estimate() > required_order - 0.5 print("Errors for S':") print(sp_eoc_rec) required_order = qbx_order assert sp_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D':") print(dp_eoc_rec) required_order = qbx_order assert dp_eoc_rec.order_estimate() > required_order - 1.5
def main(mesh_name="ellipsoid"): import logging logger = logging.getLogger(__name__) logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) if mesh_name == "ellipsoid": cad_file_name = "geometries/ellipsoid.step" h = 0.6 elif mesh_name == "two-cylinders": cad_file_name = "geometries/two-cylinders-smooth.step" h = 0.4 else: raise ValueError("unknown mesh name: %s" % mesh_name) from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource(cad_file_name), 2, order=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h], target_unit="MM") from meshmode.mesh.processing import perform_flips # Flip elements--gmsh generates inside-out geometry. mesh = perform_flips(mesh, np.ones(mesh.nelements)) from meshmode.mesh.processing import find_bounding_box bbox_min, bbox_max = find_bounding_box(mesh) bbox_center = 0.5 * (bbox_min + bbox_max) bbox_size = max(bbox_max - bbox_min) / 2 logger.info("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(density_discr, 4 * target_order, qbx_order, fmm_order=qbx_order + 3, target_association_tolerance=0.15) from pytential.target import PointsTarget fplot = FieldPlotter(bbox_center, extent=3.5 * bbox_size, npoints=150) from pytential import GeometryCollection places = GeometryCollection( { "qbx": qbx, "targets": PointsTarget(fplot.points) }, auto_where="qbx") density_discr = places.get_discretization("qbx") nodes = thaw(actx, density_discr.nodes()) angle = actx.np.arctan2(nodes[1], nodes[0]) if k: kernel = HelmholtzKernel(3) else: kernel = LaplaceKernel(3) #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None)) op = sym.D(kernel, sym.var("sigma"), qbx_forced_limit=None) #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None) sigma = actx.np.cos(mode_nr * angle) if 0: from meshmode.dof_array import flatten, unflatten sigma = flatten(0 * angle) from random import randrange for i in range(5): sigma[randrange(len(sigma))] = 1 sigma = unflatten(actx, density_discr, sigma) if isinstance(kernel, HelmholtzKernel): for i, elem in np.ndenumerate(sigma): sigma[i] = elem.astype(np.complex128) fld_in_vol = actx.to_numpy( bind(places, op, auto_where=("qbx", "targets"))(actx, sigma=sigma, k=k)) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("layerpot-3d-potential.vts", [("potential", fld_in_vol)]) bdry_normals = bind(places, sym.normal( density_discr.ambient_dim))(actx).as_vector(dtype=object) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(actx, density_discr, target_order) bdry_vis.write_vtk_file("layerpot-3d-density.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ])
def main(ctx_factory=cl.create_some_context, snapshot_pattern="flame1d-{step:06d}-{rank:04d}.pkl", restart_step=None, use_profiling=False, use_logmgr=False): """Drive the Y0 example.""" from mpi4py import MPI comm = MPI.COMM_WORLD rank = 0 rank = comm.Get_rank() nparts = comm.Get_size() """logging and profiling""" logmgr = initialize_logmgr(use_logmgr, filename="flame1d.sqlite", mode="wo", mpi_comm=comm) cl_ctx = ctx_factory() 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))) #nviz = 500 #nrestart = 500 nviz = 1 nrestart = 3 #current_dt = 5.0e-8 # stable with euler current_dt = 5.0e-8 # stable with rk4 #current_dt = 4e-7 # stable with lrsrk144 t_final = 1.5e-7 dim = 2 order = 1 exittol = 1000000000000 #t_final = 0.001 current_cfl = 1.0 current_t = 0 constant_cfl = False nstatus = 10000000000 rank = 0 checkpoint_t = current_t current_step = 0 vel_burned = np.zeros(shape=(dim, )) vel_unburned = np.zeros(shape=(dim, )) # {{{ Set up initial state using Cantera # Use Cantera for initialization # -- Pick up a CTI for the thermochemistry config # --- Note: Users may add their own CTI file by dropping it into # --- mirgecom/mechanisms alongside the other CTI files. from mirgecom.mechanisms import get_mechanism_cti # uiuc C2H4 #mech_cti = get_mechanism_cti("uiuc") # sanDiego H2 mech_cti = get_mechanism_cti("sanDiego") cantera_soln = cantera.Solution(phase_id="gas", source=mech_cti) nspecies = cantera_soln.n_species # Initial temperature, pressure, and mixutre mole fractions are needed to # set up the initial state in Cantera. temp_unburned = 300.0 temp_ignition = 1500.0 # Parameters for calculating the amounts of fuel, oxidizer, and inert species equiv_ratio = 1.0 ox_di_ratio = 0.21 # H2 stoich_ratio = 0.5 #C2H4 #stoich_ratio = 3.0 # Grab the array indices for the specific species, ethylene, oxygen, and nitrogen # C2H4 #i_fu = cantera_soln.species_index("C2H4") # H2 i_fu = cantera_soln.species_index("H2") i_ox = cantera_soln.species_index("O2") i_di = cantera_soln.species_index("N2") x = np.zeros(nspecies) # Set the species mole fractions according to our desired fuel/air mixture x[i_fu] = (ox_di_ratio * equiv_ratio) / (stoich_ratio + ox_di_ratio * equiv_ratio) x[i_ox] = stoich_ratio * x[i_fu] / equiv_ratio x[i_di] = (1.0 - ox_di_ratio) * x[i_ox] / ox_di_ratio # Uncomment next line to make pylint fail when it can't find cantera.one_atm one_atm = cantera.one_atm # pylint: disable=no-member # one_atm = 101325.0 pres_unburned = one_atm # Let the user know about how Cantera is being initilized print(f"Input state (T,P,X) = ({temp_unburned}, {pres_unburned}, {x}") # Set Cantera internal gas temperature, pressure, and mole fractios cantera_soln.TPX = temp_unburned, pres_unburned, x # Pull temperature, total density, mass fractions, and pressure from Cantera # We need total density, and mass fractions to initialize the fluid/gas state. y_unburned = np.zeros(nspecies) can_t, rho_unburned, y_unburned = cantera_soln.TDY can_p = cantera_soln.P # *can_t*, *can_p* should not differ (significantly) from user's initial data, # but we want to ensure that we use exactly the same starting point as Cantera, # so we use Cantera's version of these data. # now find the conditions for the burned gas cantera_soln.equilibrate('TP') temp_burned, rho_burned, y_burned = cantera_soln.TDY pres_burned = cantera_soln.P casename = "flame1d" pyrometheus_mechanism = pyro.get_thermochem_class(cantera_soln)(actx.np) # C2H4 mu = 1.e-5 kappa = 1.6e-5 # Pr = mu*rho/alpha = 0.75 # H2 mu = 1.e-5 kappa = mu * 0.08988 / 0.75 # Pr = mu*rho/alpha = 0.75 species_diffusivity = 1.e-5 * np.ones(nspecies) transport_model = SimpleTransport(viscosity=mu, thermal_conductivity=kappa, species_diffusivity=species_diffusivity) eos = PyrometheusMixture(pyrometheus_mechanism, temperature_guess=temp_unburned, transport_model=transport_model) species_names = pyrometheus_mechanism.species_names print(f"Pyrometheus mechanism species names {species_names}") print( f"Unburned state (T,P,Y) = ({temp_unburned}, {pres_unburned}, {y_unburned}" ) print(f"Burned state (T,P,Y) = ({temp_burned}, {pres_burned}, {y_burned}") flame_start_loc = 0.05 flame_speed = 1000 # use the burned conditions with a lower temperature bulk_init = PlanarDiscontinuity(dim=dim, disc_location=flame_start_loc, sigma=0.01, nspecies=nspecies, temperature_left=temp_ignition, temperature_right=temp_unburned, pressure_left=pres_burned, pressure_right=pres_unburned, velocity_left=vel_burned, velocity_right=vel_unburned, species_mass_left=y_burned, species_mass_right=y_unburned) inflow_init = MixtureInitializer(dim=dim, nspecies=nspecies, pressure=pres_burned, temperature=temp_ignition, massfractions=y_burned, velocity=vel_burned) outflow_init = MixtureInitializer(dim=dim, nspecies=nspecies, pressure=pres_unburned, temperature=temp_unburned, massfractions=y_unburned, velocity=vel_unburned) inflow = PrescribedViscousBoundary(q_func=inflow_init) outflow = PrescribedViscousBoundary(q_func=outflow_init) wall = PrescribedViscousBoundary( ) # essentially a "dummy" use the interior solution for the exterior from grudge import sym boundaries = { sym.DTAG_BOUNDARY("Inflow"): inflow, sym.DTAG_BOUNDARY("Outflow"): outflow, sym.DTAG_BOUNDARY("Wall"): wall } if restart_step is None: char_len = 0.001 box_ll = (0.0, 0.0) box_ur = (0.25, 0.01) num_elements = (int((box_ur[0] - box_ll[0]) / char_len), int((box_ur[1] - box_ll[1]) / char_len)) from meshmode.mesh.generation import generate_regular_rect_mesh generate_mesh = partial(generate_regular_rect_mesh, a=box_ll, b=box_ur, n=num_elements, mesh_type="X", boundary_tag_to_face={ "Inflow": ["-x"], "Outflow": ["+x"], "Wall": ["+y", "-y"] }) local_mesh, global_nelements = generate_and_distribute_mesh( comm, generate_mesh) local_nelements = local_mesh.nelements else: # Restart with open(snapshot_pattern.format(step=restart_step, rank=rank), "rb") as f: restart_data = pickle.load(f) local_mesh = restart_data["local_mesh"] local_nelements = local_mesh.nelements global_nelements = restart_data["global_nelements"] assert comm.Get_size() == restart_data["num_parts"] if rank == 0: logging.info("Making discretization") discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) nodes = thaw(actx, discr.nodes()) if restart_step is None: if rank == 0: logging.info("Initializing soln.") # for Discontinuity initial conditions current_state = bulk_init(t=0., x_vec=nodes, eos=eos) # for uniform background initial condition #current_state = bulk_init(nodes, eos=eos) else: current_t = restart_data["t"] current_step = restart_step current_state = unflatten( actx, discr.discr_from_dd("vol"), obj_array_vectorize(actx.from_numpy, restart_data["state"])) vis_timer = None if logmgr: logmgr_add_cl_device_info(logmgr, queue) logmgr_add_many_discretization_quantities(logmgr, discr, dim, extract_vars_for_logging, units_for_logging) logmgr.add_watches([ "step.max", "t_sim.max", "t_step.max", "t_log.max", "min_pressure", "max_pressure", "min_temperature", "max_temperature" ]) try: logmgr.add_watches( ["memory_usage_python.max", "memory_usage_gpu.max"]) except KeyError: pass if use_profiling: logmgr.add_watches(["pyopencl_array_time.max"]) vis_timer = IntervalTimer("t_vis", "Time spent visualizing") logmgr.add_quantity(vis_timer) visualizer = make_visualizer(discr, order) # initname = initializer.__class__.__name__ initname = "flame1d" 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) #timestepper = rk4_step #timestepper = lsrk54_step #timestepper = lsrk144_step timestepper = euler_step 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): # check for some troublesome output types inf_exists = not np.isfinite(discr.norm(state, np.inf)) if inf_exists: if rank == 0: logging.info( "Non-finite values detected in simulation, exiting...") # dump right now sim_checkpoint(discr=discr, visualizer=visualizer, eos=eos, q=state, vizname=casename, step=999999999, t=t, dt=current_dt, nviz=1, exittol=exittol, constant_cfl=constant_cfl, comm=comm, vis_timer=vis_timer, overwrite=True, s0=s0_sc, kappa=kappa_sc) exit() cv = split_conserved(dim=dim, q=state) return ( ns_operator(discr, q=state, t=t, boundaries=boundaries, eos=eos) + eos.get_species_source_terms(cv)) def my_checkpoint(step, t, dt, state): write_restart = (check_step(step, nrestart) if step != restart_step else False) if write_restart is True: with open(snapshot_pattern.format(step=step, rank=rank), "wb") as f: pickle.dump( { "local_mesh": local_mesh, "state": obj_array_vectorize(actx.to_numpy, flatten(state)), "t": t, "step": step, "global_nelements": global_nelements, "num_parts": nparts, }, f) def loc_fn(t): return flame_start_loc + flame_speed * t exact_soln = PlanarDiscontinuity(dim=dim, disc_location=loc_fn, sigma=0.0000001, nspecies=nspecies, temperature_left=temp_ignition, temperature_right=temp_unburned, pressure_left=pres_burned, pressure_right=pres_unburned, velocity_left=vel_burned, velocity_right=vel_unburned, species_mass_left=y_burned, species_mass_right=y_unburned) cv = split_conserved(dim, state) reaction_rates = eos.get_production_rates(cv) viz_fields = [("reaction_rates", reaction_rates)] return sim_checkpoint(discr=discr, visualizer=visualizer, eos=eos, q=state, vizname=casename, step=step, t=t, dt=dt, nstatus=nstatus, nviz=nviz, exittol=exittol, constant_cfl=constant_cfl, comm=comm, vis_timer=vis_timer, overwrite=True, exact_soln=exact_soln, viz_fields=viz_fields) if rank == 0: logging.info("Stepping.") (current_step, current_t, current_state) = \ advance_state(rhs=my_rhs, timestepper=timestepper, checkpoint=my_checkpoint, get_timestep=get_timestep, state=current_state, t_final=t_final, t=current_t, istep=current_step, logmgr=logmgr,eos=eos,dim=dim) 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 logmgr: logmgr.close() elif use_profiling: print(actx.tabulate_profiling_data()) exit()
def interpolate_from_meshmode(queue, dof_vec, elements_to_sources_lookup, order="tree"): """Interpolate a DoF vector from :mod:`meshmode`. :arg dof_vec: a DoF vector representing a field in :mod:`meshmode` of shape ``(..., nnodes)``. :arg elements_to_sources_lookup: a :class:`ElementsToSourcesLookup`. :arg order: order of the output potential, either "tree" or "user". .. note:: This function currently supports meshes with just one element group. Also, the element group must be simplex-based. .. note:: This function does some heavy-lifting computation in Python, which we intend to optimize in the future. In particular, we plan to shift the batched linear solves and basis evaluations to :mod:`loopy`. TODO: make linear solvers available as :mod:`loopy` callables. TODO: make :mod:`modepy` emit :mod:`loopy` callables for basis evaluation. """ if not isinstance(dof_vec, cl.array.Array): raise TypeError("non-array passed to interpolator") assert len(elements_to_sources_lookup.discr.groups) == 1 assert len(elements_to_sources_lookup.discr.mesh.groups) == 1 degroup = elements_to_sources_lookup.discr.groups[0] megroup = elements_to_sources_lookup.discr.mesh.groups[0] if not degroup.is_affine: raise ValueError( "interpolation requires global-to-local map, " "which is only available for affinely mapped elements") mesh = elements_to_sources_lookup.discr.mesh dim = elements_to_sources_lookup.discr.dim template_simplex = mesh.groups[0].vertex_unit_coordinates().T # ------------------------------------------------------- # Inversely map source points with a global-to-local map. # # 1. For each element, solve for the affine map. # # 2. Apply the map to corresponding source points. # # This step computes `unit_sources`, the list of inversely # mapped source points. sources_in_element_starts = \ elements_to_sources_lookup.sources_in_element_starts.get(queue) sources_in_element_lists = \ elements_to_sources_lookup.sources_in_element_lists.get(queue) tree = elements_to_sources_lookup.tree.get(queue) unit_sources_host = make_obj_array( [np.zeros_like(srccrd) for srccrd in tree.sources]) for iel in range(degroup.nelements): vertex_ids = megroup.vertex_indices[iel] vertices = mesh.vertices[:, vertex_ids] afa, afb = compute_affine_transform(vertices, template_simplex) beg = sources_in_element_starts[iel] end = sources_in_element_starts[iel + 1] source_ids_in_el = sources_in_element_lists[beg:end] sources_in_el = np.vstack( [tree.sources[iaxis][source_ids_in_el] for iaxis in range(dim)]) ivmapped_el_sources = afa @ sources_in_el + afb.reshape([dim, 1]) for iaxis in range(dim): unit_sources_host[iaxis][source_ids_in_el] = \ ivmapped_el_sources[iaxis, :] unit_sources = make_obj_array( [cl.array.to_device(queue, usc) for usc in unit_sources_host]) # ----------------------------------------------------- # Carry out evaluations in the local (template) frames. # # 1. Assemble a resampling matrix for each element, with # the basis functions and the local source points. # # 2. For each element, perform matvec on the resampling # matrix and the local DoF coefficients. # # This step assumes `unit_sources` computed on device, so # that the previous step can be swapped with a kernel without # interrupting the followed computation. mapped_sources = np.vstack([usc.get(queue) for usc in unit_sources]) basis_funcs = degroup.basis() arr_ctx = PyOpenCLArrayContext(queue) dof_vec_view = unflatten(arr_ctx, elements_to_sources_lookup.discr, dof_vec)[0] dof_vec_view = dof_vec_view.get() sym_shape = dof_vec.shape[:-1] source_vec = np.zeros(sym_shape + (tree.nsources, )) for iel in range(degroup.nelements): beg = sources_in_element_starts[iel] end = sources_in_element_starts[iel + 1] source_ids_in_el = sources_in_element_lists[beg:end] mapped_sources_in_el = mapped_sources[:, source_ids_in_el] local_dof_vec = dof_vec_view[..., iel, :] # resampling matrix built from Vandermonde matrices import modepy as mp rsplm = mp.resampling_matrix(basis=basis_funcs, new_nodes=mapped_sources_in_el, old_nodes=degroup.unit_nodes) if len(sym_shape) == 0: local_coeffs = local_dof_vec source_vec[source_ids_in_el] = rsplm @ local_coeffs else: from pytools import indices_in_shape for sym_id in indices_in_shape(sym_shape): source_vec[sym_id + (source_ids_in_el, )] = \ rsplm @ local_dof_vec[sym_id] source_vec = cl.array.to_device(queue, source_vec) if order == "tree": pass # no need to do anything elif order == "user": source_vec = source_vec[tree.sorted_target_ids] # into user order else: raise ValueError(f"order must be 'tree' or 'user' (got {order}).") return source_vec
def main(ctx_factory=cl.create_some_context, snapshot_pattern="y0euler-{step:06d}-{rank:04d}.pkl", restart_step=None, use_profiling=False, use_logmgr=False): """Drive the Y0 example.""" from mpi4py import MPI comm = MPI.COMM_WORLD rank = 0 rank = comm.Get_rank() nparts = comm.Get_size() """logging and profiling""" logmgr = initialize_logmgr(use_logmgr, use_profiling, filename="y0euler.sqlite", mode="wu", mpi_comm=comm) cl_ctx = ctx_factory() 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))) #nviz = 500 #nrestart = 500 nviz = 50 nrestart = 10000000 current_dt = 1.0e-7 #t_final = 5.e-7 t_final = 3e-4 dim = 2 order = 1 exittol = 10000000 # do never exit when comparing to exact solution #t_final = 0.001 current_cfl = 1.0 vel_init = np.zeros(shape=(dim, )) vel_inflow = np.zeros(shape=(dim, )) vel_outflow = np.zeros(shape=(dim, )) orig = np.zeros(shape=(dim, )) #vel[0] = 340.0 #vel_inflow[0] = 100.0 # m/s current_t = 0 casename = "y0euler" constant_cfl = False # no internal euler status messages nstatus = 1000000000 checkpoint_t = current_t current_step = 0 # working gas: CO2 # # gamma = 1.289 # MW=44.009 g/mol # cp = 37.135 J/mol-K, # rho= 1.977 kg/m^3 @298K gamma_CO2 = 1.289 R_CO2 = 8314.59 / 44.009 # background # 100 Pa # 298 K # rho = 1.77619667e-3 kg/m^3 # velocity = 0,0,0 rho_bkrnd = 1.77619667e-3 pres_bkrnd = 100 temp_bkrnd = 298 c_bkrnd = math.sqrt(gamma_CO2 * pres_bkrnd / rho_bkrnd) # isentropic shock relations # # lab frame, moving shock # state 1 is behind (downstream) the shock, state 2 is in front (upstream) of the shock mach = 2.0 pressure_ratio = (2. * gamma_CO2 * mach * mach - (gamma_CO2 - 1.)) / (gamma_CO2 + 1.) density_ratio = (gamma_CO2 + 1.) * mach * mach / ( (gamma_CO2 - 1.) * mach * mach + 2.) mach2 = math.sqrt(((gamma_CO2 - 1.) * mach * mach + 2.) / (2. * gamma_CO2 * mach * mach - (gamma_CO2 - 1.))) rho1 = rho_bkrnd pressure1 = pres_bkrnd rho2 = rho1 * density_ratio pressure2 = pressure1 * pressure_ratio velocity1 = 0. velocity2 = -mach * c_bkrnd * (1 / density_ratio - 1) c_shkd = math.sqrt(gamma_CO2 * pressure2 / rho2) vel_inflow[0] = velocity2 timestepper = rk4_step eos = IdealSingleGas(gamma=gamma_CO2, gas_const=R_CO2) bulk_init = Discontinuity(dim=dim, x0=.05, sigma=0.01, rhol=rho2, rhor=rho1, pl=pressure2, pr=pressure1, ul=vel_inflow[0], ur=0.) inflow_init = Lump(dim=dim, rho0=rho2, p0=pressure2, center=orig, velocity=vel_inflow, rhoamp=0.0) outflow_init = Lump(dim=dim, rho0=rho1, p0=pressure1, center=orig, velocity=vel_outflow, rhoamp=0.0) inflow = PrescribedBoundary(inflow_init) outflow = PrescribedBoundary(outflow_init) wall = AdiabaticSlipBoundary() dummy = DummyBoundary() # shock capturing parameters # sonic conditions density_ratio = (gamma_CO2 + 1.) * 1.0 / ((gamma_CO2 - 1.) + 2.) density_star = rho1 * density_ratio shock_thickness = 20 * 0.001 # on the order of 3 elements, should match what is in mesh generator # alpha is ~h/p (spacing/order) #alpha_sc = shock_thickness*abs(velocity1-velocity2)*density_star alpha_sc = 0.1 # sigma is ~p^-4 sigma_sc = -11.0 # kappa is empirical ... kappa_sc = 0.5 print( f"Shock capturing parameters: alpha {alpha_sc}, s0 {sigma_sc}, kappa {kappa_sc}" ) # timestep estimate wave_speed = max(mach2 * c_bkrnd, c_shkd + velocity2) char_len = 0.001 area = char_len * char_len / 2 perimeter = 2 * char_len + math.sqrt(2 * char_len * char_len) h = 2 * area / perimeter dt_est = 1 / (wave_speed * order * order / h) print(f"Time step estimate {dt_est}\n") dt_est_visc = 1 / (wave_speed * order * order / h + alpha_sc * order * order * order * order / h / h) print(f"Viscous timestep estimate {dt_est_visc}\n") from grudge import sym # boundaries = {BTAG_ALL: DummyBoundary} boundaries = { sym.DTAG_BOUNDARY("Inflow"): inflow, sym.DTAG_BOUNDARY("Outflow"): outflow, sym.DTAG_BOUNDARY("Wall"): wall } #local_mesh, global_nelements = create_parallel_grid(comm, #get_pseudo_y0_mesh) # #local_nelements = local_mesh.nelements if restart_step is None: local_mesh, global_nelements = create_parallel_grid(comm, get_mesh) local_nelements = local_mesh.nelements else: # Restart with open(snapshot_pattern.format(step=restart_step, rank=rank), "rb") as f: restart_data = pickle.load(f) local_mesh = restart_data["local_mesh"] local_nelements = local_mesh.nelements global_nelements = restart_data["global_nelements"] assert comm.Get_size() == restart_data["num_parts"] if rank == 0: logging.info("Making discretization") discr = EagerDGDiscretization(actx, local_mesh, order=order, mpi_communicator=comm) nodes = thaw(actx, discr.nodes()) if restart_step is None: if rank == 0: logging.info("Initializing soln.") current_state = bulk_init(0, nodes, eos=eos) else: current_t = restart_data["t"] current_step = restart_step current_state = unflatten( actx, discr.discr_from_dd("vol"), obj_array_vectorize(actx.from_numpy, restart_data["state"])) vis_timer = None if logmgr: logmgr_add_device_name(logmgr, queue) logmgr_add_discretization_quantities(logmgr, discr, eos, dim) #logmgr_add_package_versions(logmgr) logmgr.add_watches([ "step.max", "t_sim.max", "t_step.max", "min_pressure", "max_pressure", "min_temperature", "max_temperature" ]) try: logmgr.add_watches(["memory_usage.max"]) except KeyError: pass if use_profiling: logmgr.add_watches(["pyopencl_array_time.max"]) vis_timer = IntervalTimer("t_vis", "Time spent visualizing") logmgr.add_quantity(vis_timer) #visualizer = make_visualizer(discr, discr.order + 3 #if discr.dim == 2 else discr.order) visualizer = make_visualizer(discr, discr.order) # initname = initializer.__class__.__name__ initname = "pseudoY0" 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_rhs(t, state): #return inviscid_operator(discr, eos=eos, boundaries=boundaries, q=state, t=t) 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_sc, sigma=sigma_sc, kappa=kappa_sc)) def my_checkpoint(step, t, dt, state): write_restart = (check_step(step, nrestart) if step != restart_step else False) if write_restart is True: with open(snapshot_pattern.format(step=step, rank=rank), "wb") as f: pickle.dump( { "local_mesh": local_mesh, "state": obj_array_vectorize(actx.to_numpy, flatten(state)), "t": t, "step": step, "global_nelements": global_nelements, "num_parts": nparts, }, f) #x0=f(time) exact_soln = Discontinuity(dim=dim, x0=.05, sigma=0.00001, rhol=rho2, rhor=rho1, pl=pressure2, pr=pressure1, ul=vel_inflow[0], ur=0., uc=mach * c_bkrnd) return sim_checkpoint(discr=discr, visualizer=visualizer, eos=eos, q=state, vizname=casename, step=step, t=t, dt=dt, nstatus=nstatus, nviz=nviz, exittol=exittol, constant_cfl=constant_cfl, comm=comm, vis_timer=vis_timer, overwrite=True, exact_soln=exact_soln, sigma=sigma_sc, kappa=kappa_sc) if rank == 0: logging.info("Stepping.") (current_step, current_t, current_state) = \ advance_state(rhs=my_rhs, timestepper=timestepper, checkpoint=my_checkpoint, get_timestep=get_timestep, state=current_state, t_final=t_final, t=current_t, istep=current_step, logmgr=logmgr,eos=eos,dim=dim) 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 logmgr: logmgr.close() elif use_profiling: print(actx.tabulate_profiling_data())
def __call__(self): self.receive_request.Wait() actx = self.array_context remote_data = unflatten(self.array_context, self.bdry_discr, actx.from_numpy(self.remote_data_host)) return [(self.insn_name, remote_data)], []
def exec_compute_potential_insn_fmm(self, actx: PyOpenCLArrayContext, insn, bound_expr, evaluate, fmm_driver): """ :arg fmm_driver: A function that accepts four arguments: *wrangler*, *strength*, *geo_data*, *kernel*, *kernel_arguments* :returns: a tuple ``(assignments, extra_outputs)``, where *assignments* is a list of tuples containing pairs ``(name, value)`` representing assignments to be performed in the evaluation context. *extra_outputs* is data that *fmm_driver* may return (such as timing data), passed through unmodified. """ target_name_and_side_to_number, target_discrs_and_qbx_sides = ( self.get_target_discrs_and_qbx_sides(insn, bound_expr)) geo_data = self.qbx_fmm_geometry_data(bound_expr.places, insn.source.geometry, target_discrs_and_qbx_sides) # FIXME Exert more positive control over geo_data attribute lifetimes using # geo_data.<method>.clear_cache(geo_data). # FIXME Synthesize "bad centers" around corners and edges that have # inadequate QBX coverage. # FIXME don't compute *all* output kernels on all targets--respect that # some target discretizations may only be asking for derivatives (e.g.) from pytential import bind, sym waa = bind( bound_expr.places, sym.weights_and_area_elements(self.ambient_dim, dofdesc=insn.source))(actx) densities = [evaluate(density) for density in insn.densities] strengths = [waa * density for density in densities] flat_strengths = tuple(flatten(strength) for strength in strengths) base_kernel = single_valued(knl.get_base_kernel() for knl in insn.source_kernels) output_and_expansion_dtype = (self.get_fmm_output_and_expansion_dtype( insn.source_kernels, flat_strengths[0])) kernel_extra_kwargs, source_extra_kwargs = ( self.get_fmm_expansion_wrangler_extra_kwargs( actx, insn.target_kernels + insn.source_kernels, geo_data.tree().user_source_ids, insn.kernel_arguments, evaluate)) wrangler = self.expansion_wrangler_code_container( target_kernels=insn.target_kernels, source_kernels=insn.source_kernels).get_wrangler( actx.queue, geo_data, output_and_expansion_dtype, self.qbx_order, self.fmm_level_to_order, source_extra_kwargs=source_extra_kwargs, kernel_extra_kwargs=kernel_extra_kwargs, _use_target_specific_qbx=self._use_target_specific_qbx) from pytential.qbx.geometry import target_state if (actx.thaw(geo_data.user_target_to_center()) == target_state.FAILED ).any().get(): raise RuntimeError("geometry has failed targets") # {{{ geometry data inspection hook if self.geometry_data_inspector is not None: perform_fmm = self.geometry_data_inspector(insn, bound_expr, geo_data) if not perform_fmm: return [(o.name, 0) for o in insn.outputs] # }}} # Execute global QBX. all_potentials_on_every_target, extra_outputs = (fmm_driver( wrangler, flat_strengths, geo_data, base_kernel, kernel_extra_kwargs)) results = [] for o in insn.outputs: target_side_number = target_name_and_side_to_number[ o.target_name, o.qbx_forced_limit] target_discr, _ = target_discrs_and_qbx_sides[target_side_number] target_slice = slice(*geo_data.target_info( ).target_discr_starts[target_side_number:target_side_number + 2]) result = \ all_potentials_on_every_target[o.target_kernel_index][target_slice] from meshmode.discretization import Discretization if isinstance(target_discr, Discretization): from meshmode.dof_array import unflatten result = unflatten(actx, target_discr, result) results.append((o.name, result)) return results, extra_outputs
def test_interpolation(ctx_factory, name, source_discr_stage, target_granularity): ctx = ctx_factory() queue = cl.CommandQueue(ctx) actx = PyOpenCLArrayContext(queue) nelements = 32 target_order = 7 qbx_order = 4 where = sym.as_dofdesc("test_interpolation") from_dd = sym.DOFDescriptor(geometry=where.geometry, discr_stage=source_discr_stage, granularity=sym.GRANULARITY_NODE) to_dd = sym.DOFDescriptor(geometry=where.geometry, discr_stage=sym.QBX_SOURCE_QUAD_STAGE2, granularity=target_granularity) mesh = make_curve_mesh(starfish, np.linspace(0.0, 1.0, nelements + 1), target_order) discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource(discr, fine_order=4 * target_order, qbx_order=qbx_order, fmm_order=False) from pytential import GeometryCollection places = GeometryCollection(qbx, auto_where=where) sigma_sym = sym.var("sigma") op_sym = sym.sin(sym.interp(from_dd, to_dd, sigma_sym)) bound_op = bind(places, op_sym, auto_where=where) from meshmode.dof_array import thaw, flatten, unflatten def discr_and_nodes(stage): density_discr = places.get_discretization(where.geometry, stage) return density_discr, np.array([ actx.to_numpy(flatten(axis)) for axis in thaw(actx, density_discr.nodes()) ]) _, target_nodes = discr_and_nodes(sym.QBX_SOURCE_QUAD_STAGE2) source_discr, source_nodes = discr_and_nodes(source_discr_stage) sigma_target = np.sin(la.norm(target_nodes, axis=0)) sigma_dev = unflatten(actx, source_discr, actx.from_numpy(la.norm(source_nodes, axis=0))) sigma_target_interp = actx.to_numpy( flatten(bound_op(actx, sigma=sigma_dev))) if name in ("default", "default_explicit", "stage2", "quad"): error = la.norm(sigma_target_interp - sigma_target) / la.norm(sigma_target) assert error < 1.0e-10 elif name in ("stage2_center", ): assert len(sigma_target_interp) == 2 * len(sigma_target) else: raise ValueError(f"unknown test case name: {name}")
def exec_compute_potential_insn_fmm(self, actx: PyOpenCLArrayContext, insn, bound_expr, evaluate): # {{{ gather unique target discretizations used target_name_to_index = {} targets = [] for o in insn.outputs: assert o.qbx_forced_limit not in (-1, 1) if o.target_name in target_name_to_index: continue target_name_to_index[o.target_name] = len(targets) targets.append(bound_expr.places.get_geometry(o.target_name.geometry)) targets = tuple(targets) # }}} # {{{ get wrangler geo_data = self.fmm_geometry_data(targets) from pytential import bind, sym waa = bind(bound_expr.places, sym.weights_and_area_elements( self.ambient_dim, dofdesc=insn.source))(actx) strengths = waa * evaluate(insn.density) from meshmode.dof_array import flatten flat_strengths = flatten(strengths) out_kernels = tuple(knl for knl in insn.kernels) fmm_kernel = self.get_fmm_kernel(out_kernels) output_and_expansion_dtype = ( self.get_fmm_output_and_expansion_dtype(fmm_kernel, strengths)) kernel_extra_kwargs, source_extra_kwargs = ( self.get_fmm_expansion_wrangler_extra_kwargs( actx, out_kernels, geo_data.tree().user_source_ids, insn.kernel_arguments, evaluate)) wrangler = self.expansion_wrangler_code_container( fmm_kernel, out_kernels).get_wrangler( actx.queue, geo_data.tree(), output_and_expansion_dtype, self.fmm_level_to_order, source_extra_kwargs=source_extra_kwargs, kernel_extra_kwargs=kernel_extra_kwargs) # }}} from boxtree.fmm import drive_fmm all_potentials_on_every_tgt = drive_fmm( geo_data.traversal(), wrangler, (flat_strengths,), timing_data=None) # {{{ postprocess fmm results = [] for o in insn.outputs: target_index = target_name_to_index[o.target_name] target_slice = slice(*geo_data.target_info().target_discr_starts[ target_index:target_index+2]) target_discr = targets[target_index] result = all_potentials_on_every_tgt[o.kernel_index][target_slice] from meshmode.discretization import Discretization if isinstance(target_discr, Discretization): from meshmode.dof_array import unflatten result = unflatten(actx, target_discr, result) results.append((o.name, result)) # }}} timing_data = {} return results, timing_data
if d == 2: u = np.log(dist) grad_u = diff/dist_squared elif d == 3: u = 1/dist grad_u = -diff/dist**3 else: assert False dn_u = 0 for i in range(d): dn_u = dn_u + normal_host[i]*grad_u[i] # }}} u_dev = unflatten(actx, density_discr, actx.from_numpy(u)) dn_u_dev = unflatten(actx, density_discr, actx.from_numpy(dn_u)) from pytools.obj_array import make_obj_array, obj_array_vectorize grad_u_dev = unflatten(actx, density_discr, obj_array_vectorize(actx.from_numpy, make_obj_array(grad_u))) key = (case.qbx_order, case.geometry.mesh_name, resolution, case.expr.zero_op_name) bound_op = bind(places, case.expr.get_zero_op(k_sym, **knl_kwargs)) error = bound_op( actx, u=u_dev, dn_u=dn_u_dev, grad_u=grad_u_dev, k=case.k) if 0: pt.plot(error) pt.show()
def main(ctx_factory=cl.create_some_context, snapshot_pattern="y0euler-{step:06d}-{rank:04d}.pkl", restart_step=None, use_profiling=False, use_logmgr=False): """Drive the Y0 example.""" from mpi4py import MPI comm = MPI.COMM_WORLD rank = 0 rank = comm.Get_rank() nparts = comm.Get_size() """logging and profiling""" logmgr = initialize_logmgr(use_logmgr, filename="y0euler.sqlite", mode="wo", mpi_comm=comm) cl_ctx = ctx_factory() 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))) #nviz = 500 #nrestart = 500 nviz = 100 nrestart = 100 #current_dt = 2.5e-8 # stable with euler current_dt = 4e-7 # stable with lrsrk144 t_final = 5.e-1 dim = 3 order = 1 exittol = .09 #t_final = 0.001 current_cfl = 1.0 vel_init = np.zeros(shape=(dim,)) vel_inflow = np.zeros(shape=(dim,)) vel_outflow = np.zeros(shape=(dim,)) orig = np.zeros(shape=(dim,)) orig[0] = 0.83 orig[2] = 0.001 #vel[0] = 340.0 #vel_inflow[0] = 100.0 # m/s current_t = 0 casename = "y0euler" constant_cfl = False nstatus = 10000000000 rank = 0 checkpoint_t = current_t current_step = 0 # working gas: CO2 # # gamma = 1.289 # MW=44.009 g/mol # cp = 37.135 J/mol-K, # rho= 1.977 kg/m^3 @298K gamma_CO2 = 1.289 R_CO2 = 8314.59/44.009 # background # 100 Pa # 298 K # rho = 1.77619667e-3 kg/m^3 # velocity = 0,0,0 rho_bkrnd=1.77619667e-3 pres_bkrnd=100 temp_bkrnd=298 # nozzle inflow # # # stagnation tempertuare 298 K # stagnation pressure 1.5e Pa # # isentropic expansion based on the area ratios between the inlet (r=13e-3m) and the throat (r=6.3e-3) # # MJA, this is calculated offline, add some code to do it for us # # Mach number=0.139145 # pressure=148142 # temperature=297.169 # density=2.63872 # gamma=1.289 # calculate the inlet Mach number from the area ratio nozzleInletRadius = 13.e-3 nozzleThroatRadius = 6.3e-3 nozzleInletArea = math.pi*nozzleInletRadius*nozzleInletRadius nozzleThroatArea = math.pi*nozzleThroatRadius*nozzleThroatRadius inletAreaRatio = nozzleInletArea/nozzleThroatArea def getMachFromAreaRatio(area_ratio, gamma, mach_guess=0.01): error=1.e-8 nextError=1.e8 g=gamma M0=mach_guess while nextError > error: R = ((2/(g+1)+((g-1)/(g+1)*M0*M0))**(((g+1)/(2*g-2))))/M0-area_ratio dRdM = (2*((2/(g+1)+((g-1)/(g+1)*M0*M0))**(((g+1)/(2*g-2))))/ (2*g-2)*(g-1)/(2/(g+1)+((g-1)/(g+1)*M0*M0))- ((2/(g+1)+((g-1)/(g+1)*M0*M0))**(((g+1)/(2*g-2))))* M0**(-2)) M1=M0-R/dRdM nextError=abs(R) M0=M1 return M1 def getIsentropicPressure(mach, P0, gamma): pressure=(1.+(gamma-1.)*0.5*math.pow(mach,2)) pressure=P0*math.pow(pressure,(-gamma/(gamma-1.))) return pressure def getIsentropicTemperature(mach, T0, gamma): temperature=(1.+(gamma-1.)*0.5*math.pow(mach,2)) temperature=T0*math.pow(temperature,-1.0) return temperature inlet_mach = getMachFromAreaRatio(area_ratio = inletAreaRatio, gamma=gamma_CO2, mach_guess = 0.01); # ramp the stagnation pressure start_ramp_pres = 1000 ramp_interval = 5.e-3 t_ramp_start = 1e-5 pres_inflow = getIsentropicPressure(mach=inlet_mach, P0=start_ramp_pres, gamma=gamma_CO2) temp_inflow = getIsentropicTemperature(mach=inlet_mach, T0=298, gamma=gamma_CO2) rho_inflow = pres_inflow/temp_inflow/R_CO2 print(f'inlet Mach number {inlet_mach}') print(f'inlet temperature {temp_inflow}') print(f'inlet pressure {pres_inflow}') end_ramp_pres = 150000 pres_inflow_final = getIsentropicPressure(mach=inlet_mach, P0=end_ramp_pres, gamma=gamma_CO2) print(f'final inlet pressure {pres_inflow_final}') #pres_inflow=148142 #temp_inflow=297.169 #rho_inflow=2.63872 #mach_inflow=infloM = 0.139145 vel_inflow[0] = inlet_mach*math.sqrt(gamma_CO2*pres_inflow/rho_inflow) # starting pressure for the inflow ramp #timestepper = rk4_step #timestepper = lsrk54_step timestepper = lsrk144_step #timestepper = euler_step eos = IdealSingleGas(gamma=gamma_CO2, gas_const=R_CO2) bulk_init = Discontinuity(dim=dim, x0=-.30,sigma=0.005, #bulk_init = Discontinuity(dim=dim, x0=-.31,sigma=0.04, rhol=rho_inflow, rhor=rho_bkrnd, pl=pres_inflow, pr=pres_bkrnd, ul=vel_inflow, ur=vel_outflow) #inflow_init = Lump(dim=dim, rho0=rho_inflow, p0=pres_inflow, #center=orig, velocity=vel_inflow, rhoamp=0.0) #outflow_init = Lump(dim=dim, rho0=rho_bkrnd, p0=pres_bkrnd, #center=orig, velocity=vel_outflow, rhoamp=0.0) # pressure ramp function def inflow_ramp_pressure(t, startP=start_ramp_pres, finalP=end_ramp_pres, ramp_interval=ramp_interval, t_ramp_start=t_ramp_start): if t > t_ramp_start: rampPressure = min(finalP, startP+(t-t_ramp_start)/ramp_interval*(finalP-startP)) else: rampPressure = startP return rampPressure class IsentropicInflow: def __init__(self, *, dim=1, direc=0, T0=298, P0=1e5, mach= 0.01, p_fun = None): self._P0 = P0 self._T0 = T0 self._dim = dim self._direc = direc self._mach = mach if p_fun is not None: self._p_fun = p_fun def __call__(self, x_vec, *, t=0, eos): if self._p_fun is not None: P0 = self._p_fun(t) else: P0 = self._P0 T0 = self._T0 gamma = eos.gamma() gas_const = eos.gas_const() pressure = getIsentropicPressure(mach=self._mach, P0=P0, gamma=gamma) temperature = getIsentropicTemperature(mach=self._mach, T0=T0, gamma=gamma) rho = pressure/temperature/gas_const #print(f'ramp Mach number {self._mach}') #print(f'ramp stagnation pressure {P0}') #print(f'ramp stagnation temperature {T0}') #print(f'ramp pressure {pressure}') #print(f'ramp temperature {temperature}') velocity = np.zeros(shape=(self._dim,)) velocity[self._direc] = self._mach*math.sqrt(gamma*pressure/rho) mass = 0.0*x_vec[0] + rho mom = velocity*mass energy = (pressure/(gamma - 1.0)) + np.dot(mom, mom)/(2.0*mass) from mirgecom.euler import join_conserved return join_conserved(dim=self._dim, mass=mass, momentum=mom, energy=energy) inflow_init = IsentropicInflow(dim=dim, T0=298, P0=start_ramp_pres, mach = inlet_mach , p_fun=inflow_ramp_pressure) outflow_init = Uniform(dim=dim, rho=rho_bkrnd, p=pres_bkrnd, velocity=vel_outflow) inflow = PrescribedBoundary(inflow_init) outflow = PrescribedBoundary(outflow_init) wall = AdiabaticSlipBoundary() dummy = DummyBoundary() alpha_sc = 0.5 # s0 is ~p^-4 #s0_sc = -11.0 s0_sc = -5.0 # kappa is empirical ... kappa_sc = 0.5 print(f"Shock capturing parameters: alpha {alpha_sc}, s0 {s0_sc}, kappa {kappa_sc}") # timestep estimate #wave_speed = max(mach2*c_bkrnd,c_shkd+velocity2[0]) #char_len = 0.001 #area=char_len*char_len/2 #perimeter = 2*char_len+math.sqrt(2*char_len*char_len) #h = 2*area/perimeter #dt_est = 1/(wave_speed*order*order/h) #print(f"Time step estimate {dt_est}\n") # #dt_est_visc = 1/(wave_speed*order*order/h+alpha_sc*order*order*order*order/h/h) #print(f"Viscous timestep estimate {dt_est_visc}\n") from grudge import sym boundaries = {sym.DTAG_BOUNDARY("Inflow"): inflow, sym.DTAG_BOUNDARY("Outflow"): outflow, sym.DTAG_BOUNDARY("Wall"): wall} if restart_step is None: local_mesh, global_nelements = create_parallel_grid(comm, get_pseudo_y0_mesh) local_nelements = local_mesh.nelements else: # Restart with open(snapshot_pattern.format(step=restart_step, rank=rank), "rb") as f: restart_data = pickle.load(f) local_mesh = restart_data["local_mesh"] local_nelements = local_mesh.nelements global_nelements = restart_data["global_nelements"] assert comm.Get_size() == restart_data["num_parts"] if rank == 0: logging.info("Making discretization") discr = EagerDGDiscretization( actx, local_mesh, order=order, mpi_communicator=comm ) nodes = thaw(actx, discr.nodes()) if restart_step is None: if rank == 0: logging.info("Initializing soln.") # for Discontinuity initial conditions current_state = bulk_init(0, nodes, eos=eos) # for uniform background initial condition #current_state = bulk_init(nodes, eos=eos) else: current_t = restart_data["t"] current_step = restart_step current_state = unflatten( actx, discr.discr_from_dd("vol"), obj_array_vectorize(actx.from_numpy, restart_data["state"])) vis_timer = None if logmgr: logmgr_add_device_name(logmgr, queue) logmgr_add_many_discretization_quantities(logmgr, discr, dim, extract_vars_for_logging, units_for_logging) #logmgr_add_package_versions(logmgr) logmgr.add_watches(["step.max", "t_sim.max", "t_step.max", "t_log.max", "min_pressure", "max_pressure", "min_temperature", "max_temperature"]) try: logmgr.add_watches(["memory_usage.max"]) except KeyError: pass if use_profiling: logmgr.add_watches(["pyopencl_array_time.max"]) vis_timer = IntervalTimer("t_vis", "Time spent visualizing") logmgr.add_quantity(vis_timer) visualizer = make_visualizer(discr, discr.order + 3 if discr.dim == 2 else discr.order) # initname = initializer.__class__.__name__ initname = "pseudoY0" 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_rhs(t, state): #return inviscid_operator(discr, eos=eos, boundaries=boundaries, q=state, t=t) 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_sc, s0=s0_sc, kappa=kappa_sc)) def my_checkpoint(step, t, dt, state): write_restart = (check_step(step, nrestart) if step != restart_step else False) if write_restart is True: with open(snapshot_pattern.format(step=step, rank=rank), "wb") as f: pickle.dump({ "local_mesh": local_mesh, "state": obj_array_vectorize(actx.to_numpy, flatten(state)), "t": t, "step": step, "global_nelements": global_nelements, "num_parts": nparts, }, f) return sim_checkpoint(discr=discr, visualizer=visualizer, eos=eos, q=state, vizname=casename, step=step, t=t, dt=dt, nstatus=nstatus, nviz=nviz, exittol=exittol, constant_cfl=constant_cfl, comm=comm, vis_timer=vis_timer, overwrite=True,s0=s0_sc,kappa=kappa_sc) if rank == 0: logging.info("Stepping.") (current_step, current_t, current_state) = \ advance_state(rhs=my_rhs, timestepper=timestepper, checkpoint=my_checkpoint, get_timestep=get_timestep, state=current_state, t_final=t_final, t=current_t, istep=current_step, logmgr=logmgr,eos=eos,dim=dim) 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 logmgr: logmgr.close() elif use_profiling: print(actx.tabulate_profiling_data())
def main(mesh_name="torus", visualize=False): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) if mesh_name == "torus": rout = 10 rin = 1 from meshmode.mesh.generation import generate_torus base_mesh = generate_torus( rout, rin, 40, 4, mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes # nx = 1 # ny = 1 nz = 1 dz = 0 meshes = [ affine_map( base_mesh, A=np.diag([1, 1, 1]), b=np.array([0, 0, iz*dz])) for iz in range(nz)] mesh = merge_disjoint_meshes(meshes, single_group=True) if visualize: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() else: raise ValueError(f"unknown mesh name: {mesh_name}") pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx = QBXLayerPotentialSource( pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order, ) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(3), extent=20, npoints=50) targets = actx.from_numpy(fplot.points) from pytential import GeometryCollection places = GeometryCollection({ "qbx": qbx, "qbx_target_assoc": qbx.copy(target_association_tolerance=0.2), "targets": PointsTarget(targets) }, auto_where="qbx") density_discr = places.get_discretization("qbx") # {{{ describe bvp from sumpy.kernel import LaplaceKernel kernel = LaplaceKernel(3) sigma_sym = sym.var("sigma") #sqrt_w = sym.sqrt_jac_q_weight(3) sqrt_w = 1 inv_sqrt_w_sigma = sym.cse(sigma_sym/sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (loc_sign*0.5*sigma_sym + sqrt_w*( sym.S(kernel, inv_sqrt_w_sigma, qbx_forced_limit=+1) + sym.D(kernel, inv_sqrt_w_sigma, qbx_forced_limit="avg") )) # }}} bound_op = bind(places, bdry_op_sym) # {{{ fix rhs and solve from meshmode.dof_array import thaw, flatten, unflatten nodes = thaw(actx, density_discr.nodes()) source = np.array([rout, 0, 0]) def u_incoming_func(x): from pytools.obj_array import obj_array_vectorize x = obj_array_vectorize(actx.to_numpy, flatten(x)) x = np.array(list(x)) # return 1/cl.clmath.sqrt( (x[0] - source[0])**2 # +(x[1] - source[1])**2 # +(x[2] - source[2])**2 ) return 1.0/la.norm(x - source[:, None], axis=0) bc = unflatten(actx, density_discr, actx.from_numpy(u_incoming_func(nodes))) bvp_rhs = bind(places, sqrt_w*sym.var("bc"))(actx, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(actx, "sigma", dtype=np.float64), bvp_rhs, tol=1e-14, progress=True, stall_iterations=0, hard_failure=True) sigma = bind(places, sym.var("sigma")/sqrt_w)( actx, sigma=gmres_result.solution) # }}} from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(actx, density_discr, 20) bdry_vis.write_vtk_file("laplace.vtu", [ ("sigma", sigma), ]) # {{{ postprocess/visualize repr_kwargs = dict( source="qbx_target_assoc", target="targets", qbx_forced_limit=None) representation_sym = ( sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) + sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) try: fld_in_vol = actx.to_numpy( bind(places, representation_sym)(actx, sigma=sigma)) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file("laplace-dirichlet-3d-failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)), ]) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("laplace-dirichlet-3d-potential.vts", [ ("potential", fld_in_vol), ])
def _test_data_transfer(mpi_comm, actx, local_bdry_conns, remote_to_local_bdry_conns, connected_parts): from mpi4py import MPI def f(x): return 10 * actx.np.sin(20. * x) """ Here is a simplified example of what happens from the point of view of the local rank. Local rank: 1. Transfer local points from local boundary to remote boundary to get remote points. 2. Send remote points to remote rank. Remote rank: 3. Receive remote points from local rank. 4. Transfer remote points from remote boundary to local boundary to get local points. 5. Send local points to local rank. Local rank: 6. Receive local points from remote rank. 7. Check if local points are the same as the original local points. """ # 1. send_reqs = [] for i_remote_part in connected_parts: conn = remote_to_local_bdry_conns[i_remote_part] bdry_discr = local_bdry_conns[i_remote_part].to_discr bdry_x = thaw(actx, bdry_discr.nodes()[0]) true_local_f = f(bdry_x) remote_f = conn(true_local_f) # 2. send_reqs.append( mpi_comm.isend(actx.to_numpy(flatten(remote_f)), dest=i_remote_part, tag=TAG_SEND_REMOTE_NODES)) # 3. buffers = {} for i_remote_part in connected_parts: status = MPI.Status() mpi_comm.probe(source=i_remote_part, tag=TAG_SEND_REMOTE_NODES, status=status) buffers[i_remote_part] = np.empty(status.count, dtype=bytes) recv_reqs = {} for i_remote_part, buf in buffers.items(): recv_reqs[i_remote_part] = mpi_comm.irecv(buf=buf, source=i_remote_part, tag=TAG_SEND_REMOTE_NODES) remote_to_local_f_data = {} for i_remote_part, req in recv_reqs.items(): remote_to_local_f_data[i_remote_part] = req.wait() buffers[i_remote_part] = None # free buffer for req in send_reqs: req.wait() # 4. send_reqs = [] for i_remote_part in connected_parts: conn = remote_to_local_bdry_conns[i_remote_part] local_f = unflatten( actx, conn.from_discr, actx.from_numpy(remote_to_local_f_data[i_remote_part])) remote_f = actx.to_numpy(flatten(conn(local_f))) # 5. send_reqs.append( mpi_comm.isend(remote_f, dest=i_remote_part, tag=TAG_SEND_LOCAL_NODES)) # 6. buffers = {} for i_remote_part in connected_parts: status = MPI.Status() mpi_comm.probe(source=i_remote_part, tag=TAG_SEND_LOCAL_NODES, status=status) buffers[i_remote_part] = np.empty(status.count, dtype=bytes) recv_reqs = {} for i_remote_part, buf in buffers.items(): recv_reqs[i_remote_part] = mpi_comm.irecv(buf=buf, source=i_remote_part, tag=TAG_SEND_LOCAL_NODES) local_f_data = {} for i_remote_part, req in recv_reqs.items(): local_f_data[i_remote_part] = req.wait() buffers[i_remote_part] = None # free buffer for req in send_reqs: req.wait() # 7. for i_remote_part in connected_parts: bdry_discr = local_bdry_conns[i_remote_part].to_discr bdry_x = thaw(actx, bdry_discr.nodes()[0]) true_local_f = actx.to_numpy(flatten(f(bdry_x))) local_f = local_f_data[i_remote_part] from numpy.linalg import norm err = norm(true_local_f - local_f, np.inf) assert err < 1e-11, "Error = %f is too large" % err
def main(curve_fn=starfish, visualize=True): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import make_curve_mesh mesh = make_curve_mesh( curve_fn, np.linspace(0, 1, nelements+1), target_order) from pytential.qbx import QBXLayerPotentialSource from meshmode.array_context import PyOpenCLArrayContext from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory actx = PyOpenCLArrayContext(queue) pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(pre_density_discr, 4*target_order, qbx_order, fmm_order=qbx_order+3, target_association_tolerance=0.005) from pytential.target import PointsTarget fplot = FieldPlotter(np.zeros(2), extent=5, npoints=1000) targets_dev = cl.array.to_device(queue, fplot.points) from pytential import GeometryCollection places = GeometryCollection({ "qbx": qbx, "targets": PointsTarget(targets_dev), }, auto_where="qbx") density_discr = places.get_discretization("qbx") from meshmode.dof_array import thaw nodes = thaw(actx, density_discr.nodes()) angle = actx.np.arctan2(nodes[1], nodes[0]) if k: kernel = HelmholtzKernel(2) kernel_kwargs = {"k": sym.var("k")} else: kernel = LaplaceKernel(2) kernel_kwargs = {} def op(**kwargs): kwargs.update(kernel_kwargs) #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), **kwargs)) return sym.D(kernel, sym.var("sigma"), **kwargs) #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None, **kwargs) sigma = actx.np.cos(mode_nr*angle) if 0: from meshmode.dof_array import flatten, unflatten sigma = flatten(0 * angle) from random import randrange for i in range(5): sigma[randrange(len(sigma))] = 1 sigma = unflatten(actx, density_discr, sigma) if isinstance(kernel, HelmholtzKernel): for i, elem in np.ndenumerate(sigma): sigma[i] = elem.astype(np.complex128) bound_bdry_op = bind(places, op()) if visualize: fld_in_vol = actx.to_numpy( bind(places, op( source="qbx", target="targets", qbx_forced_limit=None))(actx, sigma=sigma, k=k)) if enable_mayavi: fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) else: fplot.write_vtk_file("layerpot-potential.vts", [ ("potential", fld_in_vol) ]) if 0: apply_op = bound_bdry_op.scipy_op(actx, "sigma", np.float64, k=k) from sumpy.tools import build_matrix mat = build_matrix(apply_op) import matplotlib.pyplot as pt pt.imshow(mat) pt.colorbar() pt.show() if enable_mayavi: # {{{ plot boundary field from pytential.utils import flatten_to_numpy fld_on_bdry = flatten_to_numpy( actx, bound_bdry_op(actx, sigma=sigma, k=k)) nodes_host = flatten_to_numpy(actx, density_discr.nodes()) mlab.points3d(nodes_host[0], nodes_host[1], fld_on_bdry.real, scale_factor=0.03) mlab.colorbar() mlab.show()
pt.clf() elif ambient_dim == 3: from meshmode.discretization.visualization import make_visualizer marker = np.empty(density_discr.ndofs) for i in range(srcindices.nblocks): isrc = srcindices.block_indices(i) inbr = nbrindices.block_indices(i) marker.fill(0.0) marker[srcindices.indices] = 0.0 marker[isrc] = -42.0 marker[inbr] = +42.0 from meshmode.dof_array import unflatten marker_dev = unflatten(actx, density_discr, actx.from_numpy(marker)) vis = make_visualizer(actx, density_discr, 10) filename = "test_area_query_{}d_{:04}.vtu".format( ambient_dim, i) vis.write_vtk_file(filename, [ ("marker", marker_dev), ]) # }}} if __name__ == "__main__": import sys if len(sys.argv) > 1: exec(sys.argv[1]) else:
def test_dof_array_arithmetic_same_as_numpy(actx_factory): actx = actx_factory() from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(-0.5,)*2, b=(0.5,)*2, n=(3,)*2, order=1) discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(3)) def get_real(ary): return ary.real def get_imag(ary): return ary.real import operator from pytools import generate_nonnegative_integer_tuples_below as gnitb from random import uniform, randrange for op_func, n_args, use_integers in [ (operator.add, 2, False), (operator.sub, 2, False), (operator.mul, 2, False), (operator.truediv, 2, False), (operator.pow, 2, False), # FIXME pyopencl.Array doesn't do mod. #(operator.mod, 2, True), #(operator.mod, 2, False), #(operator.imod, 2, True), #(operator.imod, 2, False), # FIXME: Two outputs #(divmod, 2, False), (operator.iadd, 2, False), (operator.isub, 2, False), (operator.imul, 2, False), (operator.itruediv, 2, False), (operator.and_, 2, True), (operator.xor, 2, True), (operator.or_, 2, True), (operator.iand, 2, True), (operator.ixor, 2, True), (operator.ior, 2, True), (operator.ge, 2, False), (operator.lt, 2, False), (operator.gt, 2, False), (operator.eq, 2, True), (operator.ne, 2, True), (operator.pos, 1, False), (operator.neg, 1, False), (operator.abs, 1, False), (get_real, 1, False), (get_imag, 1, False), ]: for is_array_flags in gnitb(2, n_args): if sum(is_array_flags) == 0: # all scalars, no need to test continue if is_array_flags[0] == 0 and op_func in [ operator.iadd, operator.isub, operator.imul, operator.itruediv, operator.iand, operator.ixor, operator.ior, ]: # can't do in place operations with a scalar lhs continue args = [ (0.5+np.random.rand(discr.ndofs) if not use_integers else np.random.randint(3, 200, discr.ndofs)) if is_array_flag else (uniform(0.5, 2) if not use_integers else randrange(3, 200)) for is_array_flag in is_array_flags] # {{{ get reference numpy result # make a copy for the in place operators ref_args = [ arg.copy() if isinstance(arg, np.ndarray) else arg for arg in args] ref_result = op_func(*ref_args) # }}} # {{{ test DOFArrays actx_args = [ unflatten(actx, discr, actx.from_numpy(arg)) if isinstance(arg, np.ndarray) else arg for arg in args] actx_result = actx.to_numpy(flatten(op_func(*actx_args))) assert np.allclose(actx_result, ref_result) # }}} # {{{ test object arrays of DOFArrays # It would be very nice if comparisons on object arrays behaved # consistently with everything else. Alas, they do not. Instead: # # 0.5 < obj_array(DOFArray) -> obj_array([True]) # # because hey, 0.5 < DOFArray returned something truthy. if op_func not in [ operator.eq, operator.ne, operator.le, operator.lt, operator.ge, operator.gt, operator.iadd, operator.isub, operator.imul, operator.itruediv, operator.iand, operator.ixor, operator.ior, # All Python objects are real-valued, right? get_imag, ]: obj_array_args = [ make_obj_array([arg]) if isinstance(arg, DOFArray) else arg for arg in actx_args] obj_array_result = actx.to_numpy( flatten(op_func(*obj_array_args)[0])) assert np.allclose(obj_array_result, ref_result)
def exec_compute_potential_insn_direct(self, actx, insn, bound_expr, evaluate, return_timing_data): from pytential import bind, sym if return_timing_data: from pytential.source import UnableToCollectTimingData from warnings import warn warn("Timing data collection not supported.", category=UnableToCollectTimingData) lpot_applier = self.get_lpot_applier(insn.target_kernels, insn.source_kernels) p2p = None lpot_applier_on_tgt_subset = None from pytential.utils import flatten_if_needed kernel_args = {} for arg_name, arg_expr in insn.kernel_arguments.items(): kernel_args[arg_name] = flatten_if_needed(actx, evaluate(arg_expr)) waa = bind( bound_expr.places, sym.weights_and_area_elements(self.ambient_dim, dofdesc=insn.source))(actx) strength_vecs = [waa * evaluate(density) for density in insn.densities] from meshmode.discretization import Discretization flat_strengths = [flatten(strength) for strength in strength_vecs] source_discr = bound_expr.places.get_discretization( insn.source.geometry, insn.source.discr_stage) # FIXME: Do this all at once results = [] for o in insn.outputs: source_dd = insn.source.copy(discr_stage=o.target_name.discr_stage) target_discr = bound_expr.places.get_discretization( o.target_name.geometry, o.target_name.discr_stage) density_discr = bound_expr.places.get_discretization( source_dd.geometry, source_dd.discr_stage) is_self = density_discr is target_discr if is_self: # QBXPreprocessor is supposed to have taken care of this assert o.qbx_forced_limit is not None assert abs(o.qbx_forced_limit) > 0 expansion_radii = bind( bound_expr.places, sym.expansion_radii(self.ambient_dim, dofdesc=o.target_name))(actx) centers = bind( bound_expr.places, sym.expansion_centers(self.ambient_dim, o.qbx_forced_limit, dofdesc=o.target_name))(actx) evt, output_for_each_kernel = lpot_applier( actx.queue, flatten(thaw(actx, target_discr.nodes())), flatten(thaw(actx, source_discr.nodes())), flatten(centers), flat_strengths, expansion_radii=flatten(expansion_radii), **kernel_args) result = output_for_each_kernel[o.target_kernel_index] if isinstance(target_discr, Discretization): result = unflatten(actx, target_discr, result) results.append((o.name, result)) else: # no on-disk kernel caching if p2p is None: p2p = self.get_p2p(actx, insn.target_kernels, insn.source_kernels) if lpot_applier_on_tgt_subset is None: lpot_applier_on_tgt_subset = self.get_lpot_applier_on_tgt_subset( insn.target_kernels, insn.source_kernels) queue = actx.queue flat_targets = flatten_if_needed(actx, target_discr.nodes()) flat_sources = flatten(thaw(actx, source_discr.nodes())) evt, output_for_each_kernel = p2p(queue, flat_targets, flat_sources, flat_strengths, **kernel_args) qbx_forced_limit = o.qbx_forced_limit if qbx_forced_limit is None: qbx_forced_limit = 0 target_discrs_and_qbx_sides = ((target_discr, qbx_forced_limit), ) geo_data = self.qbx_fmm_geometry_data( bound_expr.places, insn.source.geometry, target_discrs_and_qbx_sides=target_discrs_and_qbx_sides) # center-related info is independent of targets # First ncenters targets are the centers tgt_to_qbx_center = ( geo_data.user_target_to_center()[geo_data.ncenters:].copy( queue=queue).with_queue(queue)) qbx_tgt_numberer = self.get_qbx_target_numberer( tgt_to_qbx_center.dtype) qbx_tgt_count = cl.array.empty(queue, (), np.int32) qbx_tgt_numbers = cl.array.empty_like(tgt_to_qbx_center) qbx_tgt_numberer(tgt_to_qbx_center, qbx_tgt_numbers, qbx_tgt_count, queue=queue) qbx_tgt_count = int(qbx_tgt_count.get()) if (o.qbx_forced_limit is not None and abs(o.qbx_forced_limit) == 1 and qbx_tgt_count < target_discr.ndofs): raise RuntimeError("Did not find a matching QBX center " "for some targets") qbx_tgt_numbers = qbx_tgt_numbers[:qbx_tgt_count] qbx_center_numbers = tgt_to_qbx_center[qbx_tgt_numbers] qbx_center_numbers.finish() tgt_subset_kwargs = kernel_args.copy() for i, res_i in enumerate(output_for_each_kernel): tgt_subset_kwargs[f"result_{i}"] = res_i if qbx_tgt_count: lpot_applier_on_tgt_subset( queue, targets=flat_targets, sources=flat_sources, centers=geo_data.flat_centers(), expansion_radii=geo_data.flat_expansion_radii(), strengths=flat_strengths, qbx_tgt_numbers=qbx_tgt_numbers, qbx_center_numbers=qbx_center_numbers, **tgt_subset_kwargs) result = output_for_each_kernel[o.target_kernel_index] if isinstance(target_discr, Discretization): result = unflatten(actx, target_discr, result) results.append((o.name, result)) timing_data = {} return results, timing_data
def run_exterior_stokes_2d( ctx_factory, nelements, mesh_order=4, target_order=4, qbx_order=4, fmm_order=False, # FIXME: FMM is slower than direct eval mu=1, circle_rad=1.5, visualize=False): # This program tests an exterior Stokes flow in 2D using the # compound representation given in Hsiao & Kress, # ``On an integral equation for the two-dimensional exterior Stokes problem,'' # Applied Numerical Mathematics 1 (1985). logging.basicConfig(level=logging.INFO) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) ovsmp_target_order = 4 * target_order # {{{ geometries from meshmode.mesh.generation import ( # noqa make_curve_mesh, starfish, ellipse, drop) mesh = make_curve_mesh(lambda t: circle_rad * ellipse(1, t), np.linspace(0, 1, nelements + 1), target_order) coarse_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource target_association_tolerance = 0.05 qbx = QBXLayerPotentialSource( coarse_density_discr, fine_order=ovsmp_target_order, qbx_order=qbx_order, fmm_order=fmm_order, target_association_tolerance=target_association_tolerance, _expansions_in_tree_have_extent=True, ) def circle_mask(test_points, radius): return (test_points[0, :]**2 + test_points[1, :]**2 > radius**2) def outside_circle(test_points, radius): mask = circle_mask(test_points, radius) return np.array([row[mask] for row in test_points]) from pytential.target import PointsTarget nsamp = 30 eval_points_1d = np.linspace(-3., 3., nsamp) eval_points = np.zeros((2, len(eval_points_1d)**2)) eval_points[0, :] = np.tile(eval_points_1d, len(eval_points_1d)) eval_points[1, :] = np.repeat(eval_points_1d, len(eval_points_1d)) eval_points = outside_circle(eval_points, radius=circle_rad) point_targets = PointsTarget(eval_points) fplot = FieldPlotter(np.zeros(2), extent=6, npoints=100) plot_targets = PointsTarget(outside_circle(fplot.points, radius=circle_rad)) places = GeometryCollection({ sym.DEFAULT_SOURCE: qbx, sym.DEFAULT_TARGET: qbx.density_discr, "point_target": point_targets, "plot_target": plot_targets, }) density_discr = places.get_discretization(sym.DEFAULT_SOURCE) normal = bind(places, sym.normal(2).as_vector())(actx) path_length = bind(places, sym.integral(2, 1, 1))(actx) # }}} # {{{ describe bvp from pytential.symbolic.stokes import StressletWrapper, StokesletWrapper dim = 2 cse = sym.cse sigma_sym = sym.make_sym_vector("sigma", dim) meanless_sigma_sym = cse(sigma_sym - sym.mean(2, 1, sigma_sym)) int_sigma = sym.Ones() * sym.integral(2, 1, sigma_sym) nvec_sym = sym.make_sym_vector("normal", dim) mu_sym = sym.var("mu") # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = 1 stresslet_obj = StressletWrapper(dim=2) stokeslet_obj = StokesletWrapper(dim=2) bdry_op_sym = (-loc_sign * 0.5 * sigma_sym - stresslet_obj.apply( sigma_sym, nvec_sym, mu_sym, qbx_forced_limit="avg") + stokeslet_obj.apply( meanless_sigma_sym, mu_sym, qbx_forced_limit="avg") - (0.5 / np.pi) * int_sigma) # }}} bound_op = bind(places, bdry_op_sym) # {{{ fix rhs and solve def fund_soln(x, y, loc, strength): #with direction (1,0) for point source r = actx.np.sqrt((x - loc[0])**2 + (y - loc[1])**2) scaling = strength / (4 * np.pi * mu) xcomp = (-actx.np.log(r) + (x - loc[0])**2 / r**2) * scaling ycomp = ((x - loc[0]) * (y - loc[1]) / r**2) * scaling return [xcomp, ycomp] def rotlet_soln(x, y, loc): r = actx.np.sqrt((x - loc[0])**2 + (y - loc[1])**2) xcomp = -(y - loc[1]) / r**2 ycomp = (x - loc[0]) / r**2 return [xcomp, ycomp] def fund_and_rot_soln(x, y, loc, strength): #with direction (1,0) for point source r = actx.np.sqrt((x - loc[0])**2 + (y - loc[1])**2) scaling = strength / (4 * np.pi * mu) xcomp = ((-actx.np.log(r) + (x - loc[0])**2 / r**2) * scaling - (y - loc[1]) * strength * 0.125 / r**2 + 3.3) ycomp = (((x - loc[0]) * (y - loc[1]) / r**2) * scaling + (x - loc[0]) * strength * 0.125 / r**2 + 1.5) return make_obj_array([xcomp, ycomp]) from meshmode.dof_array import unflatten, flatten, thaw nodes = flatten(thaw(actx, density_discr.nodes())) fund_soln_loc = np.array([0.5, -0.2]) strength = 100. bc = unflatten( actx, density_discr, fund_and_rot_soln(nodes[0], nodes[1], fund_soln_loc, strength)) omega_sym = sym.make_sym_vector("omega", dim) u_A_sym_bdry = stokeslet_obj.apply( # noqa: N806 omega_sym, mu_sym, qbx_forced_limit=1) from pytential.utils import unflatten_from_numpy omega = unflatten_from_numpy( actx, density_discr, make_obj_array([(strength / path_length) * np.ones(len(nodes[0])), np.zeros(len(nodes[0]))])) bvp_rhs = bind(places, sym.make_sym_vector("bc", dim) + u_A_sym_bdry)(actx, bc=bc, mu=mu, omega=omega) gmres_result = gmres(bound_op.scipy_op(actx, "sigma", np.float64, mu=mu, normal=normal), bvp_rhs, x0=bvp_rhs, tol=1e-9, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution sigma_int_val_sym = sym.make_sym_vector("sigma_int_val", 2) int_val = bind(places, sym.integral(2, 1, sigma_sym))(actx, sigma=sigma) int_val = -int_val / (2 * np.pi) print("int_val = ", int_val) u_A_sym_vol = stokeslet_obj.apply( # noqa: N806 omega_sym, mu_sym, qbx_forced_limit=2) representation_sym = ( -stresslet_obj.apply(sigma_sym, nvec_sym, mu_sym, qbx_forced_limit=2) + stokeslet_obj.apply(meanless_sigma_sym, mu_sym, qbx_forced_limit=2) - u_A_sym_vol + sigma_int_val_sym) where = (sym.DEFAULT_SOURCE, "point_target") vel = bind(places, representation_sym, auto_where=where)(actx, sigma=sigma, mu=mu, normal=normal, sigma_int_val=int_val, omega=omega) print("@@@@@@@@") plot_vel = bind(places, representation_sym, auto_where=(sym.DEFAULT_SOURCE, "plot_target"))(actx, sigma=sigma, mu=mu, normal=normal, sigma_int_val=int_val, omega=omega) def get_obj_array(obj_array): return make_obj_array([ary.get() for ary in obj_array]) exact_soln = fund_and_rot_soln(actx.from_numpy(eval_points[0]), actx.from_numpy(eval_points[1]), fund_soln_loc, strength) vel = get_obj_array(vel) err = vel - get_obj_array(exact_soln) # FIXME: Pointwise relative errors don't make sense! rel_err = err / (get_obj_array(exact_soln)) if 0: print("@@@@@@@@") print("vel[0], err[0], rel_err[0] ***** vel[1], err[1], rel_err[1]: ") for i in range(len(vel[0])): print( "{:15.8e}, {:15.8e}, {:15.8e} ***** {:15.8e}, {:15.8e}, {:15.8e}" .format(vel[0][i], err[0][i], rel_err[0][i], vel[1][i], err[1][i], rel_err[1][i])) print("@@@@@@@@") l2_err = np.sqrt((6. / (nsamp - 1))**2 * np.sum(err[0] * err[0]) + (6. / (nsamp - 1))**2 * np.sum(err[1] * err[1])) l2_rel_err = np.sqrt((6. / (nsamp - 1))**2 * np.sum(rel_err[0] * rel_err[0]) + (6. / (nsamp - 1))**2 * np.sum(rel_err[1] * rel_err[1])) print("L2 error estimate: ", l2_err) print("L2 rel error estimate: ", l2_rel_err) print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1]))) print("max rel error at sampled points: ", max(abs(rel_err[0])), max(abs(rel_err[1]))) if visualize: import matplotlib.pyplot as plt full_pot = np.zeros_like(fplot.points) * float("nan") mask = circle_mask(fplot.points, radius=circle_rad) for i, vel in enumerate(plot_vel): full_pot[i, mask] = vel.get() plt.quiver(fplot.points[0], fplot.points[1], full_pot[0], full_pot[1], linewidth=0.1) plt.savefig("exterior-2d-field.pdf") # }}} h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx) return h_max, l2_err