def __init__(self, nspts, cfg): self.nspts = nspts self.cfg = cfg self.order = cfg.getint('solver', 'order') self.antialias = cfg.get('solver', 'anti-alias', 'none') self.antialias = {s.strip() for s in self.antialias.split(',')} self.antialias.discard('none') if self.antialias - {'flux', 'div-flux', 'surf-flux'}: raise ValueError('Invalid anti-alias options') self.ubasis = get_polybasis(self.name, self.order + 1, self.upts) if nspts: self.nsptsord = nsptord = self.order_from_nspts(nspts) self.sbasis = get_polybasis(self.name, nsptord, self.spts) # Basis for free-stream metric # We need p-th order pseudo grid points, which includes # p-th order points on faces. # It guarantees th q-th order collocation projection on the face # on the both adjacent cells. # Ref. 1 JCP 281, 28-54, Sec 4.2 # Ref. 2 JSC 26(3), 301-327, Definition 1 self.mbasis = get_polybasis(self.name, self.order + 1, self.mpts)
def __init__(self, nspts, cfg): self.nspts = nspts self.cfg = cfg self.order = cfg.getint('solver', 'order') self.antialias = cfg.get('solver', 'anti-alias', 'none') self.antialias = {s.strip() for s in self.antialias.split(',')} self.antialias.discard('none') if self.antialias - {'flux', 'surf-flux'}: raise ValueError('Invalid anti-alias options') self.ubasis = get_polybasis(self.name, self.order + 1, self.upts) if nspts: self.nsptsord = nsptord = self.order_from_nspts(nspts) self.sbasis = get_polybasis(self.name, nsptord, self.spts) # Basis for free-stream metric # We need p-th order pseudo grid points, which includes # p-th order points on faces. # It guarantees th q-th order collocation projection on the face # on the both adjacent cells. # Ref. 1 JCP 281, 28-54, Sec 4.2 # Ref. 2 JSC 26(3), 301-327, Definition 1 self.mbasis = get_polybasis(self.name, max(self.order + 1, 2), self.mpts)
def __init__(self, nspts, cfg): self._nspts = nspts self._cfg = cfg self._order = cfg.getint('solver', 'order') self.ubasis = get_polybasis(self.name, self._order + 1, self.upts) if nspts: self._nsptsord = nsptord = self.order_from_nspts(nspts) self.sbasis = get_polybasis(self.name, nsptord, self.spts)
def _find_curved_eles(etype, eles, tol=1e-5): nspts, neles, ndims = eles.shape shape = subclass_where(BaseShape, name=etype) order = shape.order_from_nspts(nspts) basis = get_polybasis(etype, order, shape.std_ele(order - 1)) lmodes = get_polybasis(etype, 2).degrees hmodes = [i for i, j in enumerate(basis.degrees) if j not in lmodes] ehmodes = basis.invvdm.T[hmodes] @ eles.reshape(nspts, -1) ehmodes = ehmodes.reshape(-1, neles, ndims) return np.any(np.abs(ehmodes) > tol, axis=(0, 2))
def __init__(self, nspts, cfg): self.nspts = nspts self.cfg = cfg self.order = cfg.getint('solver', 'order') self.antialias = cfg.get('solver', 'anti-alias', 'none') self.antialias = {s.strip() for s in self.antialias.split(',')} self.antialias.discard('none') if self.antialias - {'flux', 'div-flux', 'surf-flux'}: raise ValueError('Invalid anti-alias options') self.ubasis = get_polybasis(self.name, self.order + 1, self.upts) if nspts: self.nsptsord = nsptord = self.order_from_nspts(nspts) self.sbasis = get_polybasis(self.name, nsptord, self.spts)
def _fbasis_coeffs_for(self, ftype, fproj, fdjacs, nffpts): # Suitable quadrature rules for various face types qrule_map = { 'line': ('gauss-legendre', self._order + 1), 'quad': ('gauss-legendre', (self._order + 1)**2), 'tri': ('williams-shunn', 36) } # Obtain a quadrature rule for integrating on the face qrule = get_quadrule(ftype, *qrule_map[ftype]) # Project the rule points onto the various faces proj = fproj(*np.atleast_2d(qrule.np_points.T)) qfacepts = np.vstack(list(np.broadcast(*p)) for p in proj) # Obtain a nodal basis on the reference face fname = self._cfg.get('solver-interfaces-' + ftype, 'flux-pts') ffpts = get_quadrule(ftype, fname, nffpts) nodeb = get_polybasis(ftype, self._order + 1, ffpts.np_points) L = nodeb.nodal_basis_at(qrule.np_points) M = self.ubasis.ortho_basis_at(qfacepts) M = M.reshape(-1, len(proj), len(qrule.np_points)) # Do the quadrature S = np.einsum('i...,ik,jli->lkj', qrule.np_weights, L, M) # Account for differing face areas S *= np.asanyarray(fdjacs)[:,None,None] return S.reshape(-1, self.nupts)
def _linearise_eles(self, lintol): lidx = {} for etype, pent in self._elenodes: if pent != self._felespent: continue # Elements and type information elesix = self._elenodes[etype, pent] petype, nnodes = self._etype_map[etype] # Obtain the dimensionality of the element type ndim = self._petype_ndim[petype] # Node maps between input and PyFR orderings itop = self._nodemaps[petype, nnodes] ptoi = np.argsort(itop) # Construct the element array eles = self._nodepts[elesix[:, itop], :ndim].swapaxes(0, 1) # Generate the associated polynomial bases shape = subclass_where(BaseShape, name=petype) order = shape.order_from_nspts(nnodes) hbasis = get_polybasis(petype, order, shape.std_ele(order - 1)) lbasis = get_polybasis(petype, 2, shape.std_ele(1)) htol = hbasis.nodal_basis_at(lbasis.pts) ltoh = lbasis.nodal_basis_at(hbasis.pts) leles = (ltoh @ htol) @ eles.reshape(nnodes, -1) leles = leles.reshape(nnodes, -1, ndim) # Use this to determine which elements are linear num = np.max(np.abs(eles - leles), axis=0) den = np.max(eles, axis=0) - np.min(eles, axis=0) lin = lidx[petype] = np.any(num / den < lintol, axis=1) for ix in np.nonzero(lin)[0]: self._nodepts[elesix[ix], :ndim] = leles[ptoi, ix] return lidx
def facebases(self): fb = {} for kind in {k for k, p, n, a in self.faces}: rule = self.cfg.get('solver-interfaces-' + kind, 'flux-pts') npts = self.npts_for_face[kind](self.order) pts = get_quadrule(kind, rule, npts).pts fb[kind] = get_polybasis(kind, self.order + 1, pts) return fb
def facebases(self): fb = {} for kind in {k for k, p, n in self.faces}: rule = self.cfg.get(f'solver-interfaces-{kind}', 'flux-pts') npts = self.npts_for_face[kind](self.order) pts = get_quadrule(kind, rule, npts).pts fb[kind] = get_polybasis(kind, self.order + 1, pts) return fb
def fbasis_coeffs(self): coeffs = [] rcache = {} # Suitable quadrature rules for various face types qrule_map = { 'line': ('gauss-legendre', self.order + 1), 'quad': ('gauss-legendre', (self.order + 1)**2), 'tri': ('williams-shunn', 36) } for kind, proj, norm, area in self.faces: # Obtain a quadrature rule for integrating on the reference face # and evaluate this rule at the nodal basis defined by the flux # points try: qr, L = rcache[kind] except KeyError: qr = get_quadrule(kind, *qrule_map[kind]) rule = self.cfg.get('solver-interfaces-' + kind, 'flux-pts') npts = self.npts_for_face[kind](self.order) pts = get_quadrule(kind, rule, npts).np_points ppb = get_polybasis(kind, self.order + 1, pts) L = ppb.nodal_basis_at(qr.np_points) rcache[kind] = (qr, L) # Do the quadrature M = self.ubasis.ortho_basis_at(_proj_rule_pts(proj, qr)) S = np.einsum('i...,ik,ji->kj', area*qr.np_weights, L, M) coeffs.append(S) return np.vstack(coeffs)
def fbasis_coeffs(self): coeffs = [] rcache = {} # Suitable quadrature rules for various face types qrule_map = { 'line': ('gauss-legendre', self.order + 1), 'quad': ('gauss-legendre', (self.order + 1)**2), 'tri': ('williams-shunn', 36) } for kind, proj, norm, area in self.faces: # Obtain a quadrature rule for integrating on the reference face # and evaluate this rule at the nodal basis defined by the flux # points try: qr, L = rcache[kind] except KeyError: qr = get_quadrule(kind, *qrule_map[kind]) rule = self.cfg.get('solver-interfaces-' + kind, 'flux-pts') npts = self.npts_for_face[kind](self.order) pts = get_quadrule(kind, rule, npts).np_points ppb = get_polybasis(kind, self.order + 1, pts) L = ppb.nodal_basis_at(qr.np_points) rcache[kind] = (qr, L) # Do the quadrature M = self.ubasis.ortho_basis_at(_proj_rule_pts(proj, qr)) S = np.einsum('i...,ik,ji->kj', area * qr.np_weights, L, M) coeffs.append(S) return np.vstack(coeffs)
def set_backend(self, backend, nscalupts, nonce, linoff): super().set_backend(backend, nscalupts, nonce, linoff) kernel = self._be.kernel kprefix = 'pyfr.solvers.baseadvecdiff.kernels' slicem = self._slice_mat # Register our pointwise kernels self._be.pointwise.register(f'{kprefix}.gradcoru') self._be.pointwise.register(f'{kprefix}.gradcorulin') # Mesh regions regions = self._mesh_regions self.kernels['_copy_fpts'] = lambda: kernel( 'copy', self._vect_fpts.slice(0, self.nfpts), self._scal_fpts) self.kernels['tgradpcoru_upts'] = lambda uin: kernel( 'mul', self.opmat('M4 - M6*M0'), self.scal_upts[uin], out=self._vect_upts) self.kernels['tgradcoru_upts'] = lambda: kernel('mul', self.opmat('M6'), self._vect_fpts.slice( 0, self.nfpts), out=self._vect_upts, beta=1.0) # Template arguments for the physical gradient kernel tplargs = { 'ndims': self.ndims, 'nvars': self.nvars, 'nverts': len(self.basis.linspts), 'jac_exprs': self.basis.jac_exprs } if 'curved' in regions: self.kernels['gradcoru_upts_curved'] = lambda: kernel( 'gradcoru', tplargs=tplargs, dims=[self.nupts, regions['curved']], gradu=slicem(self._vect_upts, 'curved'), smats=self.smat_at('upts', 'curved'), rcpdjac=self.rcpdjac_at('upts', 'curved')) if 'linear' in regions: self.kernels['gradcoru_upts_linear'] = lambda: kernel( 'gradcorulin', tplargs=tplargs, dims=[self.nupts, regions['linear']], gradu=slicem(self._vect_upts, 'linear'), upts=self.upts, verts=self.ploc_at('linspts', 'linear')) def gradcoru_fpts(): nupts, nfpts = self.nupts, self.nfpts vupts, vfpts = self._vect_upts, self._vect_fpts # Exploit the block-diagonal form of the operator muls = [ kernel('mul', self.opmat('M0'), vupts.slice(i * nupts, (i + 1) * nupts), vfpts.slice(i * nfpts, (i + 1) * nfpts)) for i in range(self.ndims) ] return MetaKernel(muls) self.kernels['gradcoru_fpts'] = gradcoru_fpts if 'flux' in self.antialias: def gradcoru_qpts(): nupts, nqpts = self.nupts, self.nqpts vupts, vqpts = self._vect_upts, self._vect_qpts # Exploit the block-diagonal form of the operator muls = [ self._be.kernel('mul', self.opmat('M7'), vupts.slice(i * nupts, (i + 1) * nupts), vqpts.slice(i * nqpts, (i + 1) * nqpts)) for i in range(self.ndims) ] return MetaKernel(muls) self.kernels['gradcoru_qpts'] = gradcoru_qpts # Shock capturing shock_capturing = self.cfg.get('solver', 'shock-capturing', 'none') if shock_capturing == 'artificial-viscosity': tags = {'align'} # Register the kernels self._be.pointwise.register( 'pyfr.solvers.baseadvecdiff.kernels.shocksensor') # Obtain the scalar variable to be used for shock sensing shockvar = self.convarmap[self.ndims].index(self.shockvar) # Obtain the name, degrees, and order of our solution basis ubname = self.basis.ubasis.name ubdegs = self.basis.ubasis.degrees uborder = self.basis.ubasis.order # Obtain the degrees of a basis whose order is one lower lubdegs = get_polybasis(ubname, max(0, uborder - 1)).degrees # Compute the intersection ind_modes = [d not in lubdegs for d in ubdegs] # Template arguments tplargs_artvisc = dict(nvars=self.nvars, nupts=self.nupts, svar=shockvar, c=self.cfg.items_as( 'solver-artificial-viscosity', float), order=self.basis.order, ind_modes=ind_modes, invvdm=self.basis.ubasis.invvdm.T) # Allocate space for the artificial viscosity vector self.artvisc = self._be.matrix((1, self.neles), extent=nonce + 'artvisc', tags=tags) # Apply the sensor to estimate the required artificial viscosity self.kernels['shocksensor'] = lambda uin: self._be.kernel( 'shocksensor', tplargs=tplargs_artvisc, dims=[self.neles], u=self.scal_upts[uin], artvisc=self.artvisc) elif shock_capturing == 'none': self.artvisc = None else: raise ValueError('Invalid shock capturing scheme')