xref: /libCEED/python/ceed_basis.py (revision 80a9ef0545a39c00cdcaab1ca26f8053604f3120)
15a21df39Svaleriabarra# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
25a21df39Svaleriabarra# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
35a21df39Svaleriabarra# reserved. See files LICENSE and NOTICE for details.
45a21df39Svaleriabarra#
55a21df39Svaleriabarra# This file is part of CEED, a collection of benchmarks, miniapps, software
65a21df39Svaleriabarra# libraries and APIs for efficient high-order finite element and spectral
75a21df39Svaleriabarra# element discretizations for exascale applications. For more information and
85a21df39Svaleriabarra# source code availability see http://github.com/ceed.
95a21df39Svaleriabarra#
105a21df39Svaleriabarra# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
115a21df39Svaleriabarra# a collaborative effort of two U.S. Department of Energy organizations (Office
125a21df39Svaleriabarra# of Science and the National Nuclear Security Administration) responsible for
135a21df39Svaleriabarra# the planning and preparation of a capable exascale ecosystem, including
145a21df39Svaleriabarra# software, applications, hardware, advanced system engineering and early
155a21df39Svaleriabarra# testbed platforms, in support of the nation's exascale computing imperative.
165a21df39Svaleriabarra
175a21df39Svaleriabarrafrom _ceed_cffi import ffi, lib
185a21df39Svaleriabarraimport tempfile
195a21df39Svaleriabarraimport numpy as np
205a21df39Svaleriabarrafrom abc import ABC
21*80a9ef05SNatalie Beamsfrom .ceed_constants import TRANSPOSE, NOTRANSPOSE, scalar_types
225a21df39Svaleriabarra
235a21df39Svaleriabarra# ------------------------------------------------------------------------------
247a7b0fa3SJed Brown
257a7b0fa3SJed Brown
265a21df39Svaleriabarraclass Basis(ABC):
275a21df39Svaleriabarra    """Ceed Basis: finite element basis objects."""
285a21df39Svaleriabarra
295a21df39Svaleriabarra    # Representation
305a21df39Svaleriabarra    def __repr__(self):
315a21df39Svaleriabarra        return "<CeedBasis instance at " + hex(id(self)) + ">"
325a21df39Svaleriabarra
335a21df39Svaleriabarra    # String conversion for print() to stdout
345a21df39Svaleriabarra    def __str__(self):
355a21df39Svaleriabarra        """View a Basis via print()."""
365a21df39Svaleriabarra
375a21df39Svaleriabarra        # libCEED call
385a21df39Svaleriabarra        with tempfile.NamedTemporaryFile() as key_file:
395a21df39Svaleriabarra            with open(key_file.name, 'r+') as stream_file:
405a21df39Svaleriabarra                stream = ffi.cast("FILE *", stream_file)
415a21df39Svaleriabarra
42477729cfSJeremy L Thompson                err_code = lib.CeedBasisView(self._pointer[0], stream)
43477729cfSJeremy L Thompson                self._ceed._check_error(err_code)
445a21df39Svaleriabarra
455a21df39Svaleriabarra                stream_file.seek(0)
465a21df39Svaleriabarra                out_string = stream_file.read()
475a21df39Svaleriabarra
485a21df39Svaleriabarra        return out_string
495a21df39Svaleriabarra
505a21df39Svaleriabarra    # Apply Basis
515a21df39Svaleriabarra    def apply(self, nelem, emode, u, v, tmode=NOTRANSPOSE):
525a21df39Svaleriabarra        """Apply basis evaluation from nodes to quadrature points or vice versa.
535a21df39Svaleriabarra
545a21df39Svaleriabarra           Args:
555a21df39Svaleriabarra             nelem: the number of elements to apply the basis evaluation to;
565a21df39Svaleriabarra                      the backend will specify the ordering in a
575a21df39Svaleriabarra                      BlockedElemRestriction
585a21df39Svaleriabarra             emode: basis evaluation mode
595a21df39Svaleriabarra             u: input vector
605a21df39Svaleriabarra             v: output vector
615a21df39Svaleriabarra             **tmode: CEED_NOTRANSPOSE to evaluate from nodes to quadrature
625a21df39Svaleriabarra                        points, CEED_TRANSPOSE to apply the transpose, mapping
635a21df39Svaleriabarra                        from quadrature points to nodes; default CEED_NOTRANSPOSE"""
645a21df39Svaleriabarra
655a21df39Svaleriabarra        # libCEED call
66477729cfSJeremy L Thompson        err_code = lib.CeedBasisApply(self._pointer[0], nelem, tmode, emode,
675a21df39Svaleriabarra                                      u._pointer[0], v._pointer[0])
68477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
695a21df39Svaleriabarra
705a21df39Svaleriabarra    # Transpose a Basis
715a21df39Svaleriabarra    @property
725a21df39Svaleriabarra    def T(self):
735a21df39Svaleriabarra        """Transpose a Basis."""
745a21df39Svaleriabarra
755a21df39Svaleriabarra        return TransposeBasis(self)
765a21df39Svaleriabarra
775a21df39Svaleriabarra    # Transpose a Basis
785a21df39Svaleriabarra    @property
795a21df39Svaleriabarra    def transpose(self):
805a21df39Svaleriabarra        """Transpose a Basis."""
815a21df39Svaleriabarra
825a21df39Svaleriabarra        return TransposeBasis(self)
835a21df39Svaleriabarra
845a21df39Svaleriabarra    # Get number of nodes
855a21df39Svaleriabarra    def get_num_nodes(self):
865a21df39Svaleriabarra        """Get total number of nodes (in dim dimensions) of a Basis.
875a21df39Svaleriabarra
885a21df39Svaleriabarra           Returns:
895a21df39Svaleriabarra             num_nodes: total number of nodes"""
905a21df39Svaleriabarra
915a21df39Svaleriabarra        # Setup argument
925a21df39Svaleriabarra        p_pointer = ffi.new("CeedInt *")
935a21df39Svaleriabarra
945a21df39Svaleriabarra        # libCEED call
95477729cfSJeremy L Thompson        err_code = lib.CeedBasisGetNumNodes(self._pointer[0], p_pointer)
96477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
975a21df39Svaleriabarra
985a21df39Svaleriabarra        return p_pointer[0]
995a21df39Svaleriabarra
1005a21df39Svaleriabarra    # Get number of quadrature points
1015a21df39Svaleriabarra    def get_num_quadrature_points(self):
1025a21df39Svaleriabarra        """Get total number of quadrature points (in dim dimensions) of a Basis.
1035a21df39Svaleriabarra
1045a21df39Svaleriabarra           Returns:
1055a21df39Svaleriabarra             num_qpts: total number of quadrature points"""
1065a21df39Svaleriabarra
1075a21df39Svaleriabarra        # Setup argument
1085a21df39Svaleriabarra        q_pointer = ffi.new("CeedInt *")
1095a21df39Svaleriabarra
1105a21df39Svaleriabarra        # libCEED call
111477729cfSJeremy L Thompson        err_code = lib.CeedBasisGetNumQuadraturePoints(
112477729cfSJeremy L Thompson            self._pointer[0], q_pointer)
113477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
1145a21df39Svaleriabarra
1155a21df39Svaleriabarra        return q_pointer[0]
1165a21df39Svaleriabarra
1175a21df39Svaleriabarra    # Destructor
1185a21df39Svaleriabarra    def __del__(self):
1195a21df39Svaleriabarra        # libCEED call
120477729cfSJeremy L Thompson        err_code = lib.CeedBasisDestroy(self._pointer)
121477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
1225a21df39Svaleriabarra
1235a21df39Svaleriabarra# ------------------------------------------------------------------------------
1247a7b0fa3SJed Brown
1257a7b0fa3SJed Brown
1265a21df39Svaleriabarraclass BasisTensorH1(Basis):
1275a21df39Svaleriabarra    """Ceed Tensor H1 Basis: finite element tensor-product basis objects for
1285a21df39Svaleriabarra         H^1 discretizations."""
1295a21df39Svaleriabarra
1305a21df39Svaleriabarra    # Constructor
1315a21df39Svaleriabarra    def __init__(self, ceed, dim, ncomp, P1d, Q1d, interp1d, grad1d,
1325a21df39Svaleriabarra                 qref1d, qweight1d):
1335a21df39Svaleriabarra
1345a21df39Svaleriabarra        # Setup arguments
1355a21df39Svaleriabarra        self._pointer = ffi.new("CeedBasis *")
1365a21df39Svaleriabarra
1375a21df39Svaleriabarra        self._ceed = ceed
1385a21df39Svaleriabarra
1395a21df39Svaleriabarra        interp1d_pointer = ffi.new("CeedScalar *")
1407a7b0fa3SJed Brown        interp1d_pointer = ffi.cast(
1417a7b0fa3SJed Brown            "CeedScalar *",
1427a7b0fa3SJed Brown            interp1d.__array_interface__['data'][0])
1435a21df39Svaleriabarra
1445a21df39Svaleriabarra        grad1d_pointer = ffi.new("CeedScalar *")
1457a7b0fa3SJed Brown        grad1d_pointer = ffi.cast(
1467a7b0fa3SJed Brown            "CeedScalar *",
1477a7b0fa3SJed Brown            grad1d.__array_interface__['data'][0])
1485a21df39Svaleriabarra
1495a21df39Svaleriabarra        qref1d_pointer = ffi.new("CeedScalar *")
1507a7b0fa3SJed Brown        qref1d_pointer = ffi.cast(
1517a7b0fa3SJed Brown            "CeedScalar *",
1527a7b0fa3SJed Brown            qref1d.__array_interface__['data'][0])
1535a21df39Svaleriabarra
1545a21df39Svaleriabarra        qweight1d_pointer = ffi.new("CeedScalar *")
1557a7b0fa3SJed Brown        qweight1d_pointer = ffi.cast(
1567a7b0fa3SJed Brown            "CeedScalar *",
1577a7b0fa3SJed Brown            qweight1d.__array_interface__['data'][0])
1585a21df39Svaleriabarra
1595a21df39Svaleriabarra        # libCEED call
160477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateTensorH1(self._ceed._pointer[0], dim, ncomp,
161477729cfSJeremy L Thompson                                               P1d, Q1d, interp1d_pointer,
162477729cfSJeremy L Thompson                                               grad1d_pointer, qref1d_pointer,
1635a21df39Svaleriabarra                                               qweight1d_pointer, self._pointer)
164477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
1655a21df39Svaleriabarra
16666ce82e0Sjeremylt    # Get 1D interpolation matrix
16766ce82e0Sjeremylt    def get_interp_1d(self):
168d99fa3c5SJeremy L Thompson        """Return 1D interpolation matrix of a tensor product Basis.
169d99fa3c5SJeremy L Thompson
170d99fa3c5SJeremy L Thompson           Returns:
171d99fa3c5SJeremy L Thompson             *array: Numpy array"""
172d99fa3c5SJeremy L Thompson
173d99fa3c5SJeremy L Thompson        # Compute the length of the array
174d99fa3c5SJeremy L Thompson        nnodes_pointer = ffi.new("CeedInt *")
175d99fa3c5SJeremy L Thompson        lib.CeedBasisGetNumNodes1D(self._pointer[0], nnodes_pointer)
176d99fa3c5SJeremy L Thompson        nqpts_pointer = ffi.new("CeedInt *")
177d99fa3c5SJeremy L Thompson        lib.CeedBasisGetNumQuadraturePoints1D(self._pointer[0], nqpts_pointer)
178d99fa3c5SJeremy L Thompson        length = nnodes_pointer[0] * nqpts_pointer[0]
179d99fa3c5SJeremy L Thompson
180d99fa3c5SJeremy L Thompson        # Setup the pointer's pointer
181d99fa3c5SJeremy L Thompson        array_pointer = ffi.new("CeedScalar **")
182d99fa3c5SJeremy L Thompson
183d99fa3c5SJeremy L Thompson        # libCEED call
184d99fa3c5SJeremy L Thompson        lib.CeedBasisGetInterp1D(self._pointer[0], array_pointer)
185d99fa3c5SJeremy L Thompson
186d99fa3c5SJeremy L Thompson        # Return array created from buffer
187d99fa3c5SJeremy L Thompson        # Create buffer object from returned pointer
188d99fa3c5SJeremy L Thompson        buff = ffi.buffer(
189d99fa3c5SJeremy L Thompson            array_pointer[0],
190d99fa3c5SJeremy L Thompson            ffi.sizeof("CeedScalar") *
191d99fa3c5SJeremy L Thompson            length)
192d99fa3c5SJeremy L Thompson        # return read only Numpy array
193*80a9ef05SNatalie Beams        ret = np.frombuffer(buff, dtype=scalar_types[lib.CEED_SCALAR_TYPE])
194d99fa3c5SJeremy L Thompson        ret.flags['WRITEABLE'] = False
195d99fa3c5SJeremy L Thompson        return ret
196d99fa3c5SJeremy L Thompson
19766ce82e0Sjeremylt    # Get 1D gradient matrix
19866ce82e0Sjeremylt    def get_grad_1d(self):
19966ce82e0Sjeremylt        """Return 1D gradient matrix of a tensor product Basis.
20066ce82e0Sjeremylt
20166ce82e0Sjeremylt           Returns:
20266ce82e0Sjeremylt             *array: Numpy array"""
20366ce82e0Sjeremylt
20466ce82e0Sjeremylt        # Compute the length of the array
20566ce82e0Sjeremylt        nnodes_pointer = ffi.new("CeedInt *")
20666ce82e0Sjeremylt        lib.CeedBasisGetNumNodes1D(self._pointer[0], nnodes_pointer)
20766ce82e0Sjeremylt        nqpts_pointer = ffi.new("CeedInt *")
20866ce82e0Sjeremylt        lib.CeedBasisGetNumQuadraturePoints1D(self._pointer[0], nqpts_pointer)
20966ce82e0Sjeremylt        length = nnodes_pointer[0] * nqpts_pointer[0]
21066ce82e0Sjeremylt
21166ce82e0Sjeremylt        # Setup the pointer's pointer
21266ce82e0Sjeremylt        array_pointer = ffi.new("CeedScalar **")
21366ce82e0Sjeremylt
21466ce82e0Sjeremylt        # libCEED call
21566ce82e0Sjeremylt        lib.CeedBasisGetGrad1D(self._pointer[0], array_pointer)
21666ce82e0Sjeremylt
21766ce82e0Sjeremylt        # Return array created from buffer
21866ce82e0Sjeremylt        # Create buffer object from returned pointer
21966ce82e0Sjeremylt        buff = ffi.buffer(
22066ce82e0Sjeremylt            array_pointer[0],
22166ce82e0Sjeremylt            ffi.sizeof("CeedScalar") *
22266ce82e0Sjeremylt            length)
22366ce82e0Sjeremylt        # return read only Numpy array
22466ce82e0Sjeremylt        ret = np.frombuffer(buff, dtype="float64")
22566ce82e0Sjeremylt        ret.flags['WRITEABLE'] = False
22666ce82e0Sjeremylt        return ret
22766ce82e0Sjeremylt
22866ce82e0Sjeremylt    # Get 1D quadrature weights matrix
22966ce82e0Sjeremylt    def get_q_weight_1d(self):
23066ce82e0Sjeremylt        """Return 1D quadrature weights matrix of a tensor product Basis.
23166ce82e0Sjeremylt
23266ce82e0Sjeremylt           Returns:
23366ce82e0Sjeremylt             *array: Numpy array"""
23466ce82e0Sjeremylt
23566ce82e0Sjeremylt        # Compute the length of the array
23666ce82e0Sjeremylt        nqpts_pointer = ffi.new("CeedInt *")
23766ce82e0Sjeremylt        lib.CeedBasisGetNumQuadraturePoints1D(self._pointer[0], nqpts_pointer)
23866ce82e0Sjeremylt        length = nqpts_pointer[0]
23966ce82e0Sjeremylt
24066ce82e0Sjeremylt        # Setup the pointer's pointer
24166ce82e0Sjeremylt        array_pointer = ffi.new("CeedScalar **")
24266ce82e0Sjeremylt
24366ce82e0Sjeremylt        # libCEED call
24466ce82e0Sjeremylt        lib.CeedBasisGetQWeights(self._pointer[0], array_pointer)
24566ce82e0Sjeremylt
24666ce82e0Sjeremylt        # Return array created from buffer
24766ce82e0Sjeremylt        # Create buffer object from returned pointer
24866ce82e0Sjeremylt        buff = ffi.buffer(
24966ce82e0Sjeremylt            array_pointer[0],
25066ce82e0Sjeremylt            ffi.sizeof("CeedScalar") *
25166ce82e0Sjeremylt            length)
25266ce82e0Sjeremylt        # return read only Numpy array
25366ce82e0Sjeremylt        ret = np.frombuffer(buff, dtype="float64")
25466ce82e0Sjeremylt        ret.flags['WRITEABLE'] = False
25566ce82e0Sjeremylt        return ret
25666ce82e0Sjeremylt
25766ce82e0Sjeremylt    # Get 1D quadrature points matrix
25866ce82e0Sjeremylt    def get_q_ref_1d(self):
25966ce82e0Sjeremylt        """Return 1D quadrature points matrix of a tensor product Basis.
26066ce82e0Sjeremylt
26166ce82e0Sjeremylt           Returns:
26266ce82e0Sjeremylt             *array: Numpy array"""
26366ce82e0Sjeremylt
26466ce82e0Sjeremylt        # Compute the length of the array
26566ce82e0Sjeremylt        nqpts_pointer = ffi.new("CeedInt *")
26666ce82e0Sjeremylt        lib.CeedBasisGetNumQuadraturePoints1D(self._pointer[0], nqpts_pointer)
26766ce82e0Sjeremylt        length = nqpts_pointer[0]
26866ce82e0Sjeremylt
26966ce82e0Sjeremylt        # Setup the pointer's pointer
27066ce82e0Sjeremylt        array_pointer = ffi.new("CeedScalar **")
27166ce82e0Sjeremylt
27266ce82e0Sjeremylt        # libCEED call
27366ce82e0Sjeremylt        lib.CeedBasisGetQRef(self._pointer[0], array_pointer)
27466ce82e0Sjeremylt
27566ce82e0Sjeremylt        # Return array created from buffer
27666ce82e0Sjeremylt        # Create buffer object from returned pointer
27766ce82e0Sjeremylt        buff = ffi.buffer(
27866ce82e0Sjeremylt            array_pointer[0],
27966ce82e0Sjeremylt            ffi.sizeof("CeedScalar") *
28066ce82e0Sjeremylt            length)
28166ce82e0Sjeremylt        # return read only Numpy array
28266ce82e0Sjeremylt        ret = np.frombuffer(buff, dtype="float64")
28366ce82e0Sjeremylt        ret.flags['WRITEABLE'] = False
28466ce82e0Sjeremylt        return ret
28566ce82e0Sjeremylt
286d99fa3c5SJeremy L Thompson
2875a21df39Svaleriabarra# ------------------------------------------------------------------------------
2887a7b0fa3SJed Brown
2897a7b0fa3SJed Brown
290d99fa3c5SJeremy L Thompsonclass BasisTensorH1Lagrange(BasisTensorH1):
2915a21df39Svaleriabarra    """Ceed Tensor H1 Lagrange Basis: finite element tensor-product Lagrange basis
2925a21df39Svaleriabarra         objects for H^1 discretizations."""
2935a21df39Svaleriabarra
2945a21df39Svaleriabarra    # Constructor
2955a21df39Svaleriabarra    def __init__(self, ceed, dim, ncomp, P, Q, qmode):
2965a21df39Svaleriabarra
2975a21df39Svaleriabarra        # Setup arguments
2985a21df39Svaleriabarra        self._pointer = ffi.new("CeedBasis *")
2995a21df39Svaleriabarra
3005a21df39Svaleriabarra        self._ceed = ceed
3015a21df39Svaleriabarra
3025a21df39Svaleriabarra        # libCEED call
303477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateTensorH1Lagrange(self._ceed._pointer[0], dim,
304477729cfSJeremy L Thompson                                                       ncomp, P, Q, qmode, self._pointer)
305477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
3065a21df39Svaleriabarra
3075a21df39Svaleriabarra# ------------------------------------------------------------------------------
3087a7b0fa3SJed Brown
3097a7b0fa3SJed Brown
3105a21df39Svaleriabarraclass BasisH1(Basis):
3115a21df39Svaleriabarra    """Ceed H1 Basis: finite element non tensor-product basis for H^1 discretizations."""
3125a21df39Svaleriabarra
3135a21df39Svaleriabarra    # Constructor
3147a7b0fa3SJed Brown    def __init__(self, ceed, topo, ncomp, nnodes,
3157a7b0fa3SJed Brown                 nqpts, interp, grad, qref, qweight):
3165a21df39Svaleriabarra
3175a21df39Svaleriabarra        # Setup arguments
3185a21df39Svaleriabarra        self._pointer = ffi.new("CeedBasis *")
3195a21df39Svaleriabarra
3205a21df39Svaleriabarra        self._ceed = ceed
3215a21df39Svaleriabarra
3225a21df39Svaleriabarra        interp_pointer = ffi.new("CeedScalar *")
3237a7b0fa3SJed Brown        interp_pointer = ffi.cast(
3247a7b0fa3SJed Brown            "CeedScalar *",
3257a7b0fa3SJed Brown            interp.__array_interface__['data'][0])
3265a21df39Svaleriabarra
3275a21df39Svaleriabarra        grad_pointer = ffi.new("CeedScalar *")
3287a7b0fa3SJed Brown        grad_pointer = ffi.cast(
3297a7b0fa3SJed Brown            "CeedScalar *",
3307a7b0fa3SJed Brown            grad.__array_interface__['data'][0])
3315a21df39Svaleriabarra
3325a21df39Svaleriabarra        qref_pointer = ffi.new("CeedScalar *")
3337a7b0fa3SJed Brown        qref_pointer = ffi.cast(
3347a7b0fa3SJed Brown            "CeedScalar *",
3357a7b0fa3SJed Brown            qref.__array_interface__['data'][0])
3365a21df39Svaleriabarra
3375a21df39Svaleriabarra        qweight_pointer = ffi.new("CeedScalar *")
3387a7b0fa3SJed Brown        qweight_pointer = ffi.cast(
3397a7b0fa3SJed Brown            "CeedScalar *",
3407a7b0fa3SJed Brown            qweight.__array_interface__['data'][0])
3415a21df39Svaleriabarra
3425a21df39Svaleriabarra        # libCEED call
343477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateH1(self._ceed._pointer[0], topo, ncomp,
344477729cfSJeremy L Thompson                                         nnodes, nqpts, interp_pointer,
345477729cfSJeremy L Thompson                                         grad_pointer, qref_pointer,
3465a21df39Svaleriabarra                                         qweight_pointer, self._pointer)
3475a21df39Svaleriabarra
3485a21df39Svaleriabarra# ------------------------------------------------------------------------------
3497a7b0fa3SJed Brown
3507a7b0fa3SJed Brown
3515a21df39Svaleriabarraclass TransposeBasis():
3525a21df39Svaleriabarra    """Transpose Ceed Basis: transpose of finite element tensor-product basis objects."""
3535a21df39Svaleriabarra
3545a21df39Svaleriabarra    # Attributes
3555a21df39Svaleriabarra    _basis = None
3565a21df39Svaleriabarra
3575a21df39Svaleriabarra    # Constructor
3585a21df39Svaleriabarra    def __init__(self, basis):
3595a21df39Svaleriabarra
3605a21df39Svaleriabarra        # Reference basis
3615a21df39Svaleriabarra        self._basis = basis
3625a21df39Svaleriabarra
3635a21df39Svaleriabarra    # Representation
3645a21df39Svaleriabarra    def __repr__(self):
3655a21df39Svaleriabarra        return "<Transpose CeedBasis instance at " + hex(id(self)) + ">"
3665a21df39Svaleriabarra
3675a21df39Svaleriabarra    # Apply Transpose Basis
3685a21df39Svaleriabarra    def apply(self, nelem, emode, u, v):
3695a21df39Svaleriabarra        """Apply basis evaluation from quadrature points to nodes.
3705a21df39Svaleriabarra
3715a21df39Svaleriabarra           Args:
3725a21df39Svaleriabarra             nelem: the number of elements to apply the basis evaluation to;
3735a21df39Svaleriabarra                      the backend will specify the ordering in a
3745a21df39Svaleriabarra                      Blocked ElemRestriction
3755a21df39Svaleriabarra             **emode: basis evaluation mode
3765a21df39Svaleriabarra             u: input vector
3775a21df39Svaleriabarra             v: output vector"""
3785a21df39Svaleriabarra
3795a21df39Svaleriabarra        # libCEED call
3805a21df39Svaleriabarra        self._basis.apply(nelem, emode, u, v, tmode=TRANSPOSE)
3815a21df39Svaleriabarra
3825a21df39Svaleriabarra# ------------------------------------------------------------------------------
383