xref: /libCEED/python/ceed_qfunctioncontext.py (revision 777ff853944a0dbc06f7f09486fdf4674828e728)
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