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# ------------------------------------------------------------------------------ 24 25 26class Vector(): 27 """Ceed Vector: storing and manipulating vectors.""" 28 29 # Attributes 30 _ceed = ffi.NULL 31 _pointer = ffi.NULL 32 33 # Constructor 34 def __init__(self, ceed, size): 35 # CeedVector object 36 self._pointer = ffi.new("CeedVector *") 37 38 # Reference to Ceed 39 self._ceed = ceed 40 41 # libCEED call 42 lib.CeedVectorCreate(self._ceed._pointer[0], size, self._pointer) 43 44 # Destructor 45 def __del__(self): 46 # libCEED call 47 lib.CeedVectorDestroy(self._pointer) 48 49 # Representation 50 def __repr__(self): 51 return "<CeedVector instance at " + hex(id(self)) + ">" 52 53 # String conversion for print() to stdout 54 def __str__(self): 55 """View a Vector via print().""" 56 57 # libCEED call 58 fmt = ffi.new("char[]", "%f".encode('ascii')) 59 with tempfile.NamedTemporaryFile() as key_file: 60 with open(key_file.name, 'r+') as stream_file: 61 stream = ffi.cast("FILE *", stream_file) 62 63 lib.CeedVectorView(self._pointer[0], fmt, stream) 64 65 stream_file.seek(0) 66 out_string = stream_file.read() 67 68 return out_string 69 70 # Set Vector's data array 71 def set_array(self, array, memtype=MEM_HOST, cmode=COPY_VALUES): 72 """Set the array used by a Vector, freeing any previously allocated 73 array if applicable. 74 75 Args: 76 *array: Numpy array to be used 77 **memtype: memory type of the array being passed, default CEED_MEM_HOST 78 **cmode: copy mode for the array, default CEED_COPY_VALUES""" 79 80 # Setup the numpy array for the libCEED call 81 array_pointer = ffi.new("CeedScalar *") 82 array_pointer = ffi.cast( 83 "CeedScalar *", 84 array.__array_interface__['data'][0]) 85 86 # libCEED call 87 lib.CeedVectorSetArray(self._pointer[0], memtype, cmode, array_pointer) 88 89 # Get Vector's data array 90 def get_array(self, memtype=MEM_HOST): 91 """Get read/write access to a Vector via the specified memory type. 92 93 Args: 94 **memtype: memory type of the array being passed, default CEED_MEM_HOST 95 96 Returns: 97 *array: Numpy array""" 98 99 # Retrieve the length of the array 100 length_pointer = ffi.new("CeedInt *") 101 lib.CeedVectorGetLength(self._pointer[0], length_pointer) 102 103 # Setup the pointer's pointer 104 array_pointer = ffi.new("CeedScalar **") 105 106 # libCEED call 107 lib.CeedVectorGetArray(self._pointer[0], memtype, array_pointer) 108 109 # Create buffer object from returned pointer 110 buff = ffi.buffer( 111 array_pointer[0], 112 ffi.sizeof("CeedScalar") * 113 length_pointer[0]) 114 # Return numpy array created from buffer 115 return np.frombuffer(buff, dtype="float64") 116 117 # Get Vector's data array in read-only mode 118 def get_array_read(self, memtype=MEM_HOST): 119 """Get read-only access to a Vector via the specified memory type. 120 121 Args: 122 **memtype: memory type of the array being passed, default CEED_MEM_HOST 123 124 Returns: 125 *array: Numpy array""" 126 127 # Retrieve the length of the array 128 length_pointer = ffi.new("CeedInt *") 129 lib.CeedVectorGetLength(self._pointer[0], length_pointer) 130 131 # Setup the pointer's pointer 132 array_pointer = ffi.new("CeedScalar **") 133 134 # libCEED call 135 lib.CeedVectorGetArrayRead(self._pointer[0], memtype, array_pointer) 136 137 # Create buffer object from returned pointer 138 buff = ffi.buffer( 139 array_pointer[0], 140 ffi.sizeof("CeedScalar") * 141 length_pointer[0]) 142 # Create numpy array from buffer 143 ret = np.frombuffer(buff, dtype="float64") 144 # Make the numpy array read-only 145 ret.flags['WRITEABLE'] = False 146 return ret 147 148 # Restore the Vector's data array 149 def restore_array(self): 150 """Restore an array obtained using get_array().""" 151 152 # Setup the pointer's pointer 153 array_pointer = ffi.new("CeedScalar **") 154 155 # libCEED call 156 lib.CeedVectorRestoreArray(self._pointer[0], array_pointer) 157 158 # Restore an array obtained using getArrayRead 159 def restore_array_read(self): 160 """Restore an array obtained using get_array_read().""" 161 162 # Setup the pointer's pointer 163 array_pointer = ffi.new("CeedScalar **") 164 165 # libCEED call 166 lib.CeedVectorRestoreArrayRead(self._pointer[0], array_pointer) 167 168 @contextlib.contextmanager 169 def array(self, *shape): 170 """Context manager for array access. 171 172 Args: 173 shape (tuple): shape of returned numpy.array 174 175 Returns: 176 np.array: writable view of vector 177 178 Examples: 179 Constructing the identity inside a libceed.Vector: 180 181 >>> vec = ceed.Vector(16) 182 >>> with vec.array(4, 4) as x: 183 >>> x[...] = np.eye(4) 184 """ 185 x = self.get_array() 186 if shape: 187 x = x.reshape(shape) 188 yield x 189 self.restore_array() 190 191 @contextlib.contextmanager 192 def array_read(self, *shape): 193 """Context manager for read-only array access. 194 195 Args: 196 shape (tuple): shape of returned numpy.array 197 198 Returns: 199 np.array: read-only view of vector 200 201 Examples: 202 Constructing the identity inside a libceed.Vector: 203 204 >>> vec = ceed.Vector(6) 205 >>> vec.set_value(1.3) 206 >>> with vec.array_read(2, 3) as x: 207 >>> print(x) 208 """ 209 x = self.get_array_read() 210 if shape: 211 x = x.reshape(shape) 212 yield x 213 self.restore_array_read() 214 215 # Get the length of a Vector 216 def get_length(self): 217 """Get the length of a Vector. 218 219 Returns: 220 length: length of the Vector""" 221 222 length_pointer = ffi.new("CeedInt *") 223 224 # libCEED call 225 lib.CeedVectorGetLength(self._pointer[0], length_pointer) 226 227 return length_pointer[0] 228 229 # Get the length of a Vector 230 def __len__(self): 231 """Get the length of a Vector. 232 233 Returns: 234 length: length of the Vector""" 235 236 length_pointer = ffi.new("CeedInt *") 237 238 # libCEED call 239 lib.CeedVectorGetLength(self._pointer[0], length_pointer) 240 241 return length_pointer[0] 242 243 # Set the Vector to a given constant value 244 def set_value(self, value): 245 """Set the Vector to a constant value. 246 247 Args: 248 value: value to be used""" 249 250 # libCEED call 251 lib.CeedVectorSetValue(self._pointer[0], value) 252 253 # Sync the Vector to a specified memtype 254 def sync_array(self, memtype=MEM_HOST): 255 """Sync the Vector to a specified memtype. 256 257 Args: 258 **memtype: memtype to be synced""" 259 260 # libCEED call 261 lib.CeedVectorSyncArray(self._pointer[0], memtype) 262 263 # Compute the norm of a vector 264 def norm(self, normtype=NORM_2): 265 """Get the norm of a Vector. 266 267 Args: 268 **normtype: type of norm to be computed""" 269 270 norm_pointer = ffi.new("CeedScalar *") 271 272 # libCEED call 273 lib.CeedVectorNorm(self._pointer[0], normtype, norm_pointer) 274 275 return norm_pointer[0] 276 277# ------------------------------------------------------------------------------ 278 279 280class _VectorWrap(Vector): 281 """Wrap a CeedVector pointer in a Vector object.""" 282 283 # Constructor 284 def __init__(self, ceed, pointer): 285 # CeedVector object 286 self._pointer = pointer 287 288 # Reference to Ceed 289 self._ceed = ceed 290 291# ------------------------------------------------------------------------------ 292