Esempio n. 1
0
    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())})
Esempio n. 2
0
  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)

    Ashape = (self.numberOfQuantities(), self.numberOfExtendedQuantities())
    self.AplusT = Tensor('AplusT', Ashape)
    self.AminusT = Tensor('AminusT', Ashape)
    Tshape = (self.numberOfExtendedQuantities(), self.numberOfExtendedQuantities())
    self.T = Tensor('T', Tshape)
    QgodShape = (self.numberOfQuantities(), self.numberOfQuantities())
    self.Tinv = Tensor('Tinv', QgodShape)
    self.QgodLocal = Tensor('QgodLocal', QgodShape)
    self.QgodNeighbor = Tensor('QgodNeighbor', QgodShape)

    self.oneSimToMultSim = Tensor('oneSimToMultSim', (self.Q.optSize(),), spp={(i,): '1.0' for i in range(self.Q.optSize())})
Esempio n. 3
0
  def __init__(self, order, multipleSimulations, matricesDir, memLayout, numberOfMechanisms):
    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)
Esempio n. 4
0
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'])
Esempio n. 5
0
 def __init__(self, order, multipleSimulations, matricesDir, memLayout):
   super().__init__(order, multipleSimulations, matricesDir)
   clones = {
     'star': ['star(0)', 'star(1)', 'star(2)'],
   }
   self.db.update( parseXMLMatrixFile('{}/star.xml'.format(matricesDir), clones) )
   memoryLayoutFromFile(memLayout, self.db, clones)
Esempio n. 6
0
    def __init__(self, order, multipleSimulations, matricesDir, memLayout,
                 numberOfMechanisms, **kwargs):

        super().__init__(order, multipleSimulations, matricesDir)
        clones = {
            'star': ['star(0)', 'star(1)', 'star(2)'],
        }
        self.db.update(
            parseXMLMatrixFile(
                '{}/matrices_poroelastic.xml'.format(matricesDir), clones))
        self.db.update(
            parseJSONMatrixFile('{}/stp_{}.json'.format(matricesDir, order),
                                clones))

        memoryLayoutFromFile(memLayout, self.db, clones)
Esempio n. 7
0
    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)
Esempio n. 8
0
def add(g):
  db = parseXMLMatrixFile('seissol_matrices.xml')
  
  Q = Tensor('Q', (8, 20, 15))
  I = Tensor('I', (8, 20, 15))
  g.add('seissol_stiffness', Q['skp'] <= db.kXiTDivM['lk'] * I['slq'] * db.star['qp'])

  # Reproduces recursive generation of zero blocks in Cauchy-Kowalevski prodedure,
  # described in "Sustained Petascale Performance of Seismic Simulations with SeisSol on SuperMUC",
  # Breuer et al., ISC 2014.
  dQ_shape = (20, 9)
  dQ0 = Tensor('dQ(0)', dQ_shape)
  star_ela = Tensor('star_ela', (9,9), spp=db.star['qp'].spp().as_ndarray()[0:9,0:9])
  dQ_prev = dQ0
  for i in range(1,4):
    derivativeSum = Add()
    for j in range(3):
      derivativeSum += db.kDivMT[j]['kl'] * dQ_prev['lq'] * star_ela['qp']
    derivativeSum = DeduceIndices('kp').visit(derivativeSum)
    derivativeSum = EquivalentSparsityPattern().visit(derivativeSum)
    dQ = Tensor('dQ({})'.format(i), dQ_shape, spp=derivativeSum.eqspp())
    g.add('derivative({})'.format(i), dQ['kp'] <= derivativeSum)
    dQ_prev = dQ
Esempio n. 9
0
  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')
    )
Esempio n. 10
0
    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)
Esempio n. 11
0
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)