# Source code for pyfr.solvers.baseadvecdiff.elements

    # -*- coding: utf-8 -*-

    from pyfr.backends.base.kernels import ComputeMetaKernel
    from pyfr.solvers.baseadvec import BaseAdvectionElements

    class BaseAdvectionDiffusionElements(BaseAdvectionElements):
        @property
        def _scratch_bufs(self):
            bufs = {'scal_fpts', 'vect_fpts', 'vect_upts'}

            if 'flux' in self.antialias:
                bufs |= {'scal_qpts', 'vect_qpts'}
            elif 'div-flux' in self.antialias:
                bufs |= {'scal_qpts'}

            if self._soln_in_src_exprs:
                if 'div-flux' in self.antialias:
                    bufs |= {'scal_qpts_cpy'}
                else:
                    bufs |= {'scal_upts_cpy'}

            return bufs

        def set_backend(self, backend, nscal_upts, nonce):
            super().set_backend(backend, nscal_upts, nonce)

            # Register pointwise kernels
            backend.pointwise.register(
                'pyfr.solvers.baseadvecdiff.kernels.gradcoru'
            )

            self.kernels['_copy_fpts'] = lambda: backend.kernel(
                'copy', self._vect_fpts.rslice(0, self.nfpts), self._scal_fpts
            )
            self.kernels['tgradpcoru_upts'] = lambda: backend.kernel(
                'mul', self.opmat('M4 - M6*M0'), self.scal_upts_inb,
                out=self._vect_upts
            )
            self.kernels['tgradcoru_upts'] = lambda: backend.kernel(
                'mul', self.opmat('M6'), self._vect_fpts.rslice(0, self.nfpts),
                 out=self._vect_upts, beta=1.0
            )
            self.kernels['gradcoru_upts'] = lambda: backend.kernel(
                'gradcoru', tplargs=dict(ndims=self.ndims, nvars=self.nvars),
                 dims=[self.nupts, self.neles], smats=self.smat_at('upts'),
                 rcpdjac=self.rcpdjac_at('upts'), gradu=self._vect_upts
            )

            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 = [backend.kernel('mul', self.opmat('M0'),
                                       vupts.rslice(i*nupts, (i + 1)*nupts),
                                       vfpts.rslice(i*nfpts, (i + 1)*nfpts))
                        for i in range(self.ndims)]

                return ComputeMetaKernel(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 = [backend.kernel('mul', self.opmat('M7'),
                                           vupts.rslice(i*nupts, (i + 1)*nupts),
                                           vqpts.rslice(i*nqpts, (i + 1)*nqpts))
                            for i in range(self.ndims)]

                    return ComputeMetaKernel(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
                backend.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)

                # Template arguments
                tplargs = dict(
                    nvars=self.nvars, nupts=self.nupts, svar=shockvar,
                    c=self.cfg.items_as('solver-artificial-viscosity', float),
                    order=self.basis.order, ubdegs=self.basis.ubasis.degrees,
                    invvdm=self.basis.ubasis.invvdm.T
                )

                # Allocate space for the artificial viscosity vector
                self.artvisc = backend.matrix((1, self.neles),
                                              extent=nonce + 'artvisc', tags=tags)

                # Apply the sensor to estimate the required artificial viscosity
                self.kernels['shocksensor'] = lambda: backend.kernel(
                    'shocksensor', tplargs=tplargs, dims=[self.neles],
                    u=self.scal_upts_inb, artvisc=self.artvisc
                )
            elif shock_capturing == 'none':
                self.artvisc = None
            else:
                raise ValueError('Invalid shock capturing scheme')

        def get_artvisc_fpts_for_inter(self, eidx, fidx):
            nfp = self.nfacefpts[fidx]
            return (self.artvisc.mid,)*nfp, (0,)*nfp, (eidx,)*nfp