def ic_expr(t, x, fields): from hedge.optemplate import CFunction from pymbolic.primitives import IfPositive from pytools.obj_array import make_obj_array tanh = CFunction("tanh") sin = CFunction("sin") rho = 1 u0 = 0.05 w = 0.05 delta = 0.05 from hedge.optemplate.primitives import make_common_subexpression as cse u = cse(make_obj_array([ IfPositive(x[1]-1/2, u0*tanh(4*(3/4-x[1])/w), u0*tanh(4*(x[1]-1/4)/w)), u0*delta*sin(2*np.pi*(x[0]+1/4))]), "u") return make_obj_array([ op.method.f_equilibrium(rho, alpha, u) for alpha in range(len(op.method)) ])
def test_make_obj_array_iteration(): pytest.importorskip("numpy") from pytools.obj_array import make_obj_array make_obj_array([FakeArray()]) assert FakeArray.nopes == 0, FakeArray.nopes
def __call__(self, t, x_vec, eos=IdealSingleGas()): """ Create the lump-of-mass solution at time *t* and locations *x_vec*. Note that *t* is used to advect the mass lump under the assumption of constant, and uniform velocity. Parameters ---------- t: float Current time at which the solution is desired x_vec: numpy.ndarray Nodal coordinates eos: :class:`mirgecom.eos.GasEOS` Equation of state class to be used in construction of soln (if needed) """ lump_loc = self._center + t * self._velocity assert len(x_vec) == self._dim # coordinates relative to lump center rel_center = make_obj_array( [x_vec[i] - lump_loc[i] for i in range(self._dim)] ) actx = x_vec[0].array_context r = actx.np.sqrt(np.dot(rel_center, rel_center)) gamma = eos.gamma() expterm = self._rhoamp * actx.np.exp(1 - r ** 2) mass = expterm + self._rho0 mom = self._velocity * make_obj_array([mass]) energy = (self._p0 / (gamma - 1.0)) + np.dot(mom, mom) / (2.0 * mass) return flat_obj_array(mass, energy, mom)
def cross_rank_trace_pairs(discrwb, vec, tag=None): if (isinstance(vec, np.ndarray) and vec.dtype.char == "O" and not isinstance(vec, DOFArray)): n, = vec.shape result = {} for ivec in range(n): for rank_tpair in _cross_rank_trace_pairs_scalar_field( discrwb, vec[ivec]): assert isinstance(rank_tpair.dd.domain_tag, sym.DTAG_BOUNDARY) assert isinstance(rank_tpair.dd.domain_tag.tag, BTAG_PARTITION) result[rank_tpair.dd.domain_tag.tag.part_nr, ivec] = rank_tpair return [ TracePair( dd=sym.as_dofdesc(sym.DTAG_BOUNDARY(BTAG_PARTITION(remote_rank))), interior=make_obj_array([ result[remote_rank, i].int for i in range(n)]), exterior=make_obj_array([ result[remote_rank, i].ext for i in range(n)]) ) for remote_rank in discrwb.connected_ranks()] else: return _cross_rank_trace_pairs_scalar_field(discrwb, vec, tag=tag)
def ic_expr(t, x, fields): from hedge.optemplate import CFunction from pymbolic.primitives import IfPositive from pytools.obj_array import make_obj_array tanh = CFunction("tanh") sin = CFunction("sin") rho = 1 u0 = 0.05 w = 0.05 delta = 0.05 from hedge.optemplate.primitives import make_common_subexpression as cse u = cse( make_obj_array([ IfPositive(x[1] - 1 / 2, u0 * tanh(4 * (3 / 4 - x[1]) / w), u0 * tanh(4 * (x[1] - 1 / 4) / w)), u0 * delta * sin(2 * np.pi * (x[0] + 1 / 4)) ]), "u") return make_obj_array([ op.method.f_equilibrium(rho, alpha, u) for alpha in range(len(op.method)) ])
def exact_rhs(self, discr, cv, t=0.0): """ Create the RHS for the uniform solution. (Hint - it should be all zero). Parameters ---------- q State array which expects at least the canonical conserved quantities (mass, energy, momentum) for the fluid at each point. (unused) t: float Time at which RHS is desired (unused) """ actx = cv.array_context nodes = thaw(actx, discr.nodes()) mass = nodes[0].copy() mass[:] = 1.0 massrhs = 0.0 * mass energyrhs = 0.0 * mass momrhs = make_obj_array([0 * mass for i in range(self._dim)]) yrhs = make_obj_array([0 * mass for i in range(self._nspecies)]) return make_conserved(dim=self._dim, mass=massrhs, energy=energyrhs, momentum=momrhs, species_mass=yrhs)
def __call__(self, x_vec, eos, **kwargs): """ Create the mixture state at locations *x_vec* (t is ignored). Parameters ---------- x_vec: numpy.ndarray Coordinates at which solution is desired eos: Mixture-compatible equation-of-state object must provide these functions: `eos.get_density` `eos.get_internal_energy` """ if x_vec.shape != (self._dim,): raise ValueError(f"Position vector has unexpected dimensionality," f" expected {self._dim}.") ones = (1.0 + x_vec[0]) - x_vec[0] pressure = self._pressure * ones temperature = self._temperature * ones velocity = make_obj_array([self._velocity[i] * ones for i in range(self._dim)]) y = make_obj_array([self._massfracs[i] * ones for i in range(self._nspecies)]) mass = eos.get_density(pressure, temperature, y) specmass = mass * y mom = mass * velocity internal_energy = eos.get_internal_energy(temperature=temperature, species_mass_fractions=y) kinetic_energy = 0.5 * np.dot(velocity, velocity) energy = mass * (internal_energy + kinetic_energy) return make_conserved(dim=self._dim, mass=mass, energy=energy, momentum=mom, species_mass=specmass)
def test_inviscid_flux(actx_factory, dim): """Identity test - directly check inviscid flux routine :func:`mirgecom.euler.inviscid_flux` against the exact expected result. This test is designed to fail if the flux routine is broken. The expected inviscid flux is: F(q) = <rhoV, (E+p)V, rho(V.x.V) + pI> """ actx = actx_factory() nel_1d = 16 from meshmode.mesh.generation import generate_regular_rect_mesh # for dim in [1, 2, 3]: mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, n=(nel_1d, ) * dim) order = 3 discr = EagerDGDiscretization(actx, mesh, order=order) eos = IdealSingleGas() logger.info(f"Number of {dim}d elems: {mesh.nelements}") mass = cl.clrandom.rand(actx.queue, (mesh.nelements, ), dtype=np.float64) energy = cl.clrandom.rand(actx.queue, (mesh.nelements, ), dtype=np.float64) mom = make_obj_array([ cl.clrandom.rand(actx.queue, (mesh.nelements, ), dtype=np.float64) for i in range(dim) ]) q = join_conserved(dim, mass=mass, energy=energy, momentum=mom) cv = split_conserved(dim, q) # {{{ create the expected result p = eos.pressure(cv) escale = (energy + p) / mass expected_flux = np.zeros((dim + 2, dim), dtype=object) expected_flux[0] = mom expected_flux[1] = mom * make_obj_array([escale]) for i in range(dim): for j in range(dim): expected_flux[2 + i, j] = (mom[i] * mom[j] / mass + (p if i == j else 0)) # }}} from mirgecom.euler import inviscid_flux flux = inviscid_flux(discr, eos, q) flux_resid = flux - expected_flux for i in range(dim + 2, dim): for j in range(dim): assert (la.norm(flux_resid[i, j].get())) == 0.0
def make_surface_particle_array(queue, nparticles, dims, dtype, seed=15): if dims == 2: def get_2d_knl(dtype): knl = lp.make_kernel( "{[i]: 0<=i<n}", """ for i <> phi = 2*M_PI/n * i x[i] = 0.5* (3*cos(phi) + 2*sin(3*phi)) y[i] = 0.5* (1*sin(phi) + 1.5*sin(2*phi)) end """, [ lp.GlobalArg("x,y", dtype, shape=lp.auto), lp.ValueArg("n", np.int32), ], name="make_surface_dist") knl = lp.split_iname(knl, "i", 128, outer_tag="g.0", inner_tag="l.0") return knl evt, result = get_2d_knl(dtype)(queue, n=nparticles) result = [x.ravel() for x in result] return make_obj_array(result) elif dims == 3: n = int(nparticles**0.5) def get_3d_knl(dtype): knl = lp.make_kernel( "{[i,j]: 0<=i,j<n}", """ for i,j <> phi = 2*M_PI/n * i <> theta = 2*M_PI/n * j x[i,j] = 5*cos(phi) * (3 + cos(theta)) y[i,j] = 5*sin(phi) * (3 + cos(theta)) z[i,j] = 5*sin(theta) end """, [ lp.GlobalArg("x,y,z,", dtype, shape=lp.auto), lp.ValueArg("n", np.int32), ]) knl = lp.split_iname(knl, "i", 16, outer_tag="g.1", inner_tag="l.1") knl = lp.split_iname(knl, "j", 16, outer_tag="g.0", inner_tag="l.0") return knl evt, result = get_3d_knl(dtype)(queue, n=n) result = [x.ravel() for x in result] return make_obj_array(result) else: raise NotImplementedError
def make_surface_particle_array(queue, nparticles, dims, dtype, seed=15): import loopy as lp if dims == 2: @first_arg_dependent_memoize_nested def get_2d_knl(context, dtype): knl = lp.make_kernel( "{[i]: 0<=i<n}", """ <> phi = 2*M_PI/n * i x[i] = 0.5* (3*cos(phi) + 2*sin(3*phi)) y[i] = 0.5* (1*sin(phi) + 1.5*sin(2*phi)) """, [ lp.GlobalArg("x,y", dtype, shape=lp.auto), lp.ValueArg("n", np.int32), ], name="make_surface_dist") knl = lp.split_iname(knl, "i", 128, outer_tag="g.0", inner_tag="l.0") return lp.CompiledKernel(context, knl) evt, result = get_2d_knl(queue.context, dtype)(queue, n=nparticles) result = [x.ravel() for x in result] return make_obj_array(result) elif dims == 3: n = int(nparticles**0.5) @first_arg_dependent_memoize_nested def get_3d_knl(context, dtype): knl = lp.make_kernel( "{[i,j]: 0<=i,j<n}", """ <> phi = 2*M_PI/n * i <> theta = 2*M_PI/n * j x[i,j] = 5*cos(phi) * (3 + cos(theta)) y[i,j] = 5*sin(phi) * (3 + cos(theta)) z[i,j] = 5*sin(theta) """, [ lp.GlobalArg("x,y,z,", dtype, shape=lp.auto), lp.ValueArg("n", np.int32), ]) knl = lp.split_iname(knl, "i", 16, outer_tag="g.1", inner_tag="l.1") knl = lp.split_iname(knl, "j", 16, outer_tag="g.0", inner_tag="l.0") return lp.CompiledKernel(context, knl) evt, result = get_3d_knl(queue.context, dtype)(queue, n=n) result = [x.ravel() for x in result] return make_obj_array(result) else: raise NotImplementedError
def test_velocity_gradient_eoc(actx_factory, dim): """Test that the velocity gradient converges at the proper rate.""" from mirgecom.fluid import velocity_gradient actx = actx_factory() order = 3 from pytools.convergence import EOCRecorder eoc = EOCRecorder() nel_1d_0 = 4 for hn1 in [1, 2, 3, 4]: nel_1d = hn1 * nel_1d_0 h = 1/nel_1d from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(1.0,) * dim, b=(2.0,) * dim, nelements_per_axis=(nel_1d,) * dim ) discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) energy = zeros + 2.5 mass = nodes[dim-1]*nodes[dim-1] velocity = make_obj_array([actx.np.cos(nodes[i]) for i in range(dim)]) mom = mass*velocity q = join_conserved(dim, mass=mass, energy=energy, momentum=mom) cv = split_conserved(dim, q) grad_q = obj_array_vectorize(discr.grad, q) grad_cv = split_conserved(dim, grad_q) grad_v = velocity_gradient(discr, cv, grad_cv) def exact_grad_row(xdata, gdim, dim): exact_grad_row = make_obj_array([zeros for _ in range(dim)]) exact_grad_row[gdim] = -actx.np.sin(xdata) return exact_grad_row comp_err = make_obj_array([ discr.norm(grad_v[i] - exact_grad_row(nodes[i], i, dim), np.inf) for i in range(dim)]) err_max = comp_err.max() eoc.add_data_point(h, err_max) logger.info(eoc) assert ( eoc.order_estimate() >= order - 0.5 or eoc.max_error() < 1e-9 )
def test_species_mass_gradient(actx_factory, dim): """Test gradY structure and values against exact.""" actx = actx_factory() nel_1d = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh( a=(1.0,) * dim, b=(2.0,) * dim, nelements_per_axis=(nel_1d,) * dim ) order = 1 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(actx, discr.nodes()) zeros = discr.zeros(actx) ones = zeros + 1 nspecies = 2*dim mass = 2*ones # make mass != 1 energy = zeros + 2.5 velocity = make_obj_array([ones for _ in range(dim)]) mom = mass * velocity # assemble y so that each one has simple, but unique grad components y = make_obj_array([ones for _ in range(nspecies)]) for idim in range(dim): ispec = 2*idim y[ispec] = ispec*(idim*dim+1)*sum([(iidim+1)*nodes[iidim] for iidim in range(dim)]) y[ispec+1] = -y[ispec] species_mass = mass*y cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom, species_mass=species_mass) from grudge.op import local_grad grad_cv = local_grad(discr, cv) from mirgecom.fluid import species_mass_fraction_gradient grad_y = species_mass_fraction_gradient(cv, grad_cv) assert grad_y.shape == (nspecies, dim) from meshmode.dof_array import DOFArray assert type(grad_y[0, 0]) == DOFArray def inf_norm(x): return actx.to_numpy(discr.norm(x, np.inf)) tol = 1e-11 for idim in range(dim): ispec = 2*idim exact_grad = np.array([(ispec*(idim*dim+1))*(iidim+1) for iidim in range(dim)]) assert inf_norm(grad_y[ispec] - exact_grad) < tol assert inf_norm(grad_y[ispec+1] + exact_grad) < tol
def cross_rank_trace_pairs(dcoll: DiscretizationCollection, ary, tag=None) -> list: r"""Get a :class:`list` of *ary* trace pairs for each partition boundary. For each partition boundary, the field data values in *ary* are communicated to/from the neighboring partition. Presumably, this communication is MPI (but strictly speaking, may not be, and this routine is agnostic to the underlying communication). For each face on each partition boundary, a :class:`TracePair` is created with the locally, and remotely owned partition boundary face data as the `internal`, and `external` components, respectively. Each of the TracePair components are structured like *ary*. :arg ary: a single :class:`~meshmode.dof_array.DOFArray`, or an object array of :class:`~meshmode.dof_array.DOFArray`\ s of arbitrary shape. :returns: a :class:`list` of :class:`TracePair` objects. """ if isinstance(ary, np.ndarray): oshape = ary.shape comm_vec = ary.flatten() n, = comm_vec.shape result = {} # FIXME: Batch this communication rather than # doing it in sequence. for ivec in range(n): for rank_tpair in _cross_rank_trace_pairs_scalar_field( dcoll, comm_vec[ivec]): assert isinstance(rank_tpair.dd.domain_tag, dof_desc.DTAG_BOUNDARY) assert isinstance(rank_tpair.dd.domain_tag.tag, BTAG_PARTITION) result[rank_tpair.dd.domain_tag.tag.part_nr, ivec] = rank_tpair return [ TracePair(dd=dof_desc.as_dofdesc( dof_desc.DTAG_BOUNDARY(BTAG_PARTITION(remote_rank))), interior=make_obj_array( [result[remote_rank, i].int for i in range(n)]).reshape(oshape), exterior=make_obj_array( [result[remote_rank, i].ext for i in range(n)]).reshape(oshape)) for remote_rank in connected_ranks(dcoll) ] else: return _cross_rank_trace_pairs_scalar_field(dcoll, ary, tag=tag)
def xyz_to_tangential(xyz_vec, where=None): ambient_dim = len(xyz_vec) tonb = tangential_onb(ambient_dim, where=where) return make_obj_array([ np.dot(tonb[:, i], xyz_vec) for i in range(ambient_dim - 1) ])
def polyfn(coeff): # , x_vec): # r = actx.np.sqrt(np.dot(nodes, nodes)) r = nodes[0] result = 0 for n, a in enumerate(coeff): result += a * r**n return make_obj_array([result])
def _small_mat_eigenvalues(mat): m, n = mat.shape if m != n: raise ValueError("eigenvalues only make sense for square matrices") if m == 1: return make_obj_array([mat[0, 0]]) elif m == 2: (a, b), (c, d) = mat return make_obj_array([ -(sqrt(d**2-2*a*d+4*b*c+a**2)-d-a)/2, (sqrt(d**2-2*a*d+4*b*c+a**2)+d+a)/2 ]) else: raise NotImplementedError( "eigenvalue formula for %dx%d matrices" % (m, n))
def nodes(self): r""" :returns: object array of shape ``(ambient_dim,)`` containing :class:`~meshmode.dof_array.DOFArray`\ s of node coordinates. """ actx = self._setup_actx @memoize_in(actx, (Discretization, "nodes_prg")) def prg(): return make_loopy_program("""{[iel,idof,j]: 0<=iel<nelements and 0<=idof<ndiscr_nodes and 0<=j<nmesh_nodes}""", """ result[iel, idof] = \ sum(j, resampling_mat[idof, j] * nodes[iel, j]) """, name="nodes") return make_obj_array([ _DOFArray.from_list(None, [ actx.freeze( actx.call_loopy( prg(), resampling_mat=actx.from_numpy( grp.from_mesh_interp_matrix()), nodes=actx.from_numpy( grp.mesh_el_group.nodes[iaxis]))["result"]) for grp in self.groups ]) for iaxis in range(self.ambient_dim) ])
def make_normal_particle_array(queue, nparticles, dims, dtype, seed=15): from pyopencl.clrandom import PhiloxGenerator rng = PhiloxGenerator(queue.context, seed=seed) return make_obj_array([ rng.normal(queue, nparticles, dtype=dtype) for i in range(dims)])
def matvec(self, x): if isinstance(x, np.ndarray): x = cl.array.to_device(self.queue, x) out_host = True else: out_host = False do_split = len(self.starts_and_ends) > 1 from pytools.obj_array import make_obj_array if do_split: x = make_obj_array( [x[start:end] for start, end in self.starts_and_ends]) args = self.extra_args.copy() args[self.arg_name] = x result = self.bound_expr(self.queue, **args) if do_split: # re-join what was split joined_result = cl.array.empty(self.queue, self.total_dofs, np.complex128) # FIXME for res_i, (start, end) in zip(result, self.starts_and_ends): joined_result[start:end] = res_i result = joined_result if out_host: result = result.get() return result
def _small_mat_inverse(mat): m, n = mat.shape if m != n: raise ValueError("inverses only make sense for square matrices") if m == 1: return make_obj_array([1/mat[0, 0]]) elif m == 2: (a, b), (c, d) = mat return 1/(a*d-b*c) * make_obj_array([ [d, -b], [-c, a], ]) else: raise NotImplementedError( "inverse formula for %dx%d matrices" % (m, n))
def my_rhs(t, state): cv, tseed = state fluid_state = make_fluid_state(cv, gas_model, temperature_seed=tseed) return make_obj_array( [euler_operator(discr, state=fluid_state, time=t, boundaries=boundaries, gas_model=gas_model), 0*tseed])
def full_output_zeros(self, template_ary): """This includes QBX and non-QBX targets.""" from pytools.obj_array import make_obj_array return make_obj_array([ np.zeros(self.tree.ntargets, self.tree_indep.dtype) for k in self.tree_indep.outputs])
def representation(self, unknown, i_domain): """ :return: a symbolic expression for the representation of the PDE solution in domain number *i_domain*. """ unk = self._structured_unknown(unknown, with_l2_weights=False) result = [] for field_kind in self.field_kinds: if not self.is_field_present(field_kind): continue field_result = 0 for i_interface, (i_domain_outer, i_domain_inner, interface_id) in ( enumerate(self.interfaces)): if i_domain_outer == i_domain: side = self.side_out elif i_domain_inner == i_domain: side = self.side_in else: continue my_unk = unk[side, field_kind, i_interface] if my_unk: field_result += sym.S( self.kernel, my_unk, source=interface_id, k=self.domain_K_exprs[i_domain]) result.append(field_result) from pytools.obj_array import make_obj_array return make_obj_array(result)
def test_area_query_balls_outside_bbox(ctx_getter, dims, do_plot=False): """ The input to the area query includes balls whose centers are not within the tree bounding box. """ ctx = ctx_getter() queue = cl.CommandQueue(ctx) nparticles = 10**4 dtype = np.float64 particles = make_normal_particle_array(queue, nparticles, dims, dtype) if do_plot: import matplotlib.pyplot as pt pt.plot(particles[0].get(), particles[1].get(), "x") from boxtree import TreeBuilder tb = TreeBuilder(ctx) queue.finish() tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True) nballs = 10**4 from pyopencl.clrandom import PhiloxGenerator rng = PhiloxGenerator(ctx, seed=13) bbox_min = tree.bounding_box[0].min() bbox_max = tree.bounding_box[1].max() from pytools.obj_array import make_obj_array ball_centers = make_obj_array([ rng.uniform(queue, nballs, dtype=dtype, a=bbox_min-1, b=bbox_max+1) for i in range(dims)]) ball_radii = cl.array.empty(queue, nballs, dtype).fill(0.1) run_area_query_test(ctx, queue, tree, ball_centers, ball_radii)
def test_norm_obj_array(actx_factory, p): """Test :func:`grudge.symbolic.operators.norm` for object arrays.""" actx = actx_factory() dim = 2 mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(8, ) * dim, order=1) discr = DiscretizationCollection(actx, mesh, order=4) w = make_obj_array([1.0, 2.0, 3.0])[:dim] # {{ scalar sym_w = sym.var("w") norm = bind(discr, sym.norm(p, sym_w))(actx, w=w[0]) norm_exact = w[0] logger.info("norm: %.5e %.5e", norm, norm_exact) assert abs(norm - norm_exact) < 1.0e-14 # }}} # {{{ vector sym_w = sym.make_sym_array("w", dim) norm = bind(discr, sym.norm(p, sym_w))(actx, w=w) norm_exact = np.sqrt(np.sum(w**2)) if p == 2 else np.max(w) logger.info("norm: %.5e %.5e", norm, norm_exact) assert abs(norm - norm_exact) < 1.0e-14
def tangent(self): self.arguments["tangent"] = \ lp.GlobalArg("tangent", self.geometry_dtype, shape=("ntargets", self.dim), order="C") from pytools.obj_array import make_obj_array return make_obj_array( [parse("tangent[itgt, %d]" % i) for i in range(self.dim)])
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 map_nodes(self, expr): discr = self.discr_dict[expr.where] from pytools.obj_array import make_obj_array return MultiVector( make_obj_array([ prim.NodeCoordinateComponent(i, expr.where) for i in range(discr.ambient_dim)]))
def get_boundaries(discr, actx, t): nodes = thaw(actx, discr.nodes()) def sym_eval(expr): return sym.EvaluationMapper({"x": nodes, "t": t})(expr) exact_u = sym_eval(sym_u) exact_grad_u = make_obj_array(sym_eval(sym.grad(dim, sym_u))) boundaries = {} for i in range(dim - 1): lower_btag = DTAG_BOUNDARY("-" + str(i)) upper_btag = DTAG_BOUNDARY("+" + str(i)) upper_grad_u = discr.project("vol", upper_btag, exact_grad_u) normal = thaw(actx, discr.normal(upper_btag)) upper_grad_u_dot_n = np.dot(upper_grad_u, normal) boundaries[lower_btag] = NeumannDiffusionBoundary(0.) boundaries[upper_btag] = NeumannDiffusionBoundary( upper_grad_u_dot_n) lower_btag = DTAG_BOUNDARY("-" + str(dim - 1)) upper_btag = DTAG_BOUNDARY("+" + str(dim - 1)) upper_u = discr.project("vol", upper_btag, exact_u) boundaries[lower_btag] = DirichletDiffusionBoundary(0.) boundaries[upper_btag] = DirichletDiffusionBoundary(upper_u) return boundaries
def map_int_g_ds(self, expr): dsource = self.rec(expr.dsource) ambient_dim = self.ambient_dim from sumpy.kernel import KernelDimensionSetter kernel = _insert_source_derivative_into_kernel( KernelDimensionSetter(ambient_dim)(expr.kernel)) from pytools.obj_array import make_obj_array nabla = MultiVector(make_obj_array( [prim.NablaComponent(axis, None) for axis in range(ambient_dim)])) kernel_arguments = dict( (name, self.rec(arg_expr)) for name, arg_expr in expr.kernel_arguments.items() ) def add_dir_vec_to_kernel_args(coeff): result = kernel_arguments.copy() result[_DIR_VEC_NAME] = _get_dir_vec(coeff, ambient_dim) return result rec_operand = prim.cse(self.rec(expr.density)) return (dsource*nabla).map( lambda coeff: prim.IntG( kernel, rec_operand, expr.qbx_forced_limit, expr.source, expr.target, kernel_arguments=add_dir_vec_to_kernel_args(coeff)))
def map_nabla(self, expr): from pytools.obj_array import make_obj_array return MultiVector( make_obj_array([ prim.NablaComponent(axis, expr.nabla_id) for axis in range(self.ambient_dim) ]))
def compute_short_lists(self, queue, wait_for=None): """balls --> overlapping leaves """ mesh = self.discr.mesh if len(mesh.groups) > 1: raise NotImplementedError("Mixed elements not supported") melgrp = mesh.groups[0] ball_centers_host = (np.max(melgrp.nodes, axis=2) + np.min(melgrp.nodes, axis=2)) / 2 ball_radii_host = np.max( np.max(melgrp.nodes, axis=2) - np.min(melgrp.nodes, axis=2), axis=0) / 2 ball_centers = make_obj_array([ cl.array.to_device(queue, center_coord_comp) for center_coord_comp in ball_centers_host ]) ball_radii = cl.array.to_device(queue, ball_radii_host) area_query_result, evt = self.area_query_builder(queue, self.tree, ball_centers, ball_radii, peer_lists=None, wait_for=wait_for) return area_query_result, evt
def __init__(self, *, dim=1, nspecies=0, rho0=1.0, p0=1.0, center=None, velocity=None, spec_y0s=None, spec_amplitudes=None, spec_centers=None): r"""Initialize MulticomponentLump parameters. Parameters ---------- dim: int specify the number of dimensions for the lump rho0: float specifies the value of $\rho_0$ p0: float specifies the value of $p_0$ center: numpy.ndarray center of lump, shape ``(dim,)`` velocity: numpy.ndarray fixed flow velocity used for exact solution at t != 0, shape ``(dim,)`` """ if center is None: center = np.zeros(shape=(dim, )) if velocity is None: velocity = np.zeros(shape=(dim, )) if center.shape != (dim, ) or velocity.shape != (dim, ): raise ValueError(f"Expected {dim}-dimensional vector inputs.") if nspecies > 0: if spec_y0s is None: spec_y0s = np.ones(shape=(nspecies, )) if spec_centers is None: spec_centers = make_obj_array( [np.zeros(shape=dim, ) for i in range(nspecies)]) if spec_amplitudes is None: spec_amplitudes = np.ones(shape=(nspecies, )) if len(spec_y0s) != nspecies or\ len(spec_amplitudes) != nspecies or\ len(spec_centers) != nspecies: raise ValueError(f"Expected nspecies={nspecies} inputs.") for i in range(nspecies): if len(spec_centers[i]) != dim: raise ValueError(f"Expected {dim}-dimensional " f"inputs for spec_centers.") self._nspecies = nspecies self._dim = dim self._velocity = velocity self._center = center self._p0 = p0 self._rho0 = rho0 self._spec_y0s = spec_y0s self._spec_centers = spec_centers self._spec_amplitudes = spec_amplitudes
def sym_wave(dim, sym_phi): """Return symbolic expressions for the wave equation system given a desired solution. (Note: In order to support manufactured solutions, we modify the wave equation to add a source term (f). If the solution is exact, this term should be 0.) """ sym_c = pmbl.var("c") sym_coords = prim.make_sym_vector("x", dim) sym_t = pmbl.var("t") # f = phi_tt - c^2 * div(grad(phi)) sym_f = sym.diff(sym_t)(sym.diff(sym_t)(sym_phi)) - sym_c**2\ * sym.div(sym.grad(dim, sym_phi)) # u = phi_t sym_u = sym.diff(sym_t)(sym_phi) # v = c*grad(phi) sym_v = [sym_c * sym.diff(sym_coords[i])(sym_phi) for i in range(dim)] # rhs(u part) = c*div(v) + f # rhs(v part) = c*grad(u) sym_rhs = flat_obj_array(sym_c * sym.div(sym_v) + sym_f, make_obj_array([sym_c]) * sym.grad(dim, sym_u)) return sym_u, sym_v, sym_f, sym_rhs
def matvec(self, x): if isinstance(x, np.ndarray): x = cl.array.to_device(self.queue, x) out_host = True else: out_host = False do_split = len(self.starts_and_ends) > 1 from pytools.obj_array import make_obj_array if do_split: x = make_obj_array( [x[start:end] for start, end in self.starts_and_ends]) args = self.extra_args.copy() args[self.arg_name] = x result = self.bound_expr(self.queue, **args) if do_split: # re-join what was split joined_result = cl.array.empty(self.queue, self.total_dofs, self.dtype) for res_i, (start, end) in zip(result, self.starts_and_ends): joined_result[start:end] = res_i result = joined_result if out_host: result = result.get() return result
def test_container_norm(actx_factory, ord): actx = actx_factory() ary_dof, ary_of_dofs, mat_of_dofs, dc_of_dofs = _get_test_containers(actx) from pytools.obj_array import make_obj_array c = MyContainer(name="hey", mass=1, momentum=make_obj_array([2, 3]), enthalpy=5) n1 = actx.np.linalg.norm(make_obj_array([c, c]), ord) n2 = np.linalg.norm([1, 2, 3, 5] * 2, ord) assert abs(n1 - n2) < 1e-12 assert abs(flat_norm(ary_dof, ord) - actx.np.linalg.norm(ary_dof, ord)) < 1e-12
def representation(self, unknown, i_domain): """ :return: a symbolic expression for the representation of the PDE solution in domain number *i_domain*. """ unk = self._structured_unknown(unknown, with_l2_weights=False) result = [] for field_kind in self.field_kinds: if not self.is_field_present(field_kind): continue field_result = 0 for i_interface, (i_domain_outer, i_domain_inner, interface_id) in (enumerate(self.interfaces)): if i_domain_outer == i_domain: side = self.side_out elif i_domain_inner == i_domain: side = self.side_in else: continue my_unk = unk[side, field_kind, i_interface] if my_unk: field_result += sym.S(self.kernel, my_unk, source=interface_id, k=self.domain_K_exprs[i_domain]) result.append(field_result) from pytools.obj_array import make_obj_array return make_obj_array(result)
def __call__(self, arg): if isinstance(arg, int) and arg == 0: return 0 from pytools.obj_array import make_obj_array from hedge.optemplate.primitives import OperatorBinding return make_obj_array([OperatorBinding(FluxOperator(f), arg) for f in self.fluxes])
def add_div_bcs(self, tgt, bc_getter, dirichlet_tags, neumann_tags, stab_term, adjust_flux, flux_v, flux_arg_int, grad_flux_arg_count): from pytools.obj_array import make_obj_array, join_fields n_times = tgt.normal_times_flux def unwrap_cse(expr): from pymbolic.primitives import CommonSubexpression if isinstance(expr, CommonSubexpression): return expr.child else: return expr for tag in dirichlet_tags: dir_bc_w = join_fields( [0]*grad_flux_arg_count, [bc_getter(tag, unwrap_cse(vol_expr)) for vol_expr in flux_arg_int[grad_flux_arg_count:]]) tgt.add_boundary_flux( adjust_flux(n_times(flux_v.int-stab_term)), flux_arg_int, dir_bc_w, tag) loc_bc_vec = make_obj_array([0]*len(flux_arg_int)) for tag in neumann_tags: neu_bc_w = join_fields( NeumannBCGenerator(tag, bc_getter(tag, None))(tgt.operand), [0]*len(flux_arg_int)) tgt.add_boundary_flux( adjust_flux(n_times(flux_v.ext)), loc_bc_vec, neu_bc_w, tag)
def add_div_bcs(self, tgt, bc_getter, dirichlet_tags, neumann_tags, stab_term, adjust_flux, flux_v, flux_arg_int, grad_flux_arg_count): from pytools.obj_array import make_obj_array, join_fields n_times = tgt.normal_times_flux def unwrap_cse(expr): from pymbolic.primitives import CommonSubexpression if isinstance(expr, CommonSubexpression): return expr.child else: return expr for tag in dirichlet_tags: dir_bc_w = join_fields([0] * grad_flux_arg_count, [ bc_getter(tag, unwrap_cse(vol_expr)) for vol_expr in flux_arg_int[grad_flux_arg_count:] ]) tgt.add_boundary_flux(adjust_flux(n_times(flux_v.int - stab_term)), flux_arg_int, dir_bc_w, tag) loc_bc_vec = make_obj_array([0] * len(flux_arg_int)) for tag in neumann_tags: neu_bc_w = join_fields( NeumannBCGenerator(tag, bc_getter(tag, None))(tgt.operand), [0] * len(flux_arg_int)) tgt.add_boundary_flux(adjust_flux(n_times(flux_v.ext)), loc_bc_vec, neu_bc_w, tag)
def full_output_zeros(self): """This includes QBX and non-QBX targets.""" from pytools.obj_array import make_obj_array return make_obj_array([ np.zeros(self.tree.ntargets, self.dtype) for k in self.outputs])
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 get_operator(self, ambient_dim, qbx_forced_limit="avg"): knl = self.knl_class(ambient_dim) kwargs = self.knl_sym_kwargs.copy() kwargs["qbx_forced_limit"] = qbx_forced_limit if self.op_type == "scalar": sym_u = sym.var("u") sym_op = sym.S(knl, sym_u, **kwargs) elif self.op_type == "scalar_mixed": sym_u = sym.var("u") sym_op = sym.S(knl, 0.3 * sym_u, **kwargs) \ + sym.D(knl, 0.5 * sym_u, **kwargs) elif self.op_type == "vector": sym_u = sym.make_sym_vector("u", ambient_dim) sym_op = make_obj_array([ sym.Sp(knl, sym_u[0], **kwargs) + sym.D(knl, sym_u[1], **kwargs), sym.S(knl, 0.4 * sym_u[0], **kwargs) + 0.3 * sym.D(knl, sym_u[0], **kwargs) ]) else: raise ValueError(f"unknown operator type: '{self.op_type}'") sym_op = 0.5 * sym_u + sym_op return sym_u, sym_op
def tangent(self): self.arguments["tangent"] = \ lp.GlobalArg("tangent", self.geometry_dtype, shape=("ntargets", self.dim), order="C") from pytools.obj_array import make_obj_array return make_obj_array([ parse("tangent[itgt, %d]" % i) for i in range(self.dim)])
def potential_zeros(self): from pytools.obj_array import make_obj_array return make_obj_array([ cl.array.zeros( self.queue, self.tree.ntargets, dtype=self.dtype) for k in self.code.out_kernels])
def curl(vec): from pytools import levi_civita from pytools.obj_array import make_obj_array return make_obj_array([ sum( levi_civita((l, m, n)) * dd_axis(m, 3, vec[n]) for m in range(3) for n in range(3)) for l in range(3)])
def nodes(ambient_dim, where=None): """Return a :class:`pymbolic.geometric_algebra.MultiVector` of node locations. """ return MultiVector( make_obj_array([ NodeCoordinateComponent(i, where) for i in range(ambient_dim)]))
def curl_S_volume(kernel, arg): from pytools import levi_civita from pytools.obj_array import make_obj_array return make_obj_array([ sum( levi_civita((l, m, n)) * IntGdTarget(kernel, arg[n], m) for m in range(3) for n in range(3)) for l in range(3)])
def src_derivative_dir(self): self.arguments["src_derivative_dir"] = \ lp.GlobalArg("src_derivative_dir", self.geometry_dtype, shape=("ntargets", self.dim), order="C") from pytools.obj_array import make_obj_array return make_obj_array([ parse("src_derivative_dir[itgt, %d]" % i) for i in range(self.dim)])
def cross(vec_a, vec_b): assert len(vec_a) == len(vec_b) == 3 from pytools import levi_civita from pytools.obj_array import make_obj_array return make_obj_array([ sum( levi_civita((i, j, k)) * vec_a[j] * vec_b[k] for j in range(3) for k in range(3)) for i in range(3)])
def n_cross(vec, which=None): nrm = normal(3, which) from pytools import levi_civita from pytools.obj_array import make_obj_array return make_obj_array([ sum( levi_civita((i, j, k)) * nrm[j] * vec[k] for j in range(3) for k in range(3)) for i in range(3)])
def make_artificial_diffusion(): if self.artificial_viscosity_mode not in ["diffusion"]: return 0 dq = self.grad_of_state() return make_obj_array([ self.div( to_vol_quad(self.sensor())*to_vol_quad(dq[i]), to_int_face_quad(self.sensor())*to_int_face_quad(dq[i])) for i in range(dq.shape[0])])
def apply_diff(self, nabla, operand): from pytools.obj_array import make_obj_array, is_obj_array if is_obj_array(operand): if len(operand) != self.dimensions: raise ValueError("operand of apply_diff must have %d dimensions" % self.dimensions) return sum(nabla[i](operand[i]) for i in range(self.dimensions)) else: return make_obj_array( [nabla[i](operand) for i in range(self.dimensions)])
def collision_update(self, f_bar): from hedge.optemplate.primitives import make_common_subexpression as cse rho = cse(self.rho(f_bar), "rho") rho_u = self.rho_u(f_bar) u = cse(rho_u/rho, "u") f_eq_func = self.method.f_equilibrium f_eq = make_obj_array([ f_eq_func(rho, alpha, u) for alpha in range(len(self.method))]) return f_bar - 1/(self.tau+1/2)*(f_bar - f_eq)
def output_zeros(self): """This ought to be called ``non_qbx_output_zeros``, but since it has to override the superclass's behavior to integrate seamlessly, it needs to be called just :meth:`output_zeros`. """ nqbtl = self.geo_data.non_qbx_box_target_lists() from pytools.obj_array import make_obj_array return make_obj_array([ np.zeros(nqbtl.nfiltered_targets, self.dtype) for k in self.outputs])
def centers(self): """ Return an object array of (interleaved) center coordinates. ``coord_t [ambient_dim][ncenters]`` """ with cl.CommandQueue(self.cl_context) as queue: from pytential.qbx.utils import get_interleaved_centers from pytools.obj_array import make_obj_array return make_obj_array([ ccomp.with_queue(None) for ccomp in get_interleaved_centers(queue, self.lpot_source)])
def curl(self, arg): """Take the curl of the vector quantity *arg*. :arg arg: an object array of shape ``(3,)`` containing :class:`numpy.ndarrays` with shape ``(npoints_total,)``. """ from pytools import levi_civita from pytools.obj_array import make_obj_array return make_obj_array([ sum( levi_civita((l, m, n)) * self.diff(m, arg[n]) for m in range(3) for n in range(3)) for l in range(3)])
def plot_traversal(ctx_getter, do_plot=False, well_sep_is_n_away=1): ctx = ctx_getter() queue = cl.CommandQueue(ctx) #for dims in [2, 3]: for dims in [2]: nparticles = 10**4 dtype = np.float64 from pyopencl.clrandom import PhiloxGenerator rng = PhiloxGenerator(queue.context, seed=15) from pytools.obj_array import make_obj_array particles = make_obj_array([ rng.normal(queue, nparticles, dtype=dtype) for i in range(dims)]) # if do_plot: # pt.plot(particles[0].get(), particles[1].get(), "x") from boxtree import TreeBuilder tb = TreeBuilder(ctx) queue.finish() tree, _ = tb(queue, particles, max_particles_in_box=30, debug=True) from boxtree.traversal import FMMTraversalBuilder tg = FMMTraversalBuilder(ctx, well_sep_is_n_away=well_sep_is_n_away) trav, _ = tg(queue, tree) tree = tree.get(queue=queue) trav = trav.get(queue=queue) from boxtree.visualization import TreePlotter plotter = TreePlotter(tree) plotter.draw_tree(fill=False, edgecolor="black") #plotter.draw_box_numbers() plotter.set_bounding_box() from random import randrange, seed # noqa seed(7) from boxtree.visualization import draw_box_lists #draw_box_lists(randrange(tree.nboxes)) draw_box_lists(plotter, trav, 320) #plotter.draw_box_numbers() import matplotlib.pyplot as pt pt.show()
def func_on_scalar_or_vector(func, arg_fields): # No CSE necessary here--the compiler CSE's these # automatically. from hedge.tools import is_obj_array, make_obj_array if is_obj_array(arg_fields): # arg_fields (as an object array) isn't hashable # --make it so by turning it into a tuple arg_fields = tuple(arg_fields) return make_obj_array([ func(i, arg_fields) for i in range(len(arg_fields))]) else: return func(0, (arg_fields,))