# Source code for pyfr.solvers.baseadvec.inters

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

    import math

    from pyfr.solvers.base import BaseInters, get_opt_view_perm
    from pyfr.nputil import npeval

    class BaseAdvectionIntInters(BaseInters):
        def __init__(self, be, lhs, rhs, elemap, cfg):
            super().__init__(be, lhs, elemap, cfg)

            const_mat = self._const_mat

            # Compute the `optimal' permutation for our interface
            self._gen_perm(lhs, rhs)

            # Generate the left and right hand side view matrices
            self._scal_lhs = self._scal_view(lhs, 'get_scal_fpts_for_inter')
            self._scal_rhs = self._scal_view(rhs, 'get_scal_fpts_for_inter')

            # Generate the constant matrices
            self._mag_pnorm_lhs = const_mat(lhs, 'get_mag_pnorms_for_inter')
            self._norm_pnorm_lhs = const_mat(lhs, 'get_norm_pnorms_for_inter')

        def _gen_perm(self, lhs, rhs):
            # Arbitrarily, take the permutation which results in an optimal
            # memory access pattern for the LHS of the interface
            self._perm = get_opt_view_perm(lhs, 'get_scal_fpts_for_inter',
                                           self._elemap)

    class BaseAdvectionMPIInters(BaseInters):
        # Tag used for MPI
        MPI_TAG = 2314

        def __init__(self, be, lhs, rhsrank, rallocs, elemap, cfg):
            super().__init__(be, lhs, elemap, cfg)
            self._rhsrank = rhsrank
            self._rallocs = rallocs

            const_mat = self._const_mat

            # Generate the left hand view matrix and its dual
            self._scal_lhs = self._scal_xchg_view(lhs, 'get_scal_fpts_for_inter')
            self._scal_rhs = be.xchg_matrix_for_view(self._scal_lhs)

            self._mag_pnorm_lhs = const_mat(lhs, 'get_mag_pnorms_for_inter')
            self._norm_pnorm_lhs = const_mat(lhs, 'get_norm_pnorms_for_inter')

            # Kernels
            self.kernels['scal_fpts_pack'] = lambda: be.kernel(
                'pack', self._scal_lhs
            )
            self.kernels['scal_fpts_send'] = lambda: be.kernel(
                'send_pack', self._scal_lhs, self._rhsrank, self.MPI_TAG
            )
            self.kernels['scal_fpts_recv'] = lambda: be.kernel(
                'recv_pack', self._scal_rhs, self._rhsrank, self.MPI_TAG
            )
            self.kernels['scal_fpts_unpack'] = lambda: be.kernel(
                'unpack', self._scal_rhs
            )

    class BaseAdvectionBCInters(BaseInters):
        type = None

        def __init__(self, be, lhs, elemap, cfgsect, cfg):
            super().__init__(be, lhs, elemap, cfg)
            self.cfgsect = cfgsect

            const_mat = self._const_mat

            # For BC interfaces, which only have an LHS state, we take the
            # permutation which results in an optimal memory access pattern
            # iterating over this state.
            self._perm = get_opt_view_perm(lhs, 'get_scal_fpts_for_inter', elemap)

            # LHS view and constant matrices
            self._scal_lhs = self._scal_view(lhs, 'get_scal_fpts_for_inter')
            self._mag_pnorm_lhs = const_mat(lhs, 'get_mag_pnorms_for_inter')
            self._norm_pnorm_lhs = const_mat(lhs, 'get_norm_pnorms_for_inter')
            self._ploc = None

        def _eval_opts(self, opts, default=None):
            # Boundary conditions, much like initial conditions, can be
            # parameterized by values in [constants] so we must bring these
            # into scope when evaluating the boundary conditions
            cc = self.cfg.items_as('constants', float)

            cfg, sect = self.cfg, self.cfgsect

            # Evaluate any BC specific arguments from the config file
            if default is not None:
                return [npeval(cfg.getexpr(sect, k, default), cc) for k in opts]
            else:
                return [npeval(cfg.getexpr(sect, k), cc) for k in opts]

        def _exp_opts(self, opts, lhs, default={}):
            cfg, sect = self.cfg, self.cfgsect

            subs = cfg.items('constants')
            subs.update(x='ploc[0]', y='ploc[1]', z='ploc[2]')
            subs.update(abs='fabs', pi=str(math.pi))

            exprs = {}
            for k in opts:
                if k in default:
                    exprs[k] = cfg.getexpr(sect, k, default[k], subs=subs)
                else:
                    exprs[k] = cfg.getexpr(sect, k, subs=subs)

            if any('ploc' in ex for ex in exprs.values()) and not self._ploc:
                self._ploc = self._const_mat(lhs, 'get_ploc_for_inter')

            return exprs