xref: /libCEED/python/ceed_basis.py (revision d99fa3c5cd91a1690aedf0679cbf290d44fec74c)
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
46477729cfSJeremy L Thompson                err_code = lib.CeedBasisView(self._pointer[0], stream)
47477729cfSJeremy 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
70477729cfSJeremy L Thompson        err_code = lib.CeedBasisApply(self._pointer[0], nelem, tmode, emode,
715a21df39Svaleriabarra                                      u._pointer[0], v._pointer[0])
72477729cfSJeremy 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
99477729cfSJeremy L Thompson        err_code = lib.CeedBasisGetNumNodes(self._pointer[0], p_pointer)
100477729cfSJeremy 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
115477729cfSJeremy L Thompson        err_code = lib.CeedBasisGetNumQuadraturePoints(
116477729cfSJeremy L Thompson            self._pointer[0], q_pointer)
117477729cfSJeremy 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
149477729cfSJeremy L Thompson        err_code = lib.CeedGaussQuadrature(q, qref1d_pointer, qweight1d_pointer)
150477729cfSJeremy 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
181477729cfSJeremy L Thompson        err_code = lib.CeedLobattoQuadrature(
182477729cfSJeremy L Thompson            q, qref1d_pointer, qweight1d_pointer)
183477729cfSJeremy 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
295477729cfSJeremy L Thompson        err_code = lib.CeedBasisDestroy(self._pointer)
296477729cfSJeremy 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
335477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateTensorH1(self._ceed._pointer[0], dim, ncomp,
336477729cfSJeremy L Thompson                                               P1d, Q1d, interp1d_pointer,
337477729cfSJeremy L Thompson                                               grad1d_pointer, qref1d_pointer,
3385a21df39Svaleriabarra                                               qweight1d_pointer, self._pointer)
339477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
3405a21df39Svaleriabarra
341*d99fa3c5SJeremy L Thompson    #
342*d99fa3c5SJeremy L Thompson    def get_interp1d(self):
343*d99fa3c5SJeremy L Thompson        """Return 1D interpolation matrix of a tensor product Basis.
344*d99fa3c5SJeremy L Thompson
345*d99fa3c5SJeremy L Thompson           Returns:
346*d99fa3c5SJeremy L Thompson             *array: Numpy array"""
347*d99fa3c5SJeremy L Thompson
348*d99fa3c5SJeremy L Thompson        # Compute the length of the array
349*d99fa3c5SJeremy L Thompson        nnodes_pointer = ffi.new("CeedInt *")
350*d99fa3c5SJeremy L Thompson        lib.CeedBasisGetNumNodes1D(self._pointer[0], nnodes_pointer)
351*d99fa3c5SJeremy L Thompson        nqpts_pointer = ffi.new("CeedInt *")
352*d99fa3c5SJeremy L Thompson        lib.CeedBasisGetNumQuadraturePoints1D(self._pointer[0], nqpts_pointer)
353*d99fa3c5SJeremy L Thompson        length = nnodes_pointer[0] * nqpts_pointer[0]
354*d99fa3c5SJeremy L Thompson
355*d99fa3c5SJeremy L Thompson        # Setup the pointer's pointer
356*d99fa3c5SJeremy L Thompson        array_pointer = ffi.new("CeedScalar **")
357*d99fa3c5SJeremy L Thompson
358*d99fa3c5SJeremy L Thompson        # libCEED call
359*d99fa3c5SJeremy L Thompson        lib.CeedBasisGetInterp1D(self._pointer[0], array_pointer)
360*d99fa3c5SJeremy L Thompson
361*d99fa3c5SJeremy L Thompson        # Return array created from buffer
362*d99fa3c5SJeremy L Thompson        # Create buffer object from returned pointer
363*d99fa3c5SJeremy L Thompson        buff = ffi.buffer(
364*d99fa3c5SJeremy L Thompson            array_pointer[0],
365*d99fa3c5SJeremy L Thompson            ffi.sizeof("CeedScalar") *
366*d99fa3c5SJeremy L Thompson            length)
367*d99fa3c5SJeremy L Thompson        # return read only Numpy array
368*d99fa3c5SJeremy L Thompson        ret = np.frombuffer(buff, dtype="float64")
369*d99fa3c5SJeremy L Thompson        ret.flags['WRITEABLE'] = False
370*d99fa3c5SJeremy L Thompson        return ret
371*d99fa3c5SJeremy L Thompson
372*d99fa3c5SJeremy L Thompson
3735a21df39Svaleriabarra# ------------------------------------------------------------------------------
3747a7b0fa3SJed Brown
3757a7b0fa3SJed Brown
376*d99fa3c5SJeremy L Thompsonclass BasisTensorH1Lagrange(BasisTensorH1):
3775a21df39Svaleriabarra    """Ceed Tensor H1 Lagrange Basis: finite element tensor-product Lagrange basis
3785a21df39Svaleriabarra         objects for H^1 discretizations."""
3795a21df39Svaleriabarra
3805a21df39Svaleriabarra    # Constructor
3815a21df39Svaleriabarra    def __init__(self, ceed, dim, ncomp, P, Q, qmode):
3825a21df39Svaleriabarra
3835a21df39Svaleriabarra        # Setup arguments
3845a21df39Svaleriabarra        self._pointer = ffi.new("CeedBasis *")
3855a21df39Svaleriabarra
3865a21df39Svaleriabarra        self._ceed = ceed
3875a21df39Svaleriabarra
3885a21df39Svaleriabarra        # libCEED call
389477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateTensorH1Lagrange(self._ceed._pointer[0], dim,
390477729cfSJeremy L Thompson                                                       ncomp, P, Q, qmode, self._pointer)
391477729cfSJeremy L Thompson        self._ceed._check_error(err_code)
3925a21df39Svaleriabarra
3935a21df39Svaleriabarra# ------------------------------------------------------------------------------
3947a7b0fa3SJed Brown
3957a7b0fa3SJed Brown
3965a21df39Svaleriabarraclass BasisH1(Basis):
3975a21df39Svaleriabarra    """Ceed H1 Basis: finite element non tensor-product basis for H^1 discretizations."""
3985a21df39Svaleriabarra
3995a21df39Svaleriabarra    # Constructor
4007a7b0fa3SJed Brown    def __init__(self, ceed, topo, ncomp, nnodes,
4017a7b0fa3SJed Brown                 nqpts, interp, grad, qref, qweight):
4025a21df39Svaleriabarra
4035a21df39Svaleriabarra        # Setup arguments
4045a21df39Svaleriabarra        self._pointer = ffi.new("CeedBasis *")
4055a21df39Svaleriabarra
4065a21df39Svaleriabarra        self._ceed = ceed
4075a21df39Svaleriabarra
4085a21df39Svaleriabarra        interp_pointer = ffi.new("CeedScalar *")
4097a7b0fa3SJed Brown        interp_pointer = ffi.cast(
4107a7b0fa3SJed Brown            "CeedScalar *",
4117a7b0fa3SJed Brown            interp.__array_interface__['data'][0])
4125a21df39Svaleriabarra
4135a21df39Svaleriabarra        grad_pointer = ffi.new("CeedScalar *")
4147a7b0fa3SJed Brown        grad_pointer = ffi.cast(
4157a7b0fa3SJed Brown            "CeedScalar *",
4167a7b0fa3SJed Brown            grad.__array_interface__['data'][0])
4175a21df39Svaleriabarra
4185a21df39Svaleriabarra        qref_pointer = ffi.new("CeedScalar *")
4197a7b0fa3SJed Brown        qref_pointer = ffi.cast(
4207a7b0fa3SJed Brown            "CeedScalar *",
4217a7b0fa3SJed Brown            qref.__array_interface__['data'][0])
4225a21df39Svaleriabarra
4235a21df39Svaleriabarra        qweight_pointer = ffi.new("CeedScalar *")
4247a7b0fa3SJed Brown        qweight_pointer = ffi.cast(
4257a7b0fa3SJed Brown            "CeedScalar *",
4267a7b0fa3SJed Brown            qweight.__array_interface__['data'][0])
4275a21df39Svaleriabarra
4285a21df39Svaleriabarra        # libCEED call
429477729cfSJeremy L Thompson        err_code = lib.CeedBasisCreateH1(self._ceed._pointer[0], topo, ncomp,
430477729cfSJeremy L Thompson                                         nnodes, nqpts, interp_pointer,
431477729cfSJeremy L Thompson                                         grad_pointer, qref_pointer,
4325a21df39Svaleriabarra                                         qweight_pointer, self._pointer)
4335a21df39Svaleriabarra
4345a21df39Svaleriabarra# ------------------------------------------------------------------------------
4357a7b0fa3SJed Brown
4367a7b0fa3SJed Brown
4375a21df39Svaleriabarraclass TransposeBasis():
4385a21df39Svaleriabarra    """Transpose Ceed Basis: transpose of finite element tensor-product basis objects."""
4395a21df39Svaleriabarra
4405a21df39Svaleriabarra    # Attributes
4415a21df39Svaleriabarra    _basis = None
4425a21df39Svaleriabarra
4435a21df39Svaleriabarra    # Constructor
4445a21df39Svaleriabarra    def __init__(self, basis):
4455a21df39Svaleriabarra
4465a21df39Svaleriabarra        # Reference basis
4475a21df39Svaleriabarra        self._basis = basis
4485a21df39Svaleriabarra
4495a21df39Svaleriabarra    # Representation
4505a21df39Svaleriabarra    def __repr__(self):
4515a21df39Svaleriabarra        return "<Transpose CeedBasis instance at " + hex(id(self)) + ">"
4525a21df39Svaleriabarra
4535a21df39Svaleriabarra    # Apply Transpose Basis
4545a21df39Svaleriabarra    def apply(self, nelem, emode, u, v):
4555a21df39Svaleriabarra        """Apply basis evaluation from quadrature points to nodes.
4565a21df39Svaleriabarra
4575a21df39Svaleriabarra           Args:
4585a21df39Svaleriabarra             nelem: the number of elements to apply the basis evaluation to;
4595a21df39Svaleriabarra                      the backend will specify the ordering in a
4605a21df39Svaleriabarra                      Blocked ElemRestriction
4615a21df39Svaleriabarra             **emode: basis evaluation mode
4625a21df39Svaleriabarra             u: input vector
4635a21df39Svaleriabarra             v: output vector"""
4645a21df39Svaleriabarra
4655a21df39Svaleriabarra        # libCEED call
4665a21df39Svaleriabarra        self._basis.apply(nelem, emode, u, v, tmode=TRANSPOSE)
4675a21df39Svaleriabarra
4685a21df39Svaleriabarra# ------------------------------------------------------------------------------
469