1*777ff853SJeremy L Thompson# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2*777ff853SJeremy L Thompson# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3*777ff853SJeremy L Thompson# reserved. See files LICENSE and NOTICE for details. 4*777ff853SJeremy L Thompson# 5*777ff853SJeremy L Thompson# This file is part of CEED, a collection of benchmarks, miniapps, software 6*777ff853SJeremy L Thompson# libraries and APIs for efficient high-order finite element and spectral 7*777ff853SJeremy L Thompson# element discretizations for exascale applications. For more information and 8*777ff853SJeremy L Thompson# source code availability see http://github.com/ceed. 9*777ff853SJeremy L Thompson# 10*777ff853SJeremy L Thompson# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11*777ff853SJeremy L Thompson# a collaborative effort of two U.S. Department of Energy organizations (Office 12*777ff853SJeremy L Thompson# of Science and the National Nuclear Security Administration) responsible for 13*777ff853SJeremy L Thompson# the planning and preparation of a capable exascale ecosystem, including 14*777ff853SJeremy L Thompson# software, applications, hardware, advanced system engineering and early 15*777ff853SJeremy L Thompson# testbed platforms, in support of the nation's exascale computing imperative. 16*777ff853SJeremy L Thompson 17*777ff853SJeremy L Thompsonfrom _ceed_cffi import ffi, lib 18*777ff853SJeremy L Thompsonimport tempfile 19*777ff853SJeremy L Thompsonimport numpy as np 20*777ff853SJeremy L Thompsonimport contextlib 21*777ff853SJeremy L Thompsonfrom .ceed_constants import MEM_HOST, COPY_VALUES 22*777ff853SJeremy L Thompson 23*777ff853SJeremy L Thompson# ------------------------------------------------------------------------------ 24*777ff853SJeremy L Thompson 25*777ff853SJeremy L Thompson 26*777ff853SJeremy L Thompsonclass QFunctionContext(): 27*777ff853SJeremy L Thompson """Ceed QFunction Context: stores Ceed QFunction user context data.""" 28*777ff853SJeremy L Thompson 29*777ff853SJeremy L Thompson # Attributes 30*777ff853SJeremy L Thompson _ceed = ffi.NULL 31*777ff853SJeremy L Thompson _pointer = ffi.NULL 32*777ff853SJeremy L Thompson 33*777ff853SJeremy L Thompson # Constructor 34*777ff853SJeremy L Thompson def __init__(self, ceed): 35*777ff853SJeremy L Thompson # CeedQFunctionContext object 36*777ff853SJeremy L Thompson self._pointer = ffi.new("CeedQFunctionContext *") 37*777ff853SJeremy L Thompson 38*777ff853SJeremy L Thompson # Reference to Ceed 39*777ff853SJeremy L Thompson self._ceed = ceed 40*777ff853SJeremy L Thompson 41*777ff853SJeremy L Thompson # libCEED call 42*777ff853SJeremy L Thompson err_code = lib.CeedQFunctionContextCreate( 43*777ff853SJeremy L Thompson self._ceed._pointer[0], self._pointer) 44*777ff853SJeremy L Thompson self._ceed._check_error(err_code) 45*777ff853SJeremy L Thompson 46*777ff853SJeremy L Thompson # Destructor 47*777ff853SJeremy L Thompson def __del__(self): 48*777ff853SJeremy L Thompson # libCEED call 49*777ff853SJeremy L Thompson err_code = lib.CeedQFunctionContextDestroy(self._pointer) 50*777ff853SJeremy L Thompson self._ceed._check_error(err_code) 51*777ff853SJeremy L Thompson 52*777ff853SJeremy L Thompson # Representation 53*777ff853SJeremy L Thompson def __repr__(self): 54*777ff853SJeremy L Thompson return "<CeedQFunctionContext instance at " + hex(id(self)) + ">" 55*777ff853SJeremy L Thompson 56*777ff853SJeremy L Thompson # String conversion for print() to stdout 57*777ff853SJeremy L Thompson def __str__(self): 58*777ff853SJeremy L Thompson """View a QFunction Context via print().""" 59*777ff853SJeremy L Thompson 60*777ff853SJeremy L Thompson # libCEED call 61*777ff853SJeremy L Thompson fmt = ffi.new("char[]", "%f".encode('ascii')) 62*777ff853SJeremy L Thompson with tempfile.NamedTemporaryFile() as key_file: 63*777ff853SJeremy L Thompson with open(key_file.name, 'r+') as stream_file: 64*777ff853SJeremy L Thompson stream = ffi.cast("FILE *", stream_file) 65*777ff853SJeremy L Thompson 66*777ff853SJeremy L Thompson err_code = lib.CeedQFunctionContextView( 67*777ff853SJeremy L Thompson self._pointer[0], stream) 68*777ff853SJeremy L Thompson self._ceed._check_error(err_code) 69*777ff853SJeremy L Thompson 70*777ff853SJeremy L Thompson stream_file.seek(0) 71*777ff853SJeremy L Thompson out_string = stream_file.read() 72*777ff853SJeremy L Thompson 73*777ff853SJeremy L Thompson return out_string 74*777ff853SJeremy L Thompson 75*777ff853SJeremy L Thompson # Set QFunction Context's data 76*777ff853SJeremy L Thompson def set_data(self, data, memtype=MEM_HOST, cmode=COPY_VALUES): 77*777ff853SJeremy L Thompson """Set the data used by a QFunction Context, freeing any previously allocated 78*777ff853SJeremy L Thompson data if applicable. 79*777ff853SJeremy L Thompson 80*777ff853SJeremy L Thompson Args: 81*777ff853SJeremy L Thompson *data: Numpy or Numba array to be used 82*777ff853SJeremy L Thompson **memtype: memory type of the array being passed, default CEED_MEM_HOST 83*777ff853SJeremy L Thompson **cmode: copy mode for the array, default CEED_COPY_VALUES""" 84*777ff853SJeremy L Thompson 85*777ff853SJeremy L Thompson # Setup the numpy array for the libCEED call 86*777ff853SJeremy L Thompson data_pointer = ffi.new("CeedScalar *") 87*777ff853SJeremy L Thompson if memtype == MEM_HOST: 88*777ff853SJeremy L Thompson data_pointer = ffi.cast( 89*777ff853SJeremy L Thompson "void *", 90*777ff853SJeremy L Thompson data.__array_interface__['data'][0]) 91*777ff853SJeremy L Thompson else: 92*777ff853SJeremy L Thompson array_pointer = ffi.cast( 93*777ff853SJeremy L Thompson "void *", 94*777ff853SJeremy L Thompson data.__cuda_array_interface__['data'][0]) 95*777ff853SJeremy L Thompson 96*777ff853SJeremy L Thompson # libCEED call 97*777ff853SJeremy L Thompson err_code = lib.CeedQFunctionContextSetData( 98*777ff853SJeremy L Thompson self._pointer[0], 99*777ff853SJeremy L Thompson memtype, 100*777ff853SJeremy L Thompson cmode, 101*777ff853SJeremy L Thompson len(data) * ffi.sizeof("CeedScalar"), 102*777ff853SJeremy L Thompson data_pointer) 103*777ff853SJeremy L Thompson self._ceed._check_error(err_code) 104*777ff853SJeremy L Thompson 105*777ff853SJeremy L Thompson # Get QFunction Context's data 106*777ff853SJeremy L Thompson def get_data(self, memtype=MEM_HOST): 107*777ff853SJeremy L Thompson """Get read/write access to a QFunction Context via the specified memory type. 108*777ff853SJeremy L Thompson 109*777ff853SJeremy L Thompson Args: 110*777ff853SJeremy L Thompson **memtype: memory type of the array being passed, default CEED_MEM_HOST 111*777ff853SJeremy L Thompson 112*777ff853SJeremy L Thompson Returns: 113*777ff853SJeremy L Thompson *data: Numpy or Numba array""" 114*777ff853SJeremy L Thompson 115*777ff853SJeremy L Thompson # Retrieve the length of the array 116*777ff853SJeremy L Thompson size_pointer = ffi.new("CeedInt *") 117*777ff853SJeremy L Thompson err_code = lib.CeedQFunctionContextGetContextSize( 118*777ff853SJeremy L Thompson self._pointer[0], size_pointer) 119*777ff853SJeremy L Thompson self._ceed._check_error(err_code) 120*777ff853SJeremy L Thompson 121*777ff853SJeremy L Thompson # Setup the pointer's pointer 122*777ff853SJeremy L Thompson data_pointer = ffi.new("CeedScalar **") 123*777ff853SJeremy L Thompson 124*777ff853SJeremy L Thompson # libCEED call 125*777ff853SJeremy L Thompson err_code = lib.CeedQFunctionContextGetData( 126*777ff853SJeremy L Thompson self._pointer[0], memtype, data_pointer) 127*777ff853SJeremy L Thompson self._ceed._check_error(err_code) 128*777ff853SJeremy L Thompson 129*777ff853SJeremy L Thompson # Return array created from buffer 130*777ff853SJeremy L Thompson if memtype == MEM_HOST: 131*777ff853SJeremy L Thompson # Create buffer object from returned pointer 132*777ff853SJeremy L Thompson buff = ffi.buffer( 133*777ff853SJeremy L Thompson data_pointer[0], 134*777ff853SJeremy L Thompson ffi.sizeof("CeedScalar") * 135*777ff853SJeremy L Thompson length_pointer[0]) 136*777ff853SJeremy L Thompson # return Numpy array 137*777ff853SJeremy L Thompson return np.frombuffer(buff, dtype="float64") 138*777ff853SJeremy L Thompson else: 139*777ff853SJeremy L Thompson # CUDA array interface 140*777ff853SJeremy L Thompson # https://numba.pydata.org/numba-doc/latest/cuda/cuda_array_interface.html 141*777ff853SJeremy L Thompson import numba.cuda as nbcuda 142*777ff853SJeremy L Thompson desc = { 143*777ff853SJeremy L Thompson 'shape': (length_pointer[0]), 144*777ff853SJeremy L Thompson 'typestr': '>f8', 145*777ff853SJeremy L Thompson 'data': (int(ffi.cast("intptr_t", data_pointer[0])), False), 146*777ff853SJeremy L Thompson 'version': 2 147*777ff853SJeremy L Thompson } 148*777ff853SJeremy L Thompson # return Numba array 149*777ff853SJeremy L Thompson return nbcuda.from_cuda_array_interface(desc) 150*777ff853SJeremy L Thompson 151*777ff853SJeremy L Thompson # Restore the QFunction Context's data 152*777ff853SJeremy L Thompson def restore_data(self): 153*777ff853SJeremy L Thompson """Restore an array obtained using get_data().""" 154*777ff853SJeremy L Thompson 155*777ff853SJeremy L Thompson # Setup the pointer's pointer 156*777ff853SJeremy L Thompson data_pointer = ffi.new("CeedScalar **") 157*777ff853SJeremy L Thompson 158*777ff853SJeremy L Thompson # libCEED call 159*777ff853SJeremy L Thompson err_code = lib.CeedQFunctionDataRestoreData(self._pointer[0], data_pointer) 160*777ff853SJeremy L Thompson self._ceed._check_error(err_code) 161*777ff853SJeremy L Thompson 162*777ff853SJeremy L Thompson @contextlib.contextmanager 163*777ff853SJeremy L Thompson def data(self, *shape, memtype=MEM_HOST): 164*777ff853SJeremy L Thompson """Context manager for array access. 165*777ff853SJeremy L Thompson 166*777ff853SJeremy L Thompson Args: 167*777ff853SJeremy L Thompson shape (tuple): shape of returned numpy.array 168*777ff853SJeremy L Thompson **memtype: memory type of the data being passed, default CEED_MEM_HOST 169*777ff853SJeremy L Thompson 170*777ff853SJeremy L Thompson 171*777ff853SJeremy L Thompson Returns: 172*777ff853SJeremy L Thompson np.array: writable view of QFunction Context 173*777ff853SJeremy L Thompson """ 174*777ff853SJeremy L Thompson x = self.get_data(memtype=memtype) 175*777ff853SJeremy L Thompson if shape: 176*777ff853SJeremy L Thompson x = x.reshape(shape) 177*777ff853SJeremy L Thompson yield x 178*777ff853SJeremy L Thompson self.restore_data() 179*777ff853SJeremy L Thompson 180*777ff853SJeremy L Thompson# ------------------------------------------------------------------------------ 181