xref: /libCEED/python/ceed_vector.py (revision 7f1dc7b91d4f5ca67db10df8f4f0b60afe166f53)
17def3d77Svaleriabarra# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
27def3d77Svaleriabarra# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
37def3d77Svaleriabarra# reserved. See files LICENSE and NOTICE for details.
47def3d77Svaleriabarra#
57def3d77Svaleriabarra# This file is part of CEED, a collection of benchmarks, miniapps, software
67def3d77Svaleriabarra# libraries and APIs for efficient high-order finite element and spectral
77def3d77Svaleriabarra# element discretizations for exascale applications. For more information and
87def3d77Svaleriabarra# source code availability see http://github.com/ceed.
97def3d77Svaleriabarra#
107def3d77Svaleriabarra# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
117def3d77Svaleriabarra# a collaborative effort of two U.S. Department of Energy organizations (Office
127def3d77Svaleriabarra# of Science and the National Nuclear Security Administration) responsible for
137def3d77Svaleriabarra# the planning and preparation of a capable exascale ecosystem, including
147def3d77Svaleriabarra# software, applications, hardware, advanced system engineering and early
157def3d77Svaleriabarra# testbed platforms, in support of the nation's exascale computing imperative.
167def3d77Svaleriabarra
177def3d77Svaleriabarrafrom _ceed_cffi import ffi, lib
187def3d77Svaleriabarraimport tempfile
197def3d77Svaleriabarraimport numpy as np
20*7f1dc7b9SJeremy L Thompsonimport numba.cuda as nbcuda
21e259ae81SJed Brownimport contextlib
22547d9b97Sjeremyltfrom .ceed_constants import MEM_HOST, COPY_VALUES, NORM_2
237def3d77Svaleriabarra
247def3d77Svaleriabarra# ------------------------------------------------------------------------------
257a7b0fa3SJed Brown
267a7b0fa3SJed Brown
277def3d77Svaleriabarraclass Vector():
287def3d77Svaleriabarra    """Ceed Vector: storing and manipulating vectors."""
297def3d77Svaleriabarra
307def3d77Svaleriabarra    # Attributes
317def3d77Svaleriabarra    _ceed = ffi.NULL
327def3d77Svaleriabarra    _pointer = ffi.NULL
337def3d77Svaleriabarra
347def3d77Svaleriabarra    # Constructor
357def3d77Svaleriabarra    def __init__(self, ceed, size):
367def3d77Svaleriabarra        # CeedVector object
377def3d77Svaleriabarra        self._pointer = ffi.new("CeedVector *")
387def3d77Svaleriabarra
397def3d77Svaleriabarra        # Reference to Ceed
407def3d77Svaleriabarra        self._ceed = ceed
417def3d77Svaleriabarra
427def3d77Svaleriabarra        # libCEED call
437def3d77Svaleriabarra        lib.CeedVectorCreate(self._ceed._pointer[0], size, self._pointer)
447def3d77Svaleriabarra
457def3d77Svaleriabarra    # Destructor
467def3d77Svaleriabarra    def __del__(self):
477def3d77Svaleriabarra        # libCEED call
487def3d77Svaleriabarra        lib.CeedVectorDestroy(self._pointer)
497def3d77Svaleriabarra
507def3d77Svaleriabarra    # Representation
517def3d77Svaleriabarra    def __repr__(self):
527def3d77Svaleriabarra        return "<CeedVector instance at " + hex(id(self)) + ">"
537def3d77Svaleriabarra
547def3d77Svaleriabarra    # String conversion for print() to stdout
557def3d77Svaleriabarra    def __str__(self):
567def3d77Svaleriabarra        """View a Vector via print()."""
577def3d77Svaleriabarra
587def3d77Svaleriabarra        # libCEED call
597def3d77Svaleriabarra        fmt = ffi.new("char[]", "%f".encode('ascii'))
607def3d77Svaleriabarra        with tempfile.NamedTemporaryFile() as key_file:
617def3d77Svaleriabarra            with open(key_file.name, 'r+') as stream_file:
627def3d77Svaleriabarra                stream = ffi.cast("FILE *", stream_file)
637def3d77Svaleriabarra
647def3d77Svaleriabarra                lib.CeedVectorView(self._pointer[0], fmt, stream)
657def3d77Svaleriabarra
667def3d77Svaleriabarra                stream_file.seek(0)
677def3d77Svaleriabarra                out_string = stream_file.read()
687def3d77Svaleriabarra
697def3d77Svaleriabarra        return out_string
707def3d77Svaleriabarra
717def3d77Svaleriabarra    # Set Vector's data array
727def3d77Svaleriabarra    def set_array(self, array, memtype=MEM_HOST, cmode=COPY_VALUES):
737def3d77Svaleriabarra        """Set the array used by a Vector, freeing any previously allocated
747def3d77Svaleriabarra           array if applicable.
757def3d77Svaleriabarra
767def3d77Svaleriabarra           Args:
77*7f1dc7b9SJeremy L Thompson             *array: Numpy or Numba array to be used
787def3d77Svaleriabarra             **memtype: memory type of the array being passed, default CEED_MEM_HOST
797def3d77Svaleriabarra             **cmode: copy mode for the array, default CEED_COPY_VALUES"""
807def3d77Svaleriabarra
817def3d77Svaleriabarra        # Setup the numpy array for the libCEED call
827def3d77Svaleriabarra        array_pointer = ffi.new("CeedScalar *")
83*7f1dc7b9SJeremy L Thompson        if memtype == MEM_HOST:
847a7b0fa3SJed Brown            array_pointer = ffi.cast(
857a7b0fa3SJed Brown                "CeedScalar *",
867a7b0fa3SJed Brown                array.__array_interface__['data'][0])
87*7f1dc7b9SJeremy L Thompson        else:
88*7f1dc7b9SJeremy L Thompson            array_pointer = ffi.cast(
89*7f1dc7b9SJeremy L Thompson                "CeedScalar *",
90*7f1dc7b9SJeremy L Thompson                array.__cuda_array_interface__['data'][0])
917def3d77Svaleriabarra
927def3d77Svaleriabarra        # libCEED call
937def3d77Svaleriabarra        lib.CeedVectorSetArray(self._pointer[0], memtype, cmode, array_pointer)
947def3d77Svaleriabarra
957def3d77Svaleriabarra    # Get Vector's data array
967def3d77Svaleriabarra    def get_array(self, memtype=MEM_HOST):
977def3d77Svaleriabarra        """Get read/write access to a Vector via the specified memory type.
987def3d77Svaleriabarra
997def3d77Svaleriabarra           Args:
1007def3d77Svaleriabarra             **memtype: memory type of the array being passed, default CEED_MEM_HOST
1017def3d77Svaleriabarra
1027def3d77Svaleriabarra           Returns:
103*7f1dc7b9SJeremy L Thompson             *array: Numpy or Numba array"""
1047def3d77Svaleriabarra
1057def3d77Svaleriabarra        # Retrieve the length of the array
1067def3d77Svaleriabarra        length_pointer = ffi.new("CeedInt *")
1077def3d77Svaleriabarra        lib.CeedVectorGetLength(self._pointer[0], length_pointer)
1087def3d77Svaleriabarra
1097def3d77Svaleriabarra        # Setup the pointer's pointer
1107def3d77Svaleriabarra        array_pointer = ffi.new("CeedScalar **")
1117def3d77Svaleriabarra
1127def3d77Svaleriabarra        # libCEED call
1137def3d77Svaleriabarra        lib.CeedVectorGetArray(self._pointer[0], memtype, array_pointer)
1147def3d77Svaleriabarra
115*7f1dc7b9SJeremy L Thompson        # Return array created from buffer
116*7f1dc7b9SJeremy L Thompson        if memtype == MEM_HOST:
1177def3d77Svaleriabarra            # Create buffer object from returned pointer
1187a7b0fa3SJed Brown            buff = ffi.buffer(
1197a7b0fa3SJed Brown                array_pointer[0],
1207a7b0fa3SJed Brown                ffi.sizeof("CeedScalar") *
1217a7b0fa3SJed Brown                length_pointer[0])
122*7f1dc7b9SJeremy L Thompson            # return Numpy array
1237def3d77Svaleriabarra            return np.frombuffer(buff, dtype="float64")
124*7f1dc7b9SJeremy L Thompson        else:
125*7f1dc7b9SJeremy L Thompson            # CUDA array interface
126*7f1dc7b9SJeremy L Thompson            # https://numba.pydata.org/numba-doc/latest/cuda/cuda_array_interface.html
127*7f1dc7b9SJeremy L Thompson            desc = {
128*7f1dc7b9SJeremy L Thompson                'shape': (length_pointer[0]),
129*7f1dc7b9SJeremy L Thompson                'typestr': '>f8',
130*7f1dc7b9SJeremy L Thompson                'data': (int(ffi.cast("intptr_t", array_pointer[0])), False),
131*7f1dc7b9SJeremy L Thompson                'version': 2
132*7f1dc7b9SJeremy L Thompson            }
133*7f1dc7b9SJeremy L Thompson            # return Numba array
134*7f1dc7b9SJeremy L Thompson            return nbcuda.from_cuda_array_interface(desc)
1357def3d77Svaleriabarra
1367def3d77Svaleriabarra    # Get Vector's data array in read-only mode
1377def3d77Svaleriabarra    def get_array_read(self, memtype=MEM_HOST):
1387def3d77Svaleriabarra        """Get read-only access to a Vector via the specified memory type.
1397def3d77Svaleriabarra
1407def3d77Svaleriabarra           Args:
1417def3d77Svaleriabarra             **memtype: memory type of the array being passed, default CEED_MEM_HOST
1427def3d77Svaleriabarra
1437def3d77Svaleriabarra           Returns:
144*7f1dc7b9SJeremy L Thompson             *array: Numpy or Numba array"""
1457def3d77Svaleriabarra
1467def3d77Svaleriabarra        # Retrieve the length of the array
1477def3d77Svaleriabarra        length_pointer = ffi.new("CeedInt *")
1487def3d77Svaleriabarra        lib.CeedVectorGetLength(self._pointer[0], length_pointer)
1497def3d77Svaleriabarra
1507def3d77Svaleriabarra        # Setup the pointer's pointer
1517def3d77Svaleriabarra        array_pointer = ffi.new("CeedScalar **")
1527def3d77Svaleriabarra
1537def3d77Svaleriabarra        # libCEED call
1547def3d77Svaleriabarra        lib.CeedVectorGetArrayRead(self._pointer[0], memtype, array_pointer)
1557def3d77Svaleriabarra
156*7f1dc7b9SJeremy L Thompson        # Return array created from buffer
157*7f1dc7b9SJeremy L Thompson        if memtype == MEM_HOST:
1587def3d77Svaleriabarra            # Create buffer object from returned pointer
1597a7b0fa3SJed Brown            buff = ffi.buffer(
1607a7b0fa3SJed Brown                array_pointer[0],
1617a7b0fa3SJed Brown                ffi.sizeof("CeedScalar") *
1627a7b0fa3SJed Brown                length_pointer[0])
163*7f1dc7b9SJeremy L Thompson            # return read only Numpy array
1647def3d77Svaleriabarra            ret = np.frombuffer(buff, dtype="float64")
1657def3d77Svaleriabarra            ret.flags['WRITEABLE'] = False
1667def3d77Svaleriabarra            return ret
167*7f1dc7b9SJeremy L Thompson        else:
168*7f1dc7b9SJeremy L Thompson            # CUDA array interface
169*7f1dc7b9SJeremy L Thompson            # https://numba.pydata.org/numba-doc/latest/cuda/cuda_array_interface.html
170*7f1dc7b9SJeremy L Thompson            desc = {
171*7f1dc7b9SJeremy L Thompson                'shape': (length_pointer[0]),
172*7f1dc7b9SJeremy L Thompson                'typestr': '>f8',
173*7f1dc7b9SJeremy L Thompson                'data': (int(ffi.cast("intptr_t", array_pointer[0])), False),
174*7f1dc7b9SJeremy L Thompson                'version': 2
175*7f1dc7b9SJeremy L Thompson            }
176*7f1dc7b9SJeremy L Thompson            # return read only Numba array
177*7f1dc7b9SJeremy L Thompson            return nbcuda.from_cuda_array_interface(desc)
1787def3d77Svaleriabarra
1797def3d77Svaleriabarra    # Restore the Vector's data array
1807def3d77Svaleriabarra    def restore_array(self):
1817def3d77Svaleriabarra        """Restore an array obtained using get_array()."""
1827def3d77Svaleriabarra
1837def3d77Svaleriabarra        # Setup the pointer's pointer
1847def3d77Svaleriabarra        array_pointer = ffi.new("CeedScalar **")
1857def3d77Svaleriabarra
1867def3d77Svaleriabarra        # libCEED call
1877def3d77Svaleriabarra        lib.CeedVectorRestoreArray(self._pointer[0], array_pointer)
1887def3d77Svaleriabarra
1897def3d77Svaleriabarra    # Restore an array obtained using getArrayRead
1907def3d77Svaleriabarra    def restore_array_read(self):
1917def3d77Svaleriabarra        """Restore an array obtained using get_array_read()."""
1927def3d77Svaleriabarra
1937def3d77Svaleriabarra        # Setup the pointer's pointer
1947def3d77Svaleriabarra        array_pointer = ffi.new("CeedScalar **")
1957def3d77Svaleriabarra
1967def3d77Svaleriabarra        # libCEED call
1977def3d77Svaleriabarra        lib.CeedVectorRestoreArrayRead(self._pointer[0], array_pointer)
1987def3d77Svaleriabarra
199e259ae81SJed Brown    @contextlib.contextmanager
200*7f1dc7b9SJeremy L Thompson    def array(self, *shape, memtype=MEM_HOST):
201e259ae81SJed Brown        """Context manager for array access.
202e259ae81SJed Brown
203e259ae81SJed Brown        Args:
204e259ae81SJed Brown          shape (tuple): shape of returned numpy.array
205*7f1dc7b9SJeremy L Thompson          **memtype: memory type of the array being passed, default CEED_MEM_HOST
206*7f1dc7b9SJeremy L Thompson
207e259ae81SJed Brown
208e259ae81SJed Brown        Returns:
209e259ae81SJed Brown          np.array: writable view of vector
210e259ae81SJed Brown
211e259ae81SJed Brown        Examples:
212e259ae81SJed Brown          Constructing the identity inside a libceed.Vector:
213e259ae81SJed Brown
214e259ae81SJed Brown          >>> vec = ceed.Vector(16)
215e259ae81SJed Brown          >>> with vec.array(4, 4) as x:
216e259ae81SJed Brown          >>>     x[...] = np.eye(4)
217e259ae81SJed Brown        """
218*7f1dc7b9SJeremy L Thompson        x = self.get_array(memtype=memtype)
219e259ae81SJed Brown        if shape:
220e259ae81SJed Brown            x = x.reshape(shape)
221e259ae81SJed Brown        yield x
222e259ae81SJed Brown        self.restore_array()
223e259ae81SJed Brown
224e259ae81SJed Brown    @contextlib.contextmanager
225*7f1dc7b9SJeremy L Thompson    def array_read(self, *shape, memtype=MEM_HOST):
226e259ae81SJed Brown        """Context manager for read-only array access.
227e259ae81SJed Brown
228e259ae81SJed Brown        Args:
229e259ae81SJed Brown          shape (tuple): shape of returned numpy.array
230*7f1dc7b9SJeremy L Thompson          **memtype: memory type of the array being passed, default CEED_MEM_HOST
231e259ae81SJed Brown
232e259ae81SJed Brown        Returns:
233e259ae81SJed Brown          np.array: read-only view of vector
234e259ae81SJed Brown
235e259ae81SJed Brown        Examples:
236e259ae81SJed Brown          Constructing the identity inside a libceed.Vector:
237e259ae81SJed Brown
238e259ae81SJed Brown          >>> vec = ceed.Vector(6)
239e259ae81SJed Brown          >>> vec.set_value(1.3)
240e259ae81SJed Brown          >>> with vec.array_read(2, 3) as x:
241e259ae81SJed Brown          >>>     print(x)
242e259ae81SJed Brown        """
243*7f1dc7b9SJeremy L Thompson        x = self.get_array_read(memtype=memtype)
244e259ae81SJed Brown        if shape:
245e259ae81SJed Brown            x = x.reshape(shape)
246e259ae81SJed Brown        yield x
247e259ae81SJed Brown        self.restore_array_read()
248e259ae81SJed Brown
2497def3d77Svaleriabarra    # Get the length of a Vector
2507def3d77Svaleriabarra    def get_length(self):
2517def3d77Svaleriabarra        """Get the length of a Vector.
2527def3d77Svaleriabarra
2537def3d77Svaleriabarra           Returns:
2547def3d77Svaleriabarra             length: length of the Vector"""
2557def3d77Svaleriabarra
2567def3d77Svaleriabarra        length_pointer = ffi.new("CeedInt *")
2577def3d77Svaleriabarra
2587def3d77Svaleriabarra        # libCEED call
2597def3d77Svaleriabarra        lib.CeedVectorGetLength(self._pointer[0], length_pointer)
2607def3d77Svaleriabarra
2617def3d77Svaleriabarra        return length_pointer[0]
2627def3d77Svaleriabarra
2637def3d77Svaleriabarra    # Get the length of a Vector
2647def3d77Svaleriabarra    def __len__(self):
2657def3d77Svaleriabarra        """Get the length of a Vector.
2667def3d77Svaleriabarra
2677def3d77Svaleriabarra           Returns:
2687def3d77Svaleriabarra             length: length of the Vector"""
2697def3d77Svaleriabarra
2707def3d77Svaleriabarra        length_pointer = ffi.new("CeedInt *")
2717def3d77Svaleriabarra
2727def3d77Svaleriabarra        # libCEED call
2737def3d77Svaleriabarra        lib.CeedVectorGetLength(self._pointer[0], length_pointer)
2747def3d77Svaleriabarra
2757def3d77Svaleriabarra        return length_pointer[0]
2767def3d77Svaleriabarra
2777def3d77Svaleriabarra    # Set the Vector to a given constant value
2787def3d77Svaleriabarra    def set_value(self, value):
2797def3d77Svaleriabarra        """Set the Vector to a constant value.
2807def3d77Svaleriabarra
2817def3d77Svaleriabarra           Args:
2827def3d77Svaleriabarra             value: value to be used"""
2837def3d77Svaleriabarra
2847def3d77Svaleriabarra        # libCEED call
2857def3d77Svaleriabarra        lib.CeedVectorSetValue(self._pointer[0], value)
2867def3d77Svaleriabarra
2877def3d77Svaleriabarra    # Sync the Vector to a specified memtype
288547d9b97Sjeremylt    def sync_array(self, memtype=MEM_HOST):
2897def3d77Svaleriabarra        """Sync the Vector to a specified memtype.
2907def3d77Svaleriabarra
2917def3d77Svaleriabarra           Args:
2927def3d77Svaleriabarra             **memtype: memtype to be synced"""
2937def3d77Svaleriabarra
2947def3d77Svaleriabarra        # libCEED call
2957def3d77Svaleriabarra        lib.CeedVectorSyncArray(self._pointer[0], memtype)
2967def3d77Svaleriabarra
297547d9b97Sjeremylt    # Compute the norm of a vector
298547d9b97Sjeremylt    def norm(self, normtype=NORM_2):
299547d9b97Sjeremylt        """Get the norm of a Vector.
300547d9b97Sjeremylt
301547d9b97Sjeremylt           Args:
302547d9b97Sjeremylt             **normtype: type of norm to be computed"""
303547d9b97Sjeremylt
304547d9b97Sjeremylt        norm_pointer = ffi.new("CeedScalar *")
305547d9b97Sjeremylt
306547d9b97Sjeremylt        # libCEED call
307547d9b97Sjeremylt        lib.CeedVectorNorm(self._pointer[0], normtype, norm_pointer)
308547d9b97Sjeremylt
309547d9b97Sjeremylt        return norm_pointer[0]
310547d9b97Sjeremylt
3117def3d77Svaleriabarra# ------------------------------------------------------------------------------
3127a7b0fa3SJed Brown
3137a7b0fa3SJed Brown
3147def3d77Svaleriabarraclass _VectorWrap(Vector):
3157def3d77Svaleriabarra    """Wrap a CeedVector pointer in a Vector object."""
3167def3d77Svaleriabarra
3177def3d77Svaleriabarra    # Constructor
3187def3d77Svaleriabarra    def __init__(self, ceed, pointer):
3197def3d77Svaleriabarra        # CeedVector object
3207def3d77Svaleriabarra        self._pointer = pointer
3217def3d77Svaleriabarra
3227def3d77Svaleriabarra        # Reference to Ceed
3237def3d77Svaleriabarra        self._ceed = ceed
3247def3d77Svaleriabarra
3257def3d77Svaleriabarra# ------------------------------------------------------------------------------
326