def addKernels(generator, aderdg, matricesDir, PlasticityMethod): # Load matrices db = parseXMLMatrixFile('{}/plasticity_{}_matrices_{}.xml'.format(matricesDir, PlasticityMethod, aderdg.order), clones=dict(), alignStride=aderdg.alignStride) numberOfNodes = db.v.shape()[0] sShape = (aderdg.numberOf3DBasisFunctions(), 6) QStress = OptionalDimTensor('QStress', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), sShape, alignStride=True) initialLoading = Tensor('initialLoading', (6,)) replicateIniLShape = (numberOfNodes,) replicateIniLSpp = np.ones(aderdg.Q.insertOptDim(replicateIniLShape, (aderdg.Q.optSize(),))) replicateInitialLoading = OptionalDimTensor('replicateInitialLoading', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), replicateIniLShape, spp=replicateIniLSpp, alignStride=True) iShape = (numberOfNodes, 6) QStressNodal = OptionalDimTensor('QStressNodal', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), iShape, alignStride=True) meanStress = OptionalDimTensor('meanStress', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOfNodes,), alignStride=True) secondInvariant = OptionalDimTensor('secondInvariant', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOfNodes,), alignStride=True) selectBulkAverage = Tensor('selectBulkAverage', (6,), spp={(i,): str(1.0/3.0) for i in range(3)}) selectBulkNegative = Tensor('selectBulkNegative', (6,), spp={(i,): '-1.0' for i in range(3)}) weightSecondInvariant = Tensor('weightSecondInvariant', (6,), spp={(i,): str(1.0/2.0) if i < 3 else '1.0' for i in range(6)}) yieldFactor = Tensor('yieldFactor', (numberOfNodes,)) generator.add('plConvertToNodal', QStressNodal['kp'] <= db.v['kl'] * QStress['lp'] + replicateInitialLoading['k'] * initialLoading['p']) generator.add('plComputeMean', meanStress['k'] <= QStressNodal['kq'] * selectBulkAverage['q']) generator.add('plSubtractMean', QStressNodal['kp'] <= QStressNodal['kp'] + meanStress['k'] * selectBulkNegative['p']) generator.add('plComputeSecondInvariant', secondInvariant['k'] <= QStressNodal['kq'] * QStressNodal['kq'] * weightSecondInvariant['q']) generator.add('plAdjustStresses', QStress['kp'] <= QStress['kp'] + db.vInv['kl'] * QStressNodal['lp'] * yieldFactor['l'])
def addInit(self, generator): fluxScale = Scalar('fluxScale') computeFluxSolverLocal = self.AplusT['ij'] <= fluxScale * self.Tinv[ 'ki'] * self.QgodLocal['kq'] * self.starMatrix( 0)['ql'] * self.T['jl'] generator.add('computeFluxSolverLocal', computeFluxSolverLocal) computeFluxSolverNeighbor = self.AminusT[ 'ij'] <= fluxScale * self.Tinv['ki'] * self.QgodNeighbor[ 'kq'] * self.starMatrix(0)['ql'] * self.T['jl'] generator.add('computeFluxSolverNeighbor', computeFluxSolverNeighbor) QFortran = Tensor( 'QFortran', (self.numberOf3DBasisFunctions(), self.numberOfQuantities())) multSimToFirstSim = Tensor('multSimToFirstSim', (self.Q.optSize(), ), spp={(0, ): '1.0'}) if self.Q.hasOptDim(): copyQToQFortran = QFortran[ 'kp'] <= self.Q['kp'] * multSimToFirstSim['s'] else: copyQToQFortran = QFortran['kp'] <= self.Q['kp'] generator.add('copyQToQFortran', copyQToQFortran) stiffnessTensor = Tensor('stiffnessTensor', (3, 3, 3, 3)) direction = Tensor('direction', (3, )) christoffel = Tensor('christoffel', (3, 3)) computeChristoffel = christoffel[ 'ik'] <= stiffnessTensor['ijkl'] * direction['j'] * direction['l'] generator.add('computeChristoffel', computeChristoffel)
def addKernels(generator, aderdg): numberOf3DBasisFunctions = aderdg.numberOf3DBasisFunctions() numberOfQuantities = aderdg.numberOfQuantities() ## Point sources mInvJInvPhisAtSources = Tensor('mInvJInvPhisAtSources', (numberOf3DBasisFunctions,)) momentNRF = Tensor('momentNRF', (numberOfQuantities,), spp=np.array([1]*6 + [0]*(numberOfQuantities-6), dtype=bool)) if aderdg.Q.hasOptDim(): sourceNRF = aderdg.Q['kp'] <= aderdg.Q['kp'] - mInvJInvPhisAtSources['k'] * momentNRF['p'] * aderdg.oneSimToMultSim['s'] else: sourceNRF = aderdg.Q['kp'] <= aderdg.Q['kp'] - mInvJInvPhisAtSources['k'] * momentNRF['p'] generator.add('sourceNRF', sourceNRF) momentFSRM = Tensor('momentFSRM', (numberOfQuantities,)) stfIntegral = Scalar('stfIntegral') if aderdg.Q.hasOptDim(): sourceFSRM = aderdg.Q['kp'] <= aderdg.Q['kp'] + stfIntegral * mInvJInvPhisAtSources['k'] * momentFSRM['p'] * aderdg.oneSimToMultSim['s'] else: sourceFSRM = aderdg.Q['kp'] <= aderdg.Q['kp'] + stfIntegral * mInvJInvPhisAtSources['k'] * momentFSRM['p'] generator.add('sourceFSRM', sourceFSRM) ## Receiver output basisFunctionsAtPoint = Tensor('basisFunctions', (numberOf3DBasisFunctions,)) QAtPoint = OptionalDimTensor('QAtPoint', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOfQuantities,)) evaluateDOFSAtPoint = QAtPoint['p'] <= aderdg.Q['kp'] * basisFunctionsAtPoint['k'] generator.add('evaluateDOFSAtPoint', evaluateDOFSAtPoint)
def addKernels(generator, aderdg, include_tensors, matricesDir, dynamicRuptureMethod): easi_ident_map = np.stack([np.eye(aderdg.numberOfQuantities())] * aderdg.numberOf2DBasisFunctions(), axis=2) assert(easi_ident_map.shape == (aderdg.numberOfQuantities(), aderdg.numberOfQuantities(), aderdg.numberOf2DBasisFunctions())) easi_ident_map = Tensor('easiIdentMap', easi_ident_map.shape, easi_ident_map, alignStride=False) easi_boundary_constant = Tensor('easiBoundaryConstant', (aderdg.numberOfQuantities(), aderdg.numberOf2DBasisFunctions()), alignStride=False) easi_boundary_map = Tensor('easiBoundaryMap', (aderdg.numberOfQuantities(), aderdg.numberOfQuantities(), aderdg.numberOf2DBasisFunctions(),), alignStride=False) create_easi_boundary_ghost_cells = ( aderdg.INodal['la'] <= easi_boundary_map['abl'] * aderdg.INodal['lb'] + easi_ident_map['abl'] * easi_boundary_constant['bl'] ) generator.add('createEasiBoundaryGhostCells', create_easi_boundary_ghost_cells) projectToNodalBoundary = lambda j: aderdg.INodal['kp'] <= aderdg.db.V3mTo2nFace[j]['km'] * aderdg.I['mp'] generator.addFamily('projectToNodalBoundary', simpleParameterSpace(4), projectToNodalBoundary) projectToNodalBoundaryRotated = lambda j: aderdg.INodal['kp'] <= aderdg.db.V3mTo2nFace[j]['kl'] \ * aderdg.I['lm'] \ * aderdg.Tinv['pm'] generator.addFamily('projectToNodalBoundaryRotated', simpleParameterSpace(4), projectToNodalBoundaryRotated) # To be used as Tinv in flux solver - this way we can save two rotations for # Dirichlet boundary, as ghost cell dofs are already rotated identity_rotation = np.double(aderdg.transformation_spp()) identity_rotation[0:9, 0:9] = np.eye(9) identity_rotation = Tensor('identityT', aderdg.transformation_spp().shape, identity_rotation, ) include_tensors.add(identity_rotation) aderdg.INodalUpdate = OptionalDimTensor('INodalUpdate', aderdg.INodal.optName(), aderdg.INodal.optSize(), aderdg.INodal.optPos(), (aderdg.numberOf2DBasisFunctions(), aderdg.numberOfQuantities()), alignStride=True) factor = Scalar('factor') updateINodal = aderdg.INodal['kp'] <= aderdg.INodal['kp'] + factor * aderdg.INodalUpdate['kp'] generator.add('updateINodal', updateINodal)
def addInit(self, generator): super().addInit(generator) selectElaFullSpp = np.zeros( (self.numberOfFullQuantities(), self.numberOfQuantities())) selectElaFullSpp[0:self.numberOfQuantities(), 0:self.numberOfQuantities()] = np.eye( self.numberOfQuantities()) selectElaFull = Tensor( 'selectElaFull', (self.numberOfFullQuantities(), self.numberOfQuantities()), selectElaFullSpp, CSCMemoryLayout) selectAneFullSpp = np.zeros( (self.numberOfFullQuantities(), self.numberOfAnelasticQuantities(), self.numberOfMechanisms)) for mech in range(self.numberOfMechanisms): q1 = self.numberOfQuantities( ) + mech * self.numberOfAnelasticQuantities() q2 = q1 + self.numberOfAnelasticQuantities() selectAneFullSpp[q1:q2, :, mech] = np.eye(self.numberOfAnelasticQuantities()) selectAneFull = Tensor( 'selectAneFull', (self.numberOfFullQuantities(), self.numberOfAnelasticQuantities(), self.numberOfMechanisms), selectAneFullSpp) iniShape = (self.numberOf3DQuadraturePoints(), self.numberOfFullQuantities()) iniCond = OptionalDimTensor('iniCond', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), iniShape, alignStride=True) dofsShape = (self.numberOf3DQuadraturePoints(), self.numberOfQuantities()) dofsQP = OptionalDimTensor('dofsQP', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), dofsShape, alignStride=True) projectIniCondEla = self.Q['kp'] <= self.db.projectQP[self.t( 'kl')] * iniCond['lq'] * selectElaFull['qp'] projectIniCondAne = self.Qane['kpm'] <= self.db.projectQP[self.t( 'kl')] * iniCond['lq'] * selectAneFull['qpm'] generator.add('projectIniCond', [projectIniCondEla, projectIniCondAne]) generator.add( 'evalAtQP', dofsQP['kp'] <= self.db.evalAtQP[self.t('kl')] * self.Q['lp'])
def kSub(d, n): Bn_1, Bn = modeRange(n) stiffnessSpp = np.zeros(fullShape) stiffnessSpp[:, Bn_1:Bn] = -stiffnessValues[d][:, Bn_1:Bn] return Tensor('kDivMTSub({},{})'.format(d, n), fullShape, spp=stiffnessSpp)
def selectQuantity(quantityNumber): selectSpp = np.zeros( (self.numberOfQuantities(), self.numberOfQuantities())) selectSpp[quantityNumber, quantityNumber] = 1 return Tensor('selectQuantity({})'.format(quantityNumber), selectSpp.shape, spp=selectSpp)
def selectModes(n): Bn_1, Bn = modeRange(n) selectModesSpp = np.zeros(fullShape) selectModesSpp[Bn_1:Bn, Bn_1:Bn] = np.eye(Bn - Bn_1) return Tensor('selectModes({})'.format(n), fullShape, spp=selectModesSpp)
def selectQuantityG(quantityNumber): selectSpp = np.zeros( (self.numberOfQuantities(), self.numberOfQuantities())) #The source matrix G only contains values at (o-4, o) selectSpp[quantityNumber - 4, quantityNumber] = 1 return Tensor('selectQuantityG({})'.format(quantityNumber), selectSpp.shape, spp=selectSpp)
def __init__(self, order, multipleSimulations, matricesDir, memLayout, numberOfMechanisms, **kwargs): self.numberOfMechanisms = numberOfMechanisms self.numberOfElasticQuantities = 9 super().__init__(order, multipleSimulations, matricesDir) clones = { 'star': ['star(0)', 'star(1)', 'star(2)'], } self.db.update( parseXMLMatrixFile( '{}/matrices_viscoelastic.xml'.format(matricesDir), clones)) star_spp = self.db.star[0].spp().as_ndarray() star_rows, star_cols = star_spp.shape aniso_cols = star_cols - self.numberOfElasticQuantities star_spp_new = np.zeros( (self.numberOfQuantities(), self.numberOfQuantities()), dtype=bool) star_spp_new[0:star_rows, 0:star_cols] = star_spp ''' The last 6 columns of star_spp contain the prototype sparsity pattern for a mechanism. Therefore, the spp is repeated for every mechanism. ''' for mech in range(1, numberOfMechanisms): offset0 = self.numberOfElasticQuantities offsetm = self.numberOfElasticQuantities + mech * aniso_cols star_spp_new[0:star_rows, offsetm:offsetm + aniso_cols] = star_spp[0:star_rows, offset0:offset0 + aniso_cols] for dim in range(3): self.db.star[dim] = Tensor(self.db.star[dim].name(), star_spp_new.shape, spp=star_spp_new) source_spp = np.zeros( (self.numberOfQuantities(), self.numberOfQuantities()), dtype=bool) ET_spp = self.db['ET'].spp().as_ndarray() ''' ET is a prototype sparsity pattern for a mechanism. Therefore, repeated for every mechanism. See Kaeser and Dumbser 2006, III. Viscoelastic attenuation. ''' for mech in range(numberOfMechanisms): offset = self.numberOfElasticQuantities + mech * aniso_cols r = slice(offset, offset + aniso_cols) source_spp[r, 0:aniso_cols] = ET_spp source_spp[r, r] = np.identity(aniso_cols, dtype=bool) self.db.ET = Tensor('ET', source_spp.shape, spp=source_spp) memoryLayoutFromFile(memLayout, self.db, clones)
def __init__(self, order, multipleSimulations, matricesDir): self.order = order self.alignStride = lambda name: True if multipleSimulations > 1: self.alignStride = lambda name: name.startswith('fP') transpose = multipleSimulations > 1 self.transpose = lambda name: transpose self.t = (lambda x: x[::-1]) if transpose else (lambda x: x) self.db = parseXMLMatrixFile('{}/matrices_{}.xml'.format( matricesDir, self.numberOf3DBasisFunctions()), transpose=self.transpose, alignStride=self.alignStride) clonesQP = {'v': ['evalAtQP'], 'vInv': ['projectQP']} self.db.update( parseXMLMatrixFile('{}/plasticity_ip_matrices_{}.xml'.format( matricesDir, order), clonesQP, transpose=self.transpose, alignStride=self.alignStride)) qShape = (self.numberOf3DBasisFunctions(), self.numberOfQuantities()) self.Q = OptionalDimTensor('Q', 's', multipleSimulations, 0, qShape, alignStride=True) self.I = OptionalDimTensor('I', 's', multipleSimulations, 0, qShape, alignStride=True) Aplusminus_spp = self.flux_solver_spp() self.AplusT = Tensor('AplusT', Aplusminus_spp.shape, spp=Aplusminus_spp) self.AminusT = Tensor('AminusT', Aplusminus_spp.shape, spp=Aplusminus_spp) Tshape = (self.numberOfExtendedQuantities(), self.numberOfExtendedQuantities()) trans_spp = self.transformation_spp() self.T = Tensor('T', trans_spp.shape, spp=trans_spp) trans_inv_spp = self.transformation_inv_spp() self.Tinv = Tensor('Tinv', trans_inv_spp.shape, spp=trans_inv_spp) godunov_spp = self.godunov_spp() self.QgodLocal = Tensor('QgodLocal', godunov_spp.shape, spp=godunov_spp) self.QgodNeighbor = Tensor('QgodNeighbor', godunov_spp.shape, spp=godunov_spp) self.oneSimToMultSim = Tensor('oneSimToMultSim', (self.Q.optSize(), ), spp={(i, ): '1.0' for i in range(self.Q.optSize())})
def addKernels(generator, aderdg): maxDepth = 3 numberOf3DBasisFunctions = aderdg.numberOf3DBasisFunctions() numberOfQuantities = aderdg.numberOfQuantities() selectVelocitySpp = np.zeros((numberOfQuantities, 3)) selectVelocitySpp[6:9, 0:3] = np.eye(3) selectVelocity = Tensor('selectVelocity', selectVelocitySpp.shape, selectVelocitySpp, CSCMemoryLayout) displacement = OptionalDimTensor('displacement', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOf3DBasisFunctions, 3), alignStride=True) generator.add( 'addVelocity', displacement['kp'] <= displacement['kp'] + aderdg.I['kq'] * selectVelocity['qp']) subTriangleDofs = [ OptionalDimTensor('subTriangleDofs({})'.format(depth), aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (4**depth, 3), alignStride=True) for depth in range(maxDepth + 1) ] subTriangleProjection = [ Tensor('subTriangleProjection({})'.format(depth), (4**depth, numberOf3DBasisFunctions), alignStride=True) for depth in range(maxDepth + 1) ] subTriangleDisplacement = lambda depth: subTriangleDofs[depth][ 'kp'] <= subTriangleProjection[depth]['kl'] * displacement['lp'] subTriangleVelocity = lambda depth: subTriangleDofs[depth][ 'kp'] <= subTriangleProjection[depth]['kl'] * aderdg.Q[ 'lq'] * selectVelocity['qp'] generator.addFamily('subTriangleDisplacement', simpleParameterSpace(maxDepth + 1), subTriangleDisplacement) generator.addFamily('subTriangleVelocity', simpleParameterSpace(maxDepth + 1), subTriangleVelocity)
def addKernels(generator, aderdg): numberOf3DBasisFunctions = aderdg.numberOf3DBasisFunctions() numberOfQuantities = aderdg.numberOfQuantities() ## Point sources mStiffnessTensor = Tensor('stiffnessTensor', (3, 3, 3, 3)) mSlip = Tensor('mSlip', (3, )) mNormal = Tensor('mNormal', (3, )) mArea = Scalar('mArea') basisFunctionsAtPoint = Tensor('basisFunctionsAtPoint', (numberOf3DBasisFunctions, )) mInvJInvPhisAtSources = Tensor('mInvJInvPhisAtSources', (numberOf3DBasisFunctions, )) JInv = Scalar('JInv') generator.add( 'computeMInvJInvPhisAtSources', mInvJInvPhisAtSources['k'] <= JInv * aderdg.db.M3inv['kl'] * basisFunctionsAtPoint['l']) #extract the moment tensors entries in SeisSol ordering (xx, yy, zz, xy, yz, xz) assert (numberOfQuantities >= 6) momentToNRF_spp = np.zeros((numberOfQuantities, 3, 3)) momentToNRF_spp[0, 0, 0] = 1 momentToNRF_spp[1, 1, 1] = 1 momentToNRF_spp[2, 2, 2] = 1 momentToNRF_spp[3, 0, 1] = 1 momentToNRF_spp[4, 1, 2] = 1 momentToNRF_spp[5, 0, 2] = 1 momentToNRF = Tensor('momentToNRF', (numberOfQuantities, 3, 3), spp=momentToNRF_spp) momentNRFKernel = momentToNRF['tpq'] * mArea * mStiffnessTensor[ 'pqij'] * mSlip['i'] * mNormal['j'] if aderdg.Q.hasOptDim(): sourceNRF = aderdg.Q['kt'] <= aderdg.Q['kt'] + mInvJInvPhisAtSources[ 'k'] * momentNRFKernel * aderdg.oneSimToMultSim['s'] else: sourceNRF = aderdg.Q['kt'] <= aderdg.Q[ 'kt'] + mInvJInvPhisAtSources['k'] * momentNRFKernel generator.add('sourceNRF', sourceNRF) momentFSRM = Tensor('momentFSRM', (numberOfQuantities, )) stfIntegral = Scalar('stfIntegral') if aderdg.Q.hasOptDim(): sourceFSRM = aderdg.Q[ 'kp'] <= aderdg.Q['kp'] + stfIntegral * mInvJInvPhisAtSources[ 'k'] * momentFSRM['p'] * aderdg.oneSimToMultSim['s'] else: sourceFSRM = aderdg.Q['kp'] <= aderdg.Q[ 'kp'] + stfIntegral * mInvJInvPhisAtSources['k'] * momentFSRM['p'] generator.add('sourceFSRM', sourceFSRM) ## Receiver output QAtPoint = OptionalDimTensor('QAtPoint', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOfQuantities, )) evaluateDOFSAtPoint = QAtPoint[ 'p'] <= aderdg.Q['kp'] * basisFunctionsAtPoint['k'] generator.add('evaluateDOFSAtPoint', evaluateDOFSAtPoint)
def addKernels(generator, aderdg, matricesDir, dynamicRuptureMethod): if dynamicRuptureMethod == 'quadrature': numberOfPoints = (aderdg.order+1)**2 elif dynamicRuptureMethod == 'cellaverage': numberOfPoints = int(4**math.ceil(math.log(aderdg.order*(aderdg.order+1)/2,4))) else: raise ValueError('Unknown dynamic rupture method.') clones = dict() # Load matrices db = parseJSONMatrixFile('{}/dr_{}_matrices_{}.json'.format(matricesDir, dynamicRuptureMethod, aderdg.order), clones, alignStride=aderdg.alignStride, transpose=aderdg.transpose) # Determine matrices # Note: This does only work because the flux does not depend on the mechanisms in the case of viscoelastic attenuation godShape = (aderdg.numberOfQuantities(), aderdg.numberOfQuantities()) godunovMatrix = Tensor('godunovMatrix', godShape) fluxSolverShape = (aderdg.numberOfQuantities(), aderdg.numberOfExtendedQuantities()) fluxSolver = Tensor('fluxSolver', fluxSolverShape) gShape = (numberOfPoints, aderdg.numberOfQuantities()) godunovState = OptionalDimTensor('godunovState', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), gShape, alignStride=True) generator.add('rotateGodunovStateLocal', godunovMatrix['qp'] <= aderdg.Tinv['kq'] * aderdg.QgodLocal['kp']) generator.add('rotateGodunovStateNeighbor', godunovMatrix['qp'] <= aderdg.Tinv['kq'] * aderdg.QgodNeighbor['kp']) fluxScale = Scalar('fluxScale') generator.add('rotateFluxMatrix', fluxSolver['qp'] <= fluxScale * aderdg.starMatrix(0)['qk'] * aderdg.T['pk']) def godunovStateGenerator(i,h): target = godunovState['kp'] term = db.V3mTo2n[i,h][aderdg.t('kl')] * aderdg.Q['lq'] * godunovMatrix['qp'] if h == 0: return target <= term return target <= target + term godunovStatePrefetch = lambda i,h: godunovState generator.addFamily('godunovState', simpleParameterSpace(4,4), godunovStateGenerator, godunovStatePrefetch) nodalFluxGenerator = lambda i,h: aderdg.extendedQTensor()['kp'] <= aderdg.extendedQTensor()['kp'] + db.V3mTo2nTWDivM[i,h][aderdg.t('kl')] * godunovState['lq'] * fluxSolver['qp'] nodalFluxPrefetch = lambda i,h: aderdg.I generator.addFamily('nodalFlux', simpleParameterSpace(4,4), nodalFluxGenerator, nodalFluxPrefetch)
def __init__(self, order, multipleSimulations, matricesDir, memLayout, numberOfMechanisms, **kwargs): super().__init__(order, multipleSimulations, matricesDir) self.numberOfMechanisms = numberOfMechanisms clones = { 'star': ['star(0)', 'star(1)', 'star(2)'], } self.db.update( parseXMLMatrixFile('{}/matrices_viscoelastic.xml'.format(matricesDir), clones) ) memoryLayoutFromFile(memLayout, self.db, clones) self._qShapeExtended = (self.numberOf3DBasisFunctions(), self.numberOfExtendedQuantities()) self._qShapeAnelastic = (self.numberOf3DBasisFunctions(), self.numberOfAnelasticQuantities(), self.numberOfMechanisms) self.Qext = OptionalDimTensor('Qext', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), self._qShapeExtended, alignStride=True) self.Qane = OptionalDimTensor('Qane', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), self._qShapeAnelastic, alignStride=True) self.Iane = OptionalDimTensor('Iane', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), self._qShapeAnelastic, alignStride=True) self.E = Tensor('E', (self.numberOfAnelasticQuantities(), self.numberOfMechanisms, self.numberOfQuantities())) self.w = Tensor('w', (self.numberOfMechanisms,)) self.W = Tensor('W', (self.numberOfMechanisms, self.numberOfMechanisms), np.eye(self.numberOfMechanisms, dtype=bool), CSCMemoryLayout) selectElaSpp = np.zeros((self.numberOfExtendedQuantities(), self.numberOfQuantities())) selectElaSpp[0:self.numberOfQuantities(),0:self.numberOfQuantities()] = np.eye(self.numberOfQuantities()) self.selectEla = Tensor('selectEla', (self.numberOfExtendedQuantities(), self.numberOfQuantities()), selectElaSpp, CSCMemoryLayout) selectAneSpp = np.zeros((self.numberOfExtendedQuantities(), self.numberOfAnelasticQuantities())) selectAneSpp[self.numberOfQuantities():self.numberOfExtendedQuantities(),0:self.numberOfAnelasticQuantities()] = np.eye(self.numberOfAnelasticQuantities()) self.selectAne = Tensor('selectAne', (self.numberOfExtendedQuantities(), self.numberOfAnelasticQuantities()), selectAneSpp, CSCMemoryLayout) self.db.update( parseJSONMatrixFile('{}/nodal/nodalBoundary_matrices_{}.json'.format(matricesDir, self.order), {}, alignStride=self.alignStride, transpose=self.transpose, namespace='nodal') )
def addKernels(generator, aderdg, matricesDir, dynamicRuptureMethod): if dynamicRuptureMethod == 'quadrature': numberOfPoints = (aderdg.order + 1)**2 elif dynamicRuptureMethod == 'cellaverage': numberOfPoints = int(4**math.ceil( math.log(aderdg.order * (aderdg.order + 1) / 2, 4))) else: raise ValueError('Unknown dynamic rupture method.') clones = dict() # Load matrices db = parseJSONMatrixFile('{}/dr_{}_matrices_{}.json'.format( matricesDir, dynamicRuptureMethod, aderdg.order), clones, alignStride=aderdg.alignStride, transpose=aderdg.transpose) db.update( parseJSONMatrixFile('{}/resample_{}.json'.format( matricesDir, aderdg.order))) # Determine matrices # Note: This does only work because the flux does not depend on the mechanisms in the case of viscoelastic attenuation trans_inv_spp_T = aderdg.transformation_inv_spp().transpose() TinvT = Tensor('TinvT', trans_inv_spp_T.shape, spp=trans_inv_spp_T) flux_solver_spp = aderdg.flux_solver_spp() fluxSolver = Tensor('fluxSolver', flux_solver_spp.shape, spp=flux_solver_spp) gShape = (numberOfPoints, aderdg.numberOfQuantities()) QInterpolated = OptionalDimTensor('QInterpolated', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), gShape, alignStride=True) generator.add('transposeTinv', TinvT['ij'] <= aderdg.Tinv['ji']) fluxScale = Scalar('fluxScale') generator.add( 'rotateFluxMatrix', fluxSolver['qp'] <= fluxScale * aderdg.starMatrix(0)['qk'] * aderdg.T['pk']) def interpolateQGenerator(i, h): return QInterpolated['kp'] <= db.V3mTo2n[i, h][aderdg.t( 'kl')] * aderdg.Q['lq'] * TinvT['qp'] interpolateQPrefetch = lambda i, h: QInterpolated generator.addFamily('evaluateAndRotateQAtInterpolationPoints', simpleParameterSpace(4, 4), interpolateQGenerator, interpolateQPrefetch) nodalFluxGenerator = lambda i, h: aderdg.extendedQTensor()[ 'kp'] <= aderdg.extendedQTensor()['kp'] + db.V3mTo2nTWDivM[i, h][ aderdg.t('kl')] * QInterpolated['lq'] * fluxSolver['qp'] nodalFluxPrefetch = lambda i, h: aderdg.I generator.addFamily('nodalFlux', simpleParameterSpace(4, 4), nodalFluxGenerator, nodalFluxPrefetch) return {db.resample}
def Zinv(o): return Tensor('Zinv({})'.format(o), (self.order, self.order))
def __init__(self, order, multipleSimulations, matricesDir): self.order = order self.alignStride = lambda name: True if multipleSimulations > 1: self.alignStride = lambda name: name.startswith('fP') transpose = multipleSimulations > 1 self.transpose = lambda name: transpose self.t = (lambda x: x[::-1]) if transpose else (lambda x: x) self.db = parseXMLMatrixFile('{}/matrices_{}.xml'.format( matricesDir, self.numberOf3DBasisFunctions()), transpose=self.transpose, alignStride=self.alignStride) clonesQP = {'v': ['evalAtQP'], 'vInv': ['projectQP']} self.db.update( parseXMLMatrixFile('{}/plasticity_ip_matrices_{}.xml'.format( matricesDir, order), clonesQP, transpose=self.transpose, alignStride=self.alignStride)) self.db.update( parseJSONMatrixFile( '{}/sampling_directions.json'.format(matricesDir))) self.db.update( parseJSONMatrixFile('{}/mass_{}.json'.format(matricesDir, order))) qShape = (self.numberOf3DBasisFunctions(), self.numberOfQuantities()) self.Q = OptionalDimTensor('Q', 's', multipleSimulations, 0, qShape, alignStride=True) self.I = OptionalDimTensor('I', 's', multipleSimulations, 0, qShape, alignStride=True) Aplusminus_spp = self.flux_solver_spp() self.AplusT = Tensor('AplusT', Aplusminus_spp.shape, spp=Aplusminus_spp) self.AminusT = Tensor('AminusT', Aplusminus_spp.shape, spp=Aplusminus_spp) Tshape = (self.numberOfExtendedQuantities(), self.numberOfExtendedQuantities()) trans_spp = self.transformation_spp() self.T = Tensor('T', trans_spp.shape, spp=trans_spp) trans_inv_spp = self.transformation_inv_spp() self.Tinv = Tensor('Tinv', trans_inv_spp.shape, spp=trans_inv_spp) godunov_spp = self.godunov_spp() self.QgodLocal = Tensor('QgodLocal', godunov_spp.shape, spp=godunov_spp) self.QgodNeighbor = Tensor('QgodNeighbor', godunov_spp.shape, spp=godunov_spp) self.oneSimToMultSim = Tensor('oneSimToMultSim', (self.Q.optSize(), ), spp={(i, ): '1.0' for i in range(self.Q.optSize())}) self.db.update( parseJSONMatrixFile( '{}/nodal/nodalBoundary_matrices_{}.json'.format( matricesDir, self.order), {}, alignStride=self.alignStride, transpose=self.transpose, namespace='nodal')) self.INodal = OptionalDimTensor( 'INodal', 's', False, #multipleSimulations, 0, (self.numberOf2DBasisFunctions(), self.numberOfQuantities()), alignStride=True) project2nFaceTo3m = tensor_collection_from_constant_expression( base_name='project2nFaceTo3m', expressions=lambda i: self.db.rDivM[i]['jk'] * self.db.V2nTo2m['kl' ], group_indices=range(4), target_indices='jl') self.db.update(project2nFaceTo3m)
def addTime(self, generator, targets): super().addTime(generator, targets) stiffnessValues = [ self.db.kDivMT[d].values_as_ndarray() for d in range(3) ] fullShape = (self.numberOf3DBasisFunctions(), self.numberOf3DBasisFunctions()) qShape = (self.numberOf3DBasisFunctions(), self.numberOfQuantities()) stpShape = (self.numberOf3DBasisFunctions(), self.numberOfQuantities(), self.order) quantityShape = (self.numberOfQuantities(), self.numberOfQuantities()) spaceTimePredictorRhs = OptionalDimTensor('spaceTimePredictorRhs', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), stpShape, alignStride=True) spaceTimePredictor = OptionalDimTensor('spaceTimePredictor', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), stpShape, alignStride=True) testRhs = OptionalDimTensor('testRhs', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), stpShape, alignStride=True) testLhs = OptionalDimTensor('testLhs', self.Q.optName(), self.Q.optSize(), self.Q.optPos(), stpShape, alignStride=True) timestep = Scalar('timestep') G = {10: Scalar('Gk'), 11: Scalar('Gl'), 12: Scalar('Gm')} ## Compute the index range for basis functions of a certain degree # # The basis functions are ordered with increasing degree, i.e. the first # basis function has degree 0, the next three basis functions have degree # 1, the next six basis functions have degree 2 and so forth. # This method computes the indices Bn_lower, Bn_upper, such that # forall Bn_lower =< i < Bn_upper: degree(phi_i) == n # # @param n The desired polynomial degree def modeRange(n): Bn_lower = choose(n - 1 + 3, 3) Bn_upper = choose(n + 3, 3) return (Bn_lower, Bn_upper) ## Compute a matrix, which filters out all basis function of degree n # # Compute a matrix M, such that for any DOF vector Q, M*Q only contains # the parts of Q, which correspond to basis functions of degree n # # @param n The desired polynomial degree def selectModes(n): Bn_1, Bn = modeRange(n) selectModesSpp = np.zeros(fullShape) selectModesSpp[Bn_1:Bn, Bn_1:Bn] = np.eye(Bn - Bn_1) return Tensor('selectModes({})'.format(n), fullShape, spp=selectModesSpp) ## Compute a matrix, which slices out one quantity # # @param quantityNumber The number of the quantity, which is sliced out def selectQuantity(quantityNumber): selectSpp = np.zeros( (self.numberOfQuantities(), self.numberOfQuantities())) selectSpp[quantityNumber, quantityNumber] = 1 return Tensor('selectQuantity({})'.format(quantityNumber), selectSpp.shape, spp=selectSpp) ## Compute a matrix, which slides out one quantity from the upper triangular # part of the source matrix # # Note: G = E - diag(E) # # @param quantityNumber The number of the quantity, which is sliced out def selectQuantityG(quantityNumber): selectSpp = np.zeros( (self.numberOfQuantities(), self.numberOfQuantities())) #The source matrix G only contains values at (o-4, o) selectSpp[quantityNumber - 4, quantityNumber] = 1 return Tensor('selectQuantityG({})'.format(quantityNumber), selectSpp.shape, spp=selectSpp) ## Zinv(o) = $(Z - E^*_{oo} * I)^{-1}$ # # @param o Index as described above def Zinv(o): return Tensor('Zinv({})'.format(o), (self.order, self.order)) ## Submatrix of the stiffness matrix # # The stiffness matrix for derivatives in direction d, where only the # contribution from basis functions of degree n is considered # # @param d The direction in which derivatives are taken 0 =< d < 3 # @param n The polynomial degree n, which is taken into account def kSub(d, n): Bn_1, Bn = modeRange(n) stiffnessSpp = np.zeros(fullShape) stiffnessSpp[:, Bn_1:Bn] = -stiffnessValues[d][:, Bn_1:Bn] return Tensor('kDivMTSub({},{})'.format(d, n), fullShape, spp=stiffnessSpp) kernels = list() kernels.append( spaceTimePredictorRhs['kpt'] <= self.Q['kp'] * self.db.wHat['t']) for n in range(self.order - 1, -1, -1): for o in range(self.numberOfQuantities() - 1, -1, -1): kernels.append( spaceTimePredictor['kpt'] <= spaceTimePredictor['kpt'] + selectModes(n)['kl'] * selectQuantity(o)['pq'] * spaceTimePredictorRhs['lqu'] * Zinv(o)['ut']) #G only has one relevant non-zero entry in each iteration, so we make it a scalar #G[o] = E[o-4, o] * timestep #In addition E only has non-zero entries, if o > 10 if o >= 10: kernels.append( spaceTimePredictorRhs['kpt'] <= spaceTimePredictorRhs['kpt'] + G[o] * selectQuantityG(o)['pv'] * selectQuantity(o)['vq'] * selectModes(n)['kl'] * spaceTimePredictor['lqt']) if n > 0: derivativeSum = spaceTimePredictorRhs['kpt'] for d in range(3): derivativeSum += kSub(d, n)['kl'] * spaceTimePredictor[ 'lqt'] * self.starMatrix(d)['qp'] kernels.append(spaceTimePredictorRhs['kpt'] <= derivativeSum) kernels.append(self.I['kp'] <= timestep * spaceTimePredictor['kpt'] * self.db.timeInt['t']) generator.add('spaceTimePredictor', kernels) # Test to see if the kernel actually solves the system of equations # This part is not used in the time kernel, but for unit testing deltaSppLarge = np.eye(self.numberOfQuantities()) deltaLarge = Tensor('deltaLarge', deltaSppLarge.shape, spp=deltaSppLarge) deltaSppSmall = np.eye(self.order) deltaSmall = Tensor('deltaSmall', deltaSppSmall.shape, spp=deltaSppSmall) minus = Scalar('minus') lhs = deltaLarge['oq'] * self.db.Z['uk'] * spaceTimePredictor['lqk'] lhs += minus * self.sourceMatrix( )['qo'] * deltaSmall['uk'] * spaceTimePredictor['lqk'] generator.add('stpTestLhs', testLhs['lou'] <= lhs) rhs = self.Q['lo'] * self.db.wHat['u'] for d in range(3): rhs += minus * self.starMatrix( d)['qo'] * self.db.kDivMT[d]['lm'] * spaceTimePredictor['mqu'] generator.add('stpTestRhs', testRhs['lou'] <= rhs)
def addKernels(generator, aderdg, matricesDir, PlasticityMethod, targets): # Load matrices db = parseXMLMatrixFile('{}/plasticity_{}_matrices_{}.xml'.format( matricesDir, PlasticityMethod, aderdg.order), clones=dict(), alignStride=aderdg.alignStride) numberOfNodes = aderdg.t(db.v.shape())[0] numberOf3DBasisFunctions = aderdg.numberOf3DBasisFunctions() sShape = (numberOf3DBasisFunctions, 6) QStress = OptionalDimTensor('QStress', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), sShape, alignStride=True) sShape_eta = (numberOf3DBasisFunctions, ) QEtaModal = OptionalDimTensor('QEtaModal', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), sShape_eta, alignStride=True) initialLoading = Tensor('initialLoading', (6, )) replicateIniLShape = (numberOfNodes, ) replicateIniLSpp = np.ones( aderdg.Q.insertOptDim(replicateIniLShape, (aderdg.Q.optSize(), ))) replicateInitialLoading = OptionalDimTensor('replicateInitialLoading', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), replicateIniLShape, spp=replicateIniLSpp, alignStride=True) iShape = (numberOfNodes, 6) QStressNodal = OptionalDimTensor('QStressNodal', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), iShape, alignStride=True) meanStress = OptionalDimTensor('meanStress', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOfNodes, ), alignStride=True) secondInvariant = OptionalDimTensor('secondInvariant', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOfNodes, ), alignStride=True) QEtaNodal = OptionalDimTensor('QEtaNodal', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOfNodes, ), alignStride=True) selectBulkAverage = Tensor('selectBulkAverage', (6, ), spp={(i, ): str(1.0 / 3.0) for i in range(3)}) selectBulkNegative = Tensor('selectBulkNegative', (6, ), spp={(i, ): '-1.0' for i in range(3)}) weightSecondInvariant = Tensor('weightSecondInvariant', (6, ), spp={(i, ): str(1.0 / 2.0) if i < 3 else '1.0' for i in range(6)}) yieldFactor = Tensor('yieldFactor', (numberOfNodes, )) generator.add( 'plConvertToNodal', QStressNodal['kp'] <= db.v[aderdg.t('kl')] * QStress['lp'] + replicateInitialLoading['k'] * initialLoading['p']) for target in targets: name_prefix = generate_kernel_name_prefix(target) generator.add( name=f'{name_prefix}plConvertToNodalNoLoading', ast=QStressNodal['kp'] <= db.v[aderdg.t('kl')] * QStress['lp'], target=target) generator.add( name=f'{name_prefix}plConvertEtaModal2Nodal', ast=QEtaNodal['k'] <= db.v[aderdg.t('kl')] * QEtaModal['l'], target=target) generator.add( name=f'{name_prefix}plConvertEtaNodal2Modal', ast=QEtaModal['k'] <= db.vInv[aderdg.t('kl')] * QEtaNodal['l'], target=target) generator.add( 'plComputeMean', meanStress['k'] <= QStressNodal['kq'] * selectBulkAverage['q']) generator.add( 'plSubtractMean', QStressNodal['kp'] <= QStressNodal['kp'] + meanStress['k'] * selectBulkNegative['p']) generator.add( 'plComputeSecondInvariant', secondInvariant['k'] <= QStressNodal['kq'] * QStressNodal['kq'] * weightSecondInvariant['q']) generator.add( 'plAdjustStresses', QStress['kp'] <= QStress['kp'] + db.vInv[aderdg.t('kl')] * QStressNodal['lp'] * yieldFactor['l']) gpu_target = 'gpu' if gpu_target in targets: name_prefix = generate_kernel_name_prefix(gpu_target) # suffix `M` stands for `Matrix` replicateInitialLoadingM = Tensor(name='replicateInitialLoadingM', shape=(numberOfNodes, 1), spp=np.ones((numberOfNodes, 1))) initialLoadingM = Tensor('initialLoadingM', (1, 6)) # Note: the last term was change on purpose because # GemmForge doesn't currently support tensor product operation convert_to_nodal = QStressNodal['kp'] <= \ db.v[aderdg.t('kl')] * QStress['lp'] + \ replicateInitialLoadingM['km'] * initialLoadingM['mp'] generator.add(name=f'{name_prefix}plConvertToNodal', ast=convert_to_nodal, target=gpu_target) generator.add(f'{name_prefix}plConvertToModal', QStress['kp'] <= QStress['kp'] + db.vInv[aderdg.t('kl')] * QStressNodal['lp'], target=gpu_target)
def addKernels(generator, aderdg, include_tensors, matricesDir, dynamicRuptureMethod): easi_ident_map = np.stack([np.eye(aderdg.numberOfQuantities())] * aderdg.numberOf2DBasisFunctions(), axis=2) assert(easi_ident_map.shape == (aderdg.numberOfQuantities(), aderdg.numberOfQuantities(), aderdg.numberOf2DBasisFunctions())) easi_ident_map = Tensor('easiIdentMap', easi_ident_map.shape, easi_ident_map, alignStride=False) easi_boundary_constant = Tensor('easiBoundaryConstant', (aderdg.numberOfQuantities(), aderdg.numberOf2DBasisFunctions()), alignStride=False) easi_boundary_map = Tensor('easiBoundaryMap', (aderdg.numberOfQuantities(), aderdg.numberOfQuantities(), aderdg.numberOf2DBasisFunctions(),), alignStride=False) create_easi_boundary_ghost_cells = ( aderdg.INodal['la'] <= easi_boundary_map['abl'] * aderdg.INodal['lb'] + easi_ident_map['abl'] * easi_boundary_constant['bl'] ) generator.add('createEasiBoundaryGhostCells', create_easi_boundary_ghost_cells) projectToNodalBoundary = lambda j: aderdg.INodal['kp'] <= aderdg.db.V3mTo2nFace[j]['km'] * aderdg.I['mp'] generator.addFamily('projectToNodalBoundary', simpleParameterSpace(4), projectToNodalBoundary) projectToNodalBoundaryRotated = lambda j: aderdg.INodal['kp'] <= aderdg.db.V3mTo2nFace[j]['kl'] \ * aderdg.I['lm'] \ * aderdg.Tinv['pm'] generator.addFamily('projectToNodalBoundaryRotated', simpleParameterSpace(4), projectToNodalBoundaryRotated) # To be used as Tinv in flux solver - this way we can save two rotations for # Dirichlet boundary, as ghost cell dofs are already rotated identity_rotation = np.double(aderdg.transformation_spp()) identity_rotation[0:9, 0:9] = np.eye(9) identity_rotation = Tensor('identityT', aderdg.transformation_spp().shape, identity_rotation, ) include_tensors.add(identity_rotation) project2nFaceTo3m = tensor_collection_from_constant_expression( base_name='project2nFaceTo3m', expressions=lambda i: aderdg.db.rDivM[i]['jk'] * aderdg.db.V2nTo2m['kl'], group_indices=range(4), target_indices='jl') aderdg.db.update(project2nFaceTo3m) selectZDisplacementFromQuantities = np.zeros(aderdg.numberOfQuantities()) selectZDisplacementFromQuantities[8] = 1 selectZDisplacementFromQuantities= Tensor('selectZDisplacementFromQuantities', selectZDisplacementFromQuantities.shape, selectZDisplacementFromQuantities, ) selectZDisplacementFromDisplacements = np.zeros(3) selectZDisplacementFromDisplacements[2] = 1 selectZDisplacementFromDisplacements = Tensor('selectZDisplacementFromDisplacements', selectZDisplacementFromDisplacements.shape, selectZDisplacementFromDisplacements, ) aderdg.INodalDisplacement = OptionalDimTensor('INodalDisplacement', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (aderdg.numberOf2DBasisFunctions(),), alignStride=True) displacement = OptionalDimTensor('displacement', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (aderdg.numberOf3DBasisFunctions(), 3), alignStride=True) dt = Scalar('dt') displacementAvgNodal = lambda side: aderdg.INodalDisplacement['i'] <= \ aderdg.db.V3mTo2nFace[side]['ij'] * aderdg.I['jk'] * selectZDisplacementFromQuantities['k'] \ + dt * aderdg.db.V3mTo2nFace[side]['ij'] * displacement['jk'] * selectZDisplacementFromDisplacements['k'] generator.addFamily('displacementAvgNodal', simpleParameterSpace(4), displacementAvgNodal) aderdg.INodalUpdate = OptionalDimTensor('INodalUpdate', aderdg.INodal.optName(), aderdg.INodal.optSize(), aderdg.INodal.optPos(), (aderdg.numberOf2DBasisFunctions(), aderdg.numberOfQuantities()), alignStride=True) factor = Scalar('factor') updateINodal = aderdg.INodal['kp'] <= aderdg.INodal['kp'] + factor * aderdg.INodalUpdate['kp'] generator.add('updateINodal', updateINodal)
def addKernels(generator, aderdg, include_tensors, targets): maxDepth = 3 numberOf3DBasisFunctions = aderdg.numberOf3DBasisFunctions() numberOf2DBasisFunctions = aderdg.numberOf2DBasisFunctions() numberOfQuantities = aderdg.numberOfQuantities() selectVelocitySpp = np.zeros((numberOfQuantities, 3)) selectVelocitySpp[6:9, 0:3] = np.eye(3) selectVelocity = Tensor('selectVelocity', selectVelocitySpp.shape, selectVelocitySpp, CSCMemoryLayout) faceDisplacement = OptionalDimTensor('faceDisplacement', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOf2DBasisFunctions, 3), alignStride=True) averageNormalDisplacement = OptionalDimTensor('averageNormalDisplacement', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOf2DBasisFunctions, ), alignStride=True) include_tensors.add(averageNormalDisplacement) subTriangleDofs = [ OptionalDimTensor('subTriangleDofs({})'.format(depth), aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (4**depth, 3), alignStride=True) for depth in range(maxDepth + 1) ] subTriangleProjection = [ Tensor('subTriangleProjection({})'.format(depth), (4**depth, numberOf3DBasisFunctions), alignStride=True) for depth in range(maxDepth + 1) ] subTriangleProjectionFromFace = [ Tensor('subTriangleProjectionFromFace({})'.format(depth), (4**depth, numberOf2DBasisFunctions), alignStride=True) for depth in range(maxDepth + 1) ] displacementRotationMatrix = Tensor('displacementRotationMatrix', (3, 3), alignStride=True) subTriangleDisplacement = lambda depth: subTriangleDofs[depth]['kp'] <= \ subTriangleProjectionFromFace[depth]['kl'] * aderdg.db.MV2nTo2m['lm'] * faceDisplacement['mp'] subTriangleVelocity = lambda depth: subTriangleDofs[depth][ 'kp'] <= subTriangleProjection[depth]['kl'] * aderdg.Q[ 'lq'] * selectVelocity['qp'] generator.addFamily('subTriangleDisplacement', simpleParameterSpace(maxDepth + 1), subTriangleDisplacement) generator.addFamily('subTriangleVelocity', simpleParameterSpace(maxDepth + 1), subTriangleVelocity) rotatedFaceDisplacement = OptionalDimTensor('rotatedFaceDisplacement', aderdg.Q.optName(), aderdg.Q.optSize(), aderdg.Q.optPos(), (numberOf2DBasisFunctions, 3), alignStride=True) generator.add( 'rotateFaceDisplacement', rotatedFaceDisplacement["mp"] <= faceDisplacement['mn'] * displacementRotationMatrix['pn']) addVelocity = lambda f: faceDisplacement['kp'] <= faceDisplacement['kp'] \ + aderdg.db.V3mTo2nFace[f]['kl'] * aderdg.I['lq'] * selectVelocity['qp'] generator.addFamily('addVelocity', simpleParameterSpace(4), addVelocity) if 'gpu' in targets: name_prefix = generate_kernel_name_prefix(target='gpu') integratedVelocities = OptionalDimTensor('integratedVelocities', aderdg.I.optName(), aderdg.I.optSize(), aderdg.I.optPos(), (numberOf3DBasisFunctions, 3), alignStride=True) addVelocity = lambda f: faceDisplacement['kp'] <= faceDisplacement['kp'] \ + aderdg.db.V3mTo2nFace[f]['kl'] * integratedVelocities['lp'] generator.addFamily(f'{name_prefix}addVelocity', simpleParameterSpace(4), addVelocity, target='gpu')