xref: /libCEED/python/ceed_basis.py (revision 477729cfdbe3383ce841609affbc919aa37fc70d)
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
215a21df39Svaleriabarrafrom .ceed_constants import TRANSPOSE, NOTRANSPOSE
225a21df39Svaleriabarra
235a21df39Svaleriabarra# ------------------------------------------------------------------------------
247a7b0fa3SJed Brown
257a7b0fa3SJed Brown
265a21df39Svaleriabarraclass Basis(ABC):
275a21df39Svaleriabarra    """Ceed Basis: finite element basis objects."""
285a21df39Svaleriabarra
295a21df39Svaleriabarra    # Attributes
305a21df39Svaleriabarra    _ceed = ffi.NULL
315a21df39Svaleriabarra    _pointer = ffi.NULL
325a21df39Svaleriabarra
335a21df39Svaleriabarra    # Representation
345a21df39Svaleriabarra    def __repr__(self):
355a21df39Svaleriabarra        return "<CeedBasis instance at " + hex(id(self)) + ">"
365a21df39Svaleriabarra
375a21df39Svaleriabarra    # String conversion for print() to stdout
385a21df39Svaleriabarra    def __str__(self):
395a21df39Svaleriabarra        """View a Basis via print()."""
405a21df39Svaleriabarra
415a21df39Svaleriabarra        # libCEED call
425a21df39Svaleriabarra        with tempfile.NamedTemporaryFile() as key_file:
435a21df39Svaleriabarra            with open(key_file.name, 'r+') as stream_file:
445a21df39Svaleriabarra                stream = ffi.cast("FILE *", stream_file)
455a21df39Svaleriabarra
46*477729cfSJeremy L Thompson                err_code = lib.CeedBasisView(self._pointer[0], stream)
47*477729cfSJeremy L Thompson                self._ceed._check_error(err_code)
485a21df39Svaleriabarra
495a21df39Svaleriabarra                stream_file.seek(0)
505a21df39Svaleriabarra                out_string = stream_file.read()
515a21df39Svaleriabarra
525a21df39Svaleriabarra        return out_string
535a21df39Svaleriabarra
545a21df39Svaleriabarra    # Apply Basis
555a21df39Svaleriabarra    def apply(self, nelem, emode, u, v, tmode=NOTRANSPOSE):
565a21df39Svaleriabarra        """Apply basis evaluation from nodes to quadrature points or vice versa.
575a21df39Svaleriabarra
585a21df39Svaleriabarra           Args:
595a21df39Svaleriabarra             nelem: the number of elements to apply the basis evaluation to;
605a21df39Svaleriabarra                      the backend will specify the ordering in a
615a21df39Svaleriabarra                      BlockedElemRestriction
625a21df39Svaleriabarra             emode: basis evaluation mode
635a21df39Svaleriabarra             u: input vector
645a21df39Svaleriabarra             v: output vector
655a21df39Svaleriabarra             **tmode: CEED_NOTRANSPOSE to evaluate from nodes to quadrature
665a21df39Svaleriabarra                        points, CEED_TRANSPOSE to apply the transpose, mapping
675a21df39Svaleriabarra                        from quadrature points to nodes; default CEED_NOTRANSPOSE"""
685a21df39Svaleriabarra
695a21df39Svaleriabarra        # libCEED call
70*477729cfSJeremy L Thompson        err_code = lib.CeedBasisApply(self._pointer[0], nelem, tmode, emode,
715a21df39Svaleriabarra                                      u._pointer[0], v._pointer[0])
72*477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
735a21df39Svaleriabarra
745a21df39Svaleriabarra    # Transpose a Basis
755a21df39Svaleriabarra    @property
765a21df39Svaleriabarra    def T(self):
775a21df39Svaleriabarra        """Transpose a Basis."""
785a21df39Svaleriabarra
795a21df39Svaleriabarra        return TransposeBasis(self)
805a21df39Svaleriabarra
815a21df39Svaleriabarra    # Transpose a Basis
825a21df39Svaleriabarra    @property
835a21df39Svaleriabarra    def transpose(self):
845a21df39Svaleriabarra        """Transpose a Basis."""
855a21df39Svaleriabarra
865a21df39Svaleriabarra        return TransposeBasis(self)
875a21df39Svaleriabarra
885a21df39Svaleriabarra    # Get number of nodes
895a21df39Svaleriabarra    def get_num_nodes(self):
905a21df39Svaleriabarra        """Get total number of nodes (in dim dimensions) of a Basis.
915a21df39Svaleriabarra
925a21df39Svaleriabarra           Returns:
935a21df39Svaleriabarra             num_nodes: total number of nodes"""
945a21df39Svaleriabarra
955a21df39Svaleriabarra        # Setup argument
965a21df39Svaleriabarra        p_pointer = ffi.new("CeedInt *")
975a21df39Svaleriabarra
985a21df39Svaleriabarra        # libCEED call
99*477729cfSJeremy L Thompson        err_code = lib.CeedBasisGetNumNodes(self._pointer[0], p_pointer)
100*477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
1015a21df39Svaleriabarra
1025a21df39Svaleriabarra        return p_pointer[0]
1035a21df39Svaleriabarra
1045a21df39Svaleriabarra    # Get number of quadrature points
1055a21df39Svaleriabarra    def get_num_quadrature_points(self):
1065a21df39Svaleriabarra        """Get total number of quadrature points (in dim dimensions) of a Basis.
1075a21df39Svaleriabarra
1085a21df39Svaleriabarra           Returns:
1095a21df39Svaleriabarra             num_qpts: total number of quadrature points"""
1105a21df39Svaleriabarra
1115a21df39Svaleriabarra        # Setup argument
1125a21df39Svaleriabarra        q_pointer = ffi.new("CeedInt *")
1135a21df39Svaleriabarra
1145a21df39Svaleriabarra        # libCEED call
115*477729cfSJeremy L Thompson        err_code = lib.CeedBasisGetNumQuadraturePoints(
116*477729cfSJeremy L Thompson            self._pointer[0], q_pointer)
117*477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
1185a21df39Svaleriabarra
1195a21df39Svaleriabarra        return q_pointer[0]
1205a21df39Svaleriabarra
1215a21df39Svaleriabarra    # Gauss quadrature
1225a21df39Svaleriabarra    @staticmethod
1235a21df39Svaleriabarra    def gauss_quadrature(q):
1245a21df39Svaleriabarra        """Construct a Gauss-Legendre quadrature.
1255a21df39Svaleriabarra
1265a21df39Svaleriabarra           Args:
1275a21df39Svaleriabarra             Q: number of quadrature points (integrates polynomials of
1285a21df39Svaleriabarra                  degree 2*Q-1 exactly)
1295a21df39Svaleriabarra
1305a21df39Svaleriabarra           Returns:
1315a21df39Svaleriabarra             (qref1d, qweight1d): array of length Q to hold the abscissa on [-1, 1]
1325a21df39Svaleriabarra                                    and array of length Q to hold the weights"""
1335a21df39Svaleriabarra
1345a21df39Svaleriabarra        # Setup arguments
1355a21df39Svaleriabarra        qref1d = np.empty(q, dtype="float64")
136fc2a3161SJed Brown        qweight1d = np.empty(q, dtype="float64")
1375a21df39Svaleriabarra
1385a21df39Svaleriabarra        qref1d_pointer = ffi.new("CeedScalar *")
1397a7b0fa3SJed Brown        qref1d_pointer = ffi.cast(
1407a7b0fa3SJed Brown            "CeedScalar *",
1417a7b0fa3SJed Brown            qref1d.__array_interface__['data'][0])
1425a21df39Svaleriabarra
1435a21df39Svaleriabarra        qweight1d_pointer = ffi.new("CeedScalar *")
1447a7b0fa3SJed Brown        qweight1d_pointer = ffi.cast(
1457a7b0fa3SJed Brown            "CeedScalar *",
1467a7b0fa3SJed Brown            qweight1d.__array_interface__['data'][0])
1475a21df39Svaleriabarra
1485a21df39Svaleriabarra        # libCEED call
149*477729cfSJeremy L Thompson        err_code = lib.CeedGaussQuadrature(q, qref1d_pointer, qweight1d_pointer)
150*477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
1515a21df39Svaleriabarra
1525a21df39Svaleriabarra        return qref1d, qweight1d
1535a21df39Svaleriabarra
1545a21df39Svaleriabarra    # Lobatto quadrature
1555a21df39Svaleriabarra    @staticmethod
1565a21df39Svaleriabarra    def lobatto_quadrature(q):
1575a21df39Svaleriabarra        """Construct a Gauss-Legendre-Lobatto quadrature.
1585a21df39Svaleriabarra
1595a21df39Svaleriabarra           Args:
1605a21df39Svaleriabarra             q: number of quadrature points (integrates polynomials of
1615a21df39Svaleriabarra                  degree 2*Q-3 exactly)
1625a21df39Svaleriabarra
1635a21df39Svaleriabarra           Returns:
1645a21df39Svaleriabarra             (qref1d, qweight1d): array of length Q to hold the abscissa on [-1, 1]
1655a21df39Svaleriabarra                                    and array of length Q to hold the weights"""
1665a21df39Svaleriabarra
1675a21df39Svaleriabarra        # Setup arguments
1685a21df39Svaleriabarra        qref1d = np.empty(q, dtype="float64")
1695a21df39Svaleriabarra        qref1d_pointer = ffi.new("CeedScalar *")
1707a7b0fa3SJed Brown        qref1d_pointer = ffi.cast(
1717a7b0fa3SJed Brown            "CeedScalar *",
1727a7b0fa3SJed Brown            qref1d.__array_interface__['data'][0])
1735a21df39Svaleriabarra
174fc2a3161SJed Brown        qweight1d = np.empty(q, dtype="float64")
1755a21df39Svaleriabarra        qweight1d_pointer = ffi.new("CeedScalar *")
1767a7b0fa3SJed Brown        qweight1d_pointer = ffi.cast(
1777a7b0fa3SJed Brown            "CeedScalar *",
1787a7b0fa3SJed Brown            qweight1d.__array_interface__['data'][0])
1795a21df39Svaleriabarra
1805a21df39Svaleriabarra        # libCEED call
181*477729cfSJeremy L Thompson        err_code = lib.CeedLobattoQuadrature(
182*477729cfSJeremy L Thompson            q, qref1d_pointer, qweight1d_pointer)
183*477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
1845a21df39Svaleriabarra
1855a21df39Svaleriabarra        return qref1d, qweight1d
1865a21df39Svaleriabarra
1875a21df39Svaleriabarra    # QR factorization
1885a21df39Svaleriabarra    @staticmethod
1895a21df39Svaleriabarra    def qr_factorization(ceed, mat, tau, m, n):
1905a21df39Svaleriabarra        """Return QR Factorization of a matrix.
1915a21df39Svaleriabarra
1925a21df39Svaleriabarra           Args:
1935a21df39Svaleriabarra             ceed: Ceed context currently in use
1945a21df39Svaleriabarra             *mat: Numpy array holding the row-major matrix to be factorized in place
1955a21df39Svaleriabarra             *tau: Numpy array to hold the vector of lengt m of scaling factors
1965a21df39Svaleriabarra             m: number of rows
1975a21df39Svaleriabarra             n: numbef of columns"""
1985a21df39Svaleriabarra
1995a21df39Svaleriabarra        # Setup arguments
2005a21df39Svaleriabarra        mat_pointer = ffi.new("CeedScalar *")
2017a7b0fa3SJed Brown        mat_pointer = ffi.cast(
2027a7b0fa3SJed Brown            "CeedScalar *",
2037a7b0fa3SJed Brown            mat.__array_interface__['data'][0])
2045a21df39Svaleriabarra
2055a21df39Svaleriabarra        tau_pointer = ffi.new("CeedScalar *")
2067a7b0fa3SJed Brown        tau_pointer = ffi.cast(
2077a7b0fa3SJed Brown            "CeedScalar *",
2087a7b0fa3SJed Brown            tau.__array_interface__['data'][0])
2095a21df39Svaleriabarra
2105a21df39Svaleriabarra        # libCEED call
2117a7b0fa3SJed Brown        lib.CeedQRFactorization(
2127a7b0fa3SJed Brown            ceed._pointer[0], mat_pointer, tau_pointer, m, n)
2135a21df39Svaleriabarra
2145a21df39Svaleriabarra        return mat, tau
2155a21df39Svaleriabarra
2165a21df39Svaleriabarra    # Symmetric Schur decomposition
2175a21df39Svaleriabarra    @staticmethod
2185a21df39Svaleriabarra    def symmetric_schur_decomposition(ceed, mat, n):
2195a21df39Svaleriabarra        """Return symmetric Schur decomposition of a symmetric matrix
2205a21df39Svaleriabarra             via symmetric QR factorization.
2215a21df39Svaleriabarra
2225a21df39Svaleriabarra           Args:
2235a21df39Svaleriabarra             ceed: Ceed context currently in use
2245a21df39Svaleriabarra             *mat: Numpy array holding the row-major matrix to be factorized in place
2255a21df39Svaleriabarra             n: number of rows/columns
2265a21df39Svaleriabarra
2275a21df39Svaleriabarra           Returns:
2285a21df39Svaleriabarra             lbda: Numpy array of length n holding eigenvalues"""
2295a21df39Svaleriabarra
2305a21df39Svaleriabarra        # Setup arguments
2315a21df39Svaleriabarra        mat_pointer = ffi.new("CeedScalar *")
2327a7b0fa3SJed Brown        mat_pointer = ffi.cast(
2337a7b0fa3SJed Brown            "CeedScalar *",
2347a7b0fa3SJed Brown            mat.__array_interface__['data'][0])
2355a21df39Svaleriabarra
2365a21df39Svaleriabarra        lbda = np.empty(n, dtype="float64")
2375a21df39Svaleriabarra        l_pointer = ffi.new("CeedScalar *")
2387a7b0fa3SJed Brown        l_pointer = ffi.cast(
2397a7b0fa3SJed Brown            "CeedScalar *",
2407a7b0fa3SJed Brown            lbda.__array_interface__['data'][0])
2415a21df39Svaleriabarra
2425a21df39Svaleriabarra        # libCEED call
2437a7b0fa3SJed Brown        lib.CeedSymmetricSchurDecomposition(
2447a7b0fa3SJed Brown            ceed._pointer[0], mat_pointer, l_pointer, n)
2455a21df39Svaleriabarra
2465a21df39Svaleriabarra        return lbda
2475a21df39Svaleriabarra
2485a21df39Svaleriabarra    # Simultaneous Diagonalization
2495a21df39Svaleriabarra    @staticmethod
2505a21df39Svaleriabarra    def simultaneous_diagonalization(ceed, matA, matB, n):
2515a21df39Svaleriabarra        """Return Simultaneous Diagonalization of two matrices.
2525a21df39Svaleriabarra
2535a21df39Svaleriabarra           Args:
2545a21df39Svaleriabarra             ceed: Ceed context currently in use
2555a21df39Svaleriabarra             *matA: Numpy array holding the row-major matrix to be factorized with
2565a21df39Svaleriabarra                      eigenvalues
2575a21df39Svaleriabarra             *matB: Numpy array holding the row-major matrix to be factorized to identity
2585a21df39Svaleriabarra             n: number of rows/columns
2595a21df39Svaleriabarra
2605a21df39Svaleriabarra           Returns:
2615a21df39Svaleriabarra             (x, lbda): Numpy array holding the row-major orthogonal matrix and
2625a21df39Svaleriabarra                          Numpy array holding the vector of length n of generalized
2635a21df39Svaleriabarra                          eigenvalues"""
2645a21df39Svaleriabarra
2655a21df39Svaleriabarra        # Setup arguments
2665a21df39Svaleriabarra        matA_pointer = ffi.new("CeedScalar *")
2677a7b0fa3SJed Brown        matA_pointer = ffi.cast(
2687a7b0fa3SJed Brown            "CeedScalar *",
2697a7b0fa3SJed Brown            matA.__array_interface__['data'][0])
2705a21df39Svaleriabarra
2715a21df39Svaleriabarra        matB_pointer = ffi.new("CeedScalar *")
2727a7b0fa3SJed Brown        matB_pointer = ffi.cast(
2737a7b0fa3SJed Brown            "CeedScalar *",
2747a7b0fa3SJed Brown            matB.__array_interface__['data'][0])
2755a21df39Svaleriabarra
2765a21df39Svaleriabarra        lbda = np.empty(n, dtype="float64")
2775a21df39Svaleriabarra        l_pointer = ffi.new("CeedScalar *")
2787a7b0fa3SJed Brown        l_pointer = ffi.cast(
2797a7b0fa3SJed Brown            "CeedScalar *",
2807a7b0fa3SJed Brown            lbda.__array_interface__['data'][0])
2815a21df39Svaleriabarra
2825a21df39Svaleriabarra        x = np.empty(n * n, dtype="float64")
2835a21df39Svaleriabarra        x_pointer = ffi.new("CeedScalar *")
2845a21df39Svaleriabarra        x_pointer = ffi.cast("CeedScalar *", x.__array_interface__['data'][0])
2855a21df39Svaleriabarra
2865a21df39Svaleriabarra        # libCEED call
2875a21df39Svaleriabarra        lib.CeedSimultaneousDiagonalization(ceed._pointer[0], matA_pointer, matB_pointer,
2885a21df39Svaleriabarra                                            x_pointer, l_pointer, n)
2895a21df39Svaleriabarra
2905a21df39Svaleriabarra        return x, lbda
2915a21df39Svaleriabarra
2925a21df39Svaleriabarra    # Destructor
2935a21df39Svaleriabarra    def __del__(self):
2945a21df39Svaleriabarra        # libCEED call
295*477729cfSJeremy L Thompson        err_code = lib.CeedBasisDestroy(self._pointer)
296*477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
2975a21df39Svaleriabarra
2985a21df39Svaleriabarra# ------------------------------------------------------------------------------
2997a7b0fa3SJed Brown
3007a7b0fa3SJed Brown
3015a21df39Svaleriabarraclass BasisTensorH1(Basis):
3025a21df39Svaleriabarra    """Ceed Tensor H1 Basis: finite element tensor-product basis objects for
3035a21df39Svaleriabarra         H^1 discretizations."""
3045a21df39Svaleriabarra
3055a21df39Svaleriabarra    # Constructor
3065a21df39Svaleriabarra    def __init__(self, ceed, dim, ncomp, P1d, Q1d, interp1d, grad1d,
3075a21df39Svaleriabarra                 qref1d, qweight1d):
3085a21df39Svaleriabarra
3095a21df39Svaleriabarra        # Setup arguments
3105a21df39Svaleriabarra        self._pointer = ffi.new("CeedBasis *")
3115a21df39Svaleriabarra
3125a21df39Svaleriabarra        self._ceed = ceed
3135a21df39Svaleriabarra
3145a21df39Svaleriabarra        interp1d_pointer = ffi.new("CeedScalar *")
3157a7b0fa3SJed Brown        interp1d_pointer = ffi.cast(
3167a7b0fa3SJed Brown            "CeedScalar *",
3177a7b0fa3SJed Brown            interp1d.__array_interface__['data'][0])
3185a21df39Svaleriabarra
3195a21df39Svaleriabarra        grad1d_pointer = ffi.new("CeedScalar *")
3207a7b0fa3SJed Brown        grad1d_pointer = ffi.cast(
3217a7b0fa3SJed Brown            "CeedScalar *",
3227a7b0fa3SJed Brown            grad1d.__array_interface__['data'][0])
3235a21df39Svaleriabarra
3245a21df39Svaleriabarra        qref1d_pointer = ffi.new("CeedScalar *")
3257a7b0fa3SJed Brown        qref1d_pointer = ffi.cast(
3267a7b0fa3SJed Brown            "CeedScalar *",
3277a7b0fa3SJed Brown            qref1d.__array_interface__['data'][0])
3285a21df39Svaleriabarra
3295a21df39Svaleriabarra        qweight1d_pointer = ffi.new("CeedScalar *")
3307a7b0fa3SJed Brown        qweight1d_pointer = ffi.cast(
3317a7b0fa3SJed Brown            "CeedScalar *",
3327a7b0fa3SJed Brown            qweight1d.__array_interface__['data'][0])
3335a21df39Svaleriabarra
3345a21df39Svaleriabarra        # libCEED call
335*477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateTensorH1(self._ceed._pointer[0], dim, ncomp,
336*477729cfSJeremy L Thompson                                               P1d, Q1d, interp1d_pointer,
337*477729cfSJeremy L Thompson                                               grad1d_pointer, qref1d_pointer,
3385a21df39Svaleriabarra                                               qweight1d_pointer, self._pointer)
339*477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
3405a21df39Svaleriabarra
3415a21df39Svaleriabarra# ------------------------------------------------------------------------------
3427a7b0fa3SJed Brown
3437a7b0fa3SJed Brown
3445a21df39Svaleriabarraclass BasisTensorH1Lagrange(Basis):
3455a21df39Svaleriabarra    """Ceed Tensor H1 Lagrange Basis: finite element tensor-product Lagrange basis
3465a21df39Svaleriabarra         objects for H^1 discretizations."""
3475a21df39Svaleriabarra
3485a21df39Svaleriabarra    # Constructor
3495a21df39Svaleriabarra    def __init__(self, ceed, dim, ncomp, P, Q, qmode):
3505a21df39Svaleriabarra
3515a21df39Svaleriabarra        # Setup arguments
3525a21df39Svaleriabarra        self._pointer = ffi.new("CeedBasis *")
3535a21df39Svaleriabarra
3545a21df39Svaleriabarra        self._ceed = ceed
3555a21df39Svaleriabarra
3565a21df39Svaleriabarra        # libCEED call
357*477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateTensorH1Lagrange(self._ceed._pointer[0], dim,
358*477729cfSJeremy L Thompson                                                       ncomp, P, Q, qmode, self._pointer)
359*477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
3605a21df39Svaleriabarra
3615a21df39Svaleriabarra# ------------------------------------------------------------------------------
3627a7b0fa3SJed Brown
3637a7b0fa3SJed Brown
3645a21df39Svaleriabarraclass BasisH1(Basis):
3655a21df39Svaleriabarra    """Ceed H1 Basis: finite element non tensor-product basis for H^1 discretizations."""
3665a21df39Svaleriabarra
3675a21df39Svaleriabarra    # Constructor
3687a7b0fa3SJed Brown    def __init__(self, ceed, topo, ncomp, nnodes,
3697a7b0fa3SJed Brown                 nqpts, interp, grad, qref, qweight):
3705a21df39Svaleriabarra
3715a21df39Svaleriabarra        # Setup arguments
3725a21df39Svaleriabarra        self._pointer = ffi.new("CeedBasis *")
3735a21df39Svaleriabarra
3745a21df39Svaleriabarra        self._ceed = ceed
3755a21df39Svaleriabarra
3765a21df39Svaleriabarra        interp_pointer = ffi.new("CeedScalar *")
3777a7b0fa3SJed Brown        interp_pointer = ffi.cast(
3787a7b0fa3SJed Brown            "CeedScalar *",
3797a7b0fa3SJed Brown            interp.__array_interface__['data'][0])
3805a21df39Svaleriabarra
3815a21df39Svaleriabarra        grad_pointer = ffi.new("CeedScalar *")
3827a7b0fa3SJed Brown        grad_pointer = ffi.cast(
3837a7b0fa3SJed Brown            "CeedScalar *",
3847a7b0fa3SJed Brown            grad.__array_interface__['data'][0])
3855a21df39Svaleriabarra
3865a21df39Svaleriabarra        qref_pointer = ffi.new("CeedScalar *")
3877a7b0fa3SJed Brown        qref_pointer = ffi.cast(
3887a7b0fa3SJed Brown            "CeedScalar *",
3897a7b0fa3SJed Brown            qref.__array_interface__['data'][0])
3905a21df39Svaleriabarra
3915a21df39Svaleriabarra        qweight_pointer = ffi.new("CeedScalar *")
3927a7b0fa3SJed Brown        qweight_pointer = ffi.cast(
3937a7b0fa3SJed Brown            "CeedScalar *",
3947a7b0fa3SJed Brown            qweight.__array_interface__['data'][0])
3955a21df39Svaleriabarra
3965a21df39Svaleriabarra        # libCEED call
397*477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateH1(self._ceed._pointer[0], topo, ncomp,
398*477729cfSJeremy L Thompson                                         nnodes, nqpts, interp_pointer,
399*477729cfSJeremy L Thompson                                         grad_pointer, qref_pointer,
4005a21df39Svaleriabarra                                         qweight_pointer, self._pointer)
4015a21df39Svaleriabarra
4025a21df39Svaleriabarra# ------------------------------------------------------------------------------
4037a7b0fa3SJed Brown
4047a7b0fa3SJed Brown
4055a21df39Svaleriabarraclass TransposeBasis():
4065a21df39Svaleriabarra    """Transpose Ceed Basis: transpose of finite element tensor-product basis objects."""
4075a21df39Svaleriabarra
4085a21df39Svaleriabarra    # Attributes
4095a21df39Svaleriabarra    _basis = None
4105a21df39Svaleriabarra
4115a21df39Svaleriabarra    # Constructor
4125a21df39Svaleriabarra    def __init__(self, basis):
4135a21df39Svaleriabarra
4145a21df39Svaleriabarra        # Reference basis
4155a21df39Svaleriabarra        self._basis = basis
4165a21df39Svaleriabarra
4175a21df39Svaleriabarra    # Representation
4185a21df39Svaleriabarra    def __repr__(self):
4195a21df39Svaleriabarra        return "<Transpose CeedBasis instance at " + hex(id(self)) + ">"
4205a21df39Svaleriabarra
4215a21df39Svaleriabarra    # Apply Transpose Basis
4225a21df39Svaleriabarra    def apply(self, nelem, emode, u, v):
4235a21df39Svaleriabarra        """Apply basis evaluation from quadrature points to nodes.
4245a21df39Svaleriabarra
4255a21df39Svaleriabarra           Args:
4265a21df39Svaleriabarra             nelem: the number of elements to apply the basis evaluation to;
4275a21df39Svaleriabarra                      the backend will specify the ordering in a
4285a21df39Svaleriabarra                      Blocked ElemRestriction
4295a21df39Svaleriabarra             **emode: basis evaluation mode
4305a21df39Svaleriabarra             u: input vector
4315a21df39Svaleriabarra             v: output vector"""
4325a21df39Svaleriabarra
4335a21df39Svaleriabarra        # libCEED call
4345a21df39Svaleriabarra        self._basis.apply(nelem, emode, u, v, tmode=TRANSPOSE)
4355a21df39Svaleriabarra
4365a21df39Svaleriabarra# ------------------------------------------------------------------------------
437