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