1# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3# reserved. See files LICENSE and NOTICE for details. 4# 5# This file is part of CEED, a collection of benchmarks, miniapps, software 6# libraries and APIs for efficient high-order finite element and spectral 7# element discretizations for exascale applications. For more information and 8# source code availability see http://github.com/ceed. 9# 10# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11# a collaborative effort of two U.S. Department of Energy organizations (Office 12# of Science and the National Nuclear Security Administration) responsible for 13# the planning and preparation of a capable exascale ecosystem, including 14# software, applications, hardware, advanced system engineering and early 15# testbed platforms, in support of the nation's exascale computing imperative. 16 17from _ceed_cffi import ffi, lib 18import tempfile 19import numpy as np 20import contextlib 21from .ceed_constants import MEM_HOST, COPY_VALUES, NORM_2 22 23# ------------------------------------------------------------------------------ 24class Vector(): 25 """Ceed Vector: storing and manipulating vectors.""" 26 27 # Attributes 28 _ceed = ffi.NULL 29 _pointer = ffi.NULL 30 31 # Constructor 32 def __init__(self, ceed, size): 33 # CeedVector object 34 self._pointer = ffi.new("CeedVector *") 35 36 # Reference to Ceed 37 self._ceed = ceed 38 39 # libCEED call 40 lib.CeedVectorCreate(self._ceed._pointer[0], size, self._pointer) 41 42 # Destructor 43 def __del__(self): 44 # libCEED call 45 lib.CeedVectorDestroy(self._pointer) 46 47 # Representation 48 def __repr__(self): 49 return "<CeedVector instance at " + hex(id(self)) + ">" 50 51 # String conversion for print() to stdout 52 def __str__(self): 53 """View a Vector via print().""" 54 55 # libCEED call 56 fmt = ffi.new("char[]", "%f".encode('ascii')) 57 with tempfile.NamedTemporaryFile() as key_file: 58 with open(key_file.name, 'r+') as stream_file: 59 stream = ffi.cast("FILE *", stream_file) 60 61 lib.CeedVectorView(self._pointer[0], fmt, stream) 62 63 stream_file.seek(0) 64 out_string = stream_file.read() 65 66 return out_string 67 68 # Set Vector's data array 69 def set_array(self, array, memtype=MEM_HOST, cmode=COPY_VALUES): 70 """Set the array used by a Vector, freeing any previously allocated 71 array if applicable. 72 73 Args: 74 *array: Numpy array to be used 75 **memtype: memory type of the array being passed, default CEED_MEM_HOST 76 **cmode: copy mode for the array, default CEED_COPY_VALUES""" 77 78 # Setup the numpy array for the libCEED call 79 array_pointer = ffi.new("CeedScalar *") 80 array_pointer = ffi.cast("CeedScalar *", array.__array_interface__['data'][0]) 81 82 # libCEED call 83 lib.CeedVectorSetArray(self._pointer[0], memtype, cmode, array_pointer) 84 85 # Get Vector's data array 86 def get_array(self, memtype=MEM_HOST): 87 """Get read/write access to a Vector via the specified memory type. 88 89 Args: 90 **memtype: memory type of the array being passed, default CEED_MEM_HOST 91 92 Returns: 93 *array: Numpy array""" 94 95 # Retrieve the length of the array 96 length_pointer = ffi.new("CeedInt *") 97 lib.CeedVectorGetLength(self._pointer[0], length_pointer) 98 99 # Setup the pointer's pointer 100 array_pointer = ffi.new("CeedScalar **") 101 102 # libCEED call 103 lib.CeedVectorGetArray(self._pointer[0], memtype, array_pointer) 104 105 # Create buffer object from returned pointer 106 buff = ffi.buffer(array_pointer[0], ffi.sizeof("CeedScalar") * length_pointer[0]) 107 # Return numpy array created from buffer 108 return np.frombuffer(buff, dtype="float64") 109 110 # Get Vector's data array in read-only mode 111 def get_array_read(self, memtype=MEM_HOST): 112 """Get read-only access to a Vector via the specified memory type. 113 114 Args: 115 **memtype: memory type of the array being passed, default CEED_MEM_HOST 116 117 Returns: 118 *array: Numpy array""" 119 120 # Retrieve the length of the array 121 length_pointer = ffi.new("CeedInt *") 122 lib.CeedVectorGetLength(self._pointer[0], length_pointer) 123 124 # Setup the pointer's pointer 125 array_pointer = ffi.new("CeedScalar **") 126 127 # libCEED call 128 lib.CeedVectorGetArrayRead(self._pointer[0], memtype, array_pointer) 129 130 # Create buffer object from returned pointer 131 buff = ffi.buffer(array_pointer[0], ffi.sizeof("CeedScalar") * length_pointer[0]) 132 # Create numpy array from buffer 133 ret = np.frombuffer(buff, dtype="float64") 134 # Make the numpy array read-only 135 ret.flags['WRITEABLE'] = False 136 return ret 137 138 # Restore the Vector's data array 139 def restore_array(self): 140 """Restore an array obtained using get_array().""" 141 142 # Setup the pointer's pointer 143 array_pointer = ffi.new("CeedScalar **") 144 145 # libCEED call 146 lib.CeedVectorRestoreArray(self._pointer[0], array_pointer) 147 148 # Restore an array obtained using getArrayRead 149 def restore_array_read(self): 150 """Restore an array obtained using get_array_read().""" 151 152 # Setup the pointer's pointer 153 array_pointer = ffi.new("CeedScalar **") 154 155 # libCEED call 156 lib.CeedVectorRestoreArrayRead(self._pointer[0], array_pointer) 157 158 @contextlib.contextmanager 159 def array(self, *shape): 160 """Context manager for array access. 161 162 Args: 163 shape (tuple): shape of returned numpy.array 164 165 Returns: 166 np.array: writable view of vector 167 168 Examples: 169 Constructing the identity inside a libceed.Vector: 170 171 >>> vec = ceed.Vector(16) 172 >>> with vec.array(4, 4) as x: 173 >>> x[...] = np.eye(4) 174 """ 175 x = self.get_array() 176 if shape: 177 x = x.reshape(shape) 178 yield x 179 self.restore_array() 180 181 @contextlib.contextmanager 182 def array_read(self, *shape): 183 """Context manager for read-only array access. 184 185 Args: 186 shape (tuple): shape of returned numpy.array 187 188 Returns: 189 np.array: read-only view of vector 190 191 Examples: 192 Constructing the identity inside a libceed.Vector: 193 194 >>> vec = ceed.Vector(6) 195 >>> vec.set_value(1.3) 196 >>> with vec.array_read(2, 3) as x: 197 >>> print(x) 198 """ 199 x = self.get_array_read() 200 if shape: 201 x = x.reshape(shape) 202 yield x 203 self.restore_array_read() 204 205 # Get the length of a Vector 206 def get_length(self): 207 """Get the length of a Vector. 208 209 Returns: 210 length: length of the Vector""" 211 212 length_pointer = ffi.new("CeedInt *") 213 214 # libCEED call 215 lib.CeedVectorGetLength(self._pointer[0], length_pointer) 216 217 return length_pointer[0] 218 219 # Get the length of a Vector 220 def __len__(self): 221 """Get the length of a Vector. 222 223 Returns: 224 length: length of the Vector""" 225 226 length_pointer = ffi.new("CeedInt *") 227 228 # libCEED call 229 lib.CeedVectorGetLength(self._pointer[0], length_pointer) 230 231 return length_pointer[0] 232 233 # Set the Vector to a given constant value 234 def set_value(self, value): 235 """Set the Vector to a constant value. 236 237 Args: 238 value: value to be used""" 239 240 # libCEED call 241 lib.CeedVectorSetValue(self._pointer[0], value) 242 243 # Sync the Vector to a specified memtype 244 def sync_array(self, memtype=MEM_HOST): 245 """Sync the Vector to a specified memtype. 246 247 Args: 248 **memtype: memtype to be synced""" 249 250 # libCEED call 251 lib.CeedVectorSyncArray(self._pointer[0], memtype) 252 253 # Compute the norm of a vector 254 def norm(self, normtype=NORM_2): 255 """Get the norm of a Vector. 256 257 Args: 258 **normtype: type of norm to be computed""" 259 260 norm_pointer = ffi.new("CeedScalar *") 261 262 # libCEED call 263 lib.CeedVectorNorm(self._pointer[0], normtype, norm_pointer) 264 265 return norm_pointer[0] 266 267# ------------------------------------------------------------------------------ 268class _VectorWrap(Vector): 269 """Wrap a CeedVector pointer in a Vector object.""" 270 271 # Constructor 272 def __init__(self, ceed, pointer): 273 # CeedVector object 274 self._pointer = pointer 275 276 # Reference to Ceed 277 self._ceed = ceed 278 279# ------------------------------------------------------------------------------ 280