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 fpts(self): n = self._order + 1 # Tri face points tname = self._cfg.get("solver-interfaces-tri", "flux-pts") ts, tt = get_quadrule("tri", tname, n * (n + 1) // 2).np_points.T # Quad face points qname = self._cfg.get("solver-interfaces-quad", "flux-pts") qs, qt = get_quadrule("quad", qname, n ** 2).np_points.T # Project proj = [(ts, tt, -1), (ts, tt, 1), (qs, -1, qt), (-qs, qs, qt), (-1, qs, qt)] return np.vstack(list(np.broadcast(*p)) for p in proj)
def std_ele(cls, sptord): esqr = get_quadrule(BaseLineQuadRule, 'equi-spaced', sptord + 1) sele = [(p, q) for i, q in enumerate(esqr.points) for p in esqr.points[:(sptord + 1 - i)]] return np.array(sele, dtype=np.object)
def fbasis(self): # Dummy parametric symbol t = sy.Symbol('t') # Dimension variables p, q = self._dims # Orthonormal basis obasis = self._orthonormal_basis(self._order + 1) # Nodal basis along an edge qrule = self._cfg.get('solver-interfaces-line', 'flux-pts') pts1d = get_quadrule(BaseLineQuadRule, qrule, self._order + 1).points nb1d = lagrange_basis(pts1d, t) # Allocate space for the flux point basis fbasis = np.empty((3, len(nb1d)), dtype=np.object) # Parametric mappings (p,q) -> t for the three edges # (bottom, hypot, left) substs = [{p: t, q: -1}, {p: -t, q: t}, {p: -1, q: -t}] for i, esub in enumerate(substs): for j, lj in enumerate(nb1d): fb = sum(sy.integrate(lj*ob.subs(esub), (t, -1, 1))*ob for ob in obasis) fbasis[i,j] = fb # Account for the longer length of the hypotenuse fbasis[1,:] *= mp.sqrt(2) return fbasis.ravel()
def upts(self): qrule = self._cfg.get('solver-elements-tri', 'soln-pts') bupts = get_quadrule(BaseTriQuadRule, qrule, self.nupts).points # Convert to Cartesian stdtri = self.std_ele(1) return np.array([_bary_to_cart(b, stdtri) for b in bupts], dtype=np.object)
def fpts(self): # Flux points for a single face rule = self._cfg.get("solver-elements-hex", "soln-pts") s, t = get_quadrule("quad", rule, self.nfpts // 6).np_points.T # Project proj = [(s, t, -1), (s, -1, t), (1, s, t), (s, 1, t), (-1, s, t), (s, t, 1)] return np.vstack(list(np.broadcast(*p)) for p in proj)
def fpts(self): # 1D points qrule = self._cfg.get("solver-interfaces-line", "flux-pts") pts1d = get_quadrule("line", qrule, self._order + 1).np_points # Project proj = [(pts1d, -1), (-pts1d, pts1d), (-1, pts1d)] return np.vstack(list(np.broadcast(*p)) for p in proj)
def fpts(self): # Flux points along an edge rulename = self._cfg.get("solver-interfaces-line", "flux-pts") pts = np.array(get_quadrule("line", rulename, self.nfpts // 4).points) # Project onto the edges proj = [(pts, -1), (1, pts), (pts, 1), (-1, pts)] return np.vstack(list(np.broadcast(*p)) for p in proj)
def _get_qrule(self, eleint, kind, **kwargs): sect = f'solver-{eleint}-{kind}' if self.cfg.hasopt(sect, 'quad-pts'): kwargs['rule'] = self.cfg.get(sect, 'quad-pts') if self.cfg.hasopt(sect, 'quad-deg'): kwargs['qdeg'] = self.cfg.getint(sect, 'quad-deg') return get_quadrule(kind, **kwargs)
def _get_qrule(self, eleint, kind, **kwargs): sect = 'solver-{0}-{1}'.format(eleint, kind) if self.cfg.hasopt(sect, 'quad-pts'): kwargs['rule'] = self.cfg.get(sect, 'quad-pts') if self.cfg.hasopt(sect, 'quad-deg'): kwargs['qdeg'] = self.cfg.getint(sect, 'quad-deg') return get_quadrule(kind, **kwargs)
def std_ele(cls, sptord): pts1d = get_quadrule("line", "equi-spaced", sptord + 1).points sele = [ (p, q, r) for i, r in enumerate(pts1d) for j, q in enumerate(pts1d[: (sptord + 1 - i)]) for p in pts1d[: (sptord + 1 - i - j)] ] return np.array(sele, dtype=np.object)
def __init__(self, intg, cfgsect, suffix=None): super().__init__(intg, cfgsect, suffix) comm, rank, root = get_comm_rank_root() # Underlying system system = intg.system # Underlying system elements class self.elementscls = system.elementscls # Expressions to integrate c = self.cfg.items_as('constants', float) self.exprs = [ self.cfg.getexpr(cfgsect, k, subs=c) for k in self.cfg.items(cfgsect) if k.startswith('int-') ] # Integration region pre-processing rinfo = self._prepare_region_info(intg) # Gradient pre-processing self._init_gradients(intg, rinfo) # Save a reference to the physical solution point locations self.plocs = system.ele_ploc_upts # Integration parameters self.nsteps = self.cfg.getint(cfgsect, 'nsteps') # The root rank needs to open the output file if rank == root: header = ['t'] + [ k for k in self.cfg.items(cfgsect) if k.startswith('int-') ] # Open self.outf = init_csv(self.cfg, cfgsect, ','.join(header)) # Prepare the per element-type info list self.eleinfo = [] for (ename, eles), (eset, emask) in zip(system.ele_map.items(), rinfo): # Locations of each solution point ploc = eles.ploc_at_np('upts')[..., eset] ploc = ploc.swapaxes(0, 1) # Jacobian determinants rcpdjacs = eles.rcpdjac_at_np('upts')[:, eset] # Quadature weights rname = self.cfg.get(f'solver-elements-{ename}', 'soln-pts') wts = get_quadrule(ename, rname, eles.nupts).wts # Save self.eleinfo.append((ploc, wts[:, None] / rcpdjacs, eset, emask))
def _qrule(self): sect = 'solver-elements-' + self.name kwargs = {'flags': 'sp'} if self.cfg.hasopt(sect, 'quad-pts'): kwargs['rule'] = self.cfg.get(sect, 'quad-pts') if self.cfg.hasopt(sect, 'quad-deg'): kwargs['qdeg'] = self.cfg.getint(sect, 'quad-deg') return get_quadrule(self.name, **kwargs)
def fpts(self): # 2D points on a triangle qrule = self._cfg.get("solver-interfaces-tri", "flux-pts") npts2d = (self._order + 1) * (self._order + 2) // 2 s, t = get_quadrule("tri", qrule, npts2d).np_points.T # Project proj = [(s, t, -1), (s, -1, t), (-1, t, s), (s, t, -s - t - 1)] return np.vstack(list(np.broadcast(*p)) for p in proj)
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 fpts(self): # 1D points qrule = self._cfg.get('solver-interfaces-line', 'flux-pts') pts1d = get_quadrule(BaseLineQuadRule, qrule, self._order + 1).points # Flux points fpts = np.empty((3, self._order + 1, 2), dtype=np.object) fpts[0,:,0], fpts[0,:,1] = pts1d, -1 fpts[1,:,0], fpts[1,:,1] = pts1d[::-1], pts1d fpts[2,:,0], fpts[2,:,1] = -1, pts1d[::-1] return fpts.reshape(-1, 2)
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 fpts_wts(self): pwts = [] for kind, proj, norm in self.faces: # Obtain the weights in reference space for the face type if 'surf-flux' in self.antialias: r = self._iqrules[kind] else: rule = self.cfg.get(f'solver-interfaces-{kind}', 'flux-pts') npts = self.npts_for_face[kind](self.order) r = get_quadrule(kind, rule, npts) pwts.append(r.wts) return np.hstack(pwts)
def fpts_wts(self): pwts = [] for kind, proj, norm, area in self.faces: # Obtain the weights in reference space for the face type if 'surf-flux' in self.antialias: r = self._iqrules[kind] else: rule = self.cfg.get('solver-interfaces-' + kind, 'flux-pts') npts = self.npts_for_face[kind](self.order) r = get_quadrule(kind, rule, npts) pwts.append(r.wts) return np.hstack(pwts)
def fpts(self): ppts = [] for kind, proj, norm in self.faces: # Obtain the flux points in reference space for the face type if 'surf-flux' in self.antialias: r = self._iqrules[kind] else: rule = self.cfg.get(f'solver-interfaces-{kind}', 'flux-pts') npts = self.npts_for_face[kind](self.order) r = get_quadrule(kind, rule, npts) # Project ppts.append(_proj_pts(proj, r.pts)) return np.vstack(ppts)
def fpts(self): rrule, ppts = {}, [] for kind, proj, norm, area in self.faces: # Obtain the flux points in reference space for the face type try: r = rrule[kind] except KeyError: rule = self.cfg.get('solver-interfaces-' + kind, 'flux-pts') npts = self.npts_for_face[kind](self.order) rrule[kind] = r = get_quadrule(kind, rule, npts) # Project ppts.append(_proj_rule_pts(proj, r)) return np.vstack(ppts)
def fpts(self): ppts = [] for kind, proj, norm, area in self.faces: # Obtain the flux points in reference space for the face type if 'surf-flux' in self.antialias: r = self._iqrules[kind] else: rule = self.cfg.get('solver-interfaces-' + kind, 'flux-pts') npts = self.npts_for_face[kind](self.order) r = get_quadrule(kind, rule, npts) # Project ppts.append(_proj_pts(proj, r.pts)) return np.vstack(ppts)
def _search_pts(self, intg): tlocs, plocs = [], [] # Use a strictly interior point set qrule_map = { 'quad': 'gauss-legendre', 'tri': 'williams-shunn', 'hex': 'gauss-legendre', 'pri': 'williams-shunn~gauss-legendre', 'pyr': 'gauss-legendre', 'tet': 'shunn-ham' } for etype, eles in intg.system.ele_map.items(): pts = get_quadrule(etype, qrule_map[etype], eles.basis.nupts).pts tlocs.append(pts) plocs.append(eles.ploc_at_np(pts).swapaxes(1, 2)) return tlocs, plocs
def gbasis_coeffs(self): coeffs = [] # 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 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 qr = get_quadrule(kind, *qrule_map[kind]) L = self.facebases[kind].nodal_basis_at(qr.pts) # Do the quadrature M = self.ubasis.ortho_basis_at(_proj_pts(proj, qr.pts)) S = np.einsum('i...,ik,ji->kj', qr.wts, L, M) coeffs.append(S) return np.vstack(coeffs)
def gbasis_coeffs(self): coeffs = [] # 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 qr = get_quadrule(kind, *qrule_map[kind]) L = self.facebases[kind].nodal_basis_at(qr.pts) # Do the quadrature M = self.ubasis.ortho_basis_at(_proj_pts(proj, qr.pts)) S = np.einsum('i...,ik,ji->kj', area*qr.wts, L, M) coeffs.append(S) return np.vstack(coeffs)
def upts(self): rname = self.cfg.get('solver-elements-' + self.name, 'soln-pts') return get_quadrule(self.name, rname, self.nupts).points
def std_ele(cls, sptord): n = (sptord + 1) ** cls.ndims return get_quadrule(cls.name, "equi-spaced", n).points
def std_ele(cls, sptord): esqr = get_quadrule(BaseLineQuadRule, 'equi-spaced', sptord + 1) return cart_prod_points(esqr.points, cls.ndims)
def _pts1d(self): rule = self._cfg.get('solver-elements-' + self.name, 'soln-pts') return get_quadrule(BaseLineQuadRule, rule, self._order + 1).points
def upts(self): rname = self.cfg.get('solver-elements-' + self.name, 'soln-pts') return get_quadrule(self.name, rname, self.nupts).pts
def spts1d(self): esqr = get_quadrule(BaseLineQuadRule, 'equi-spaced', self._nsptsord) return esqr.points
def __init__(self, intg, cfgsect, suffix=None): super().__init__(intg, cfgsect, suffix) comm, rank, root = get_comm_rank_root() # Underlying system system = intg.system # Underlying system elements class self.elementscls = system.elementscls # Expressions to integrate c = self.cfg.items_as('constants', float) self.exprs = [ self.cfg.getexpr(cfgsect, k, subs=c) for k in self.cfg.items(cfgsect) if k.startswith('int-') ] # Integration region pre-processing rinfo = self._prepare_region_info(intg) # Gradient pre-processing self._init_gradients(intg, rinfo) # Save a reference to the physical solution point locations self.plocs = system.ele_ploc_upts # Integration parameters self.nsteps = self.cfg.getint(cfgsect, 'nsteps') # The root rank needs to open the output file if rank == root: header = ['t'] + [ k for k in self.cfg.items(cfgsect) if k.startswith('int-') ] # Open self.outf = init_csv(self.cfg, cfgsect, ','.join(header)) # Prepare the per element-type info list self.eleinfo = eleinfo = [] for (ename, eles), (eset, emask) in zip(system.ele_map.items(), rinfo): # Obtain quadrature info rname = self.cfg.get(f'solver-elements-{ename}', 'soln-pts') try: # Quadrature rule (default to that of the solution points) qrule = self.cfg.get(cfgsect, f'quad-pts-{ename}', rname) # Quadrature rule degree try: qdeg = self.cfg.getint(cfgsect, f'quad-deg-{ename}') except NoOptionError: qdeg = self.cfg.getint(cfgsect, 'quad-deg') r = get_quadrule(ename, qrule, qdeg=qdeg) # Interpolation to quadrature points matrix m0 = eles.basis.ubasis.nodal_basis_at(r.pts) except NoOptionError: # Default to the quadrature rule of the solution points r = get_quadrule(ename, rname, eles.nupts) m0 = None # Locations of each quadrature point ploc = eles.ploc_at_np(r.pts).swapaxes(0, 1)[..., eset] # Jacobian determinants at each quadrature point rcpdjacs = eles.rcpdjac_at_np(r.pts)[:, eset] # Save eleinfo.append((ploc, r.wts[:, None] / rcpdjacs, m0, eset, emask))
def upts(self): rname = self.cfg.get(f'solver-elements-{self.name}', 'soln-pts') return get_quadrule(self.name, rname, self.nupts).pts