xref: /libCEED/python/ceed_qfunctioncontext.py (revision 187168c7adf497522cc3b03930f59faf3536934a)
1777ff853SJeremy L Thompson# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2777ff853SJeremy L Thompson# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3777ff853SJeremy L Thompson# reserved. See files LICENSE and NOTICE for details.
4777ff853SJeremy L Thompson#
5777ff853SJeremy L Thompson# This file is part of CEED, a collection of benchmarks, miniapps, software
6777ff853SJeremy L Thompson# libraries and APIs for efficient high-order finite element and spectral
7777ff853SJeremy L Thompson# element discretizations for exascale applications. For more information and
8777ff853SJeremy L Thompson# source code availability see http://github.com/ceed.
9777ff853SJeremy L Thompson#
10777ff853SJeremy L Thompson# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11777ff853SJeremy L Thompson# a collaborative effort of two U.S. Department of Energy organizations (Office
12777ff853SJeremy L Thompson# of Science and the National Nuclear Security Administration) responsible for
13777ff853SJeremy L Thompson# the planning and preparation of a capable exascale ecosystem, including
14777ff853SJeremy L Thompson# software, applications, hardware, advanced system engineering and early
15777ff853SJeremy L Thompson# testbed platforms, in support of the nation's exascale computing imperative.
16777ff853SJeremy L Thompson
17777ff853SJeremy L Thompsonfrom _ceed_cffi import ffi, lib
18777ff853SJeremy L Thompsonimport tempfile
19777ff853SJeremy L Thompsonimport numpy as np
20777ff853SJeremy L Thompsonimport contextlib
21*187168c7SJeremy L Thompsonfrom .ceed_constants import MEM_HOST, USE_POINTER, COPY_VALUES
22777ff853SJeremy L Thompson
23777ff853SJeremy L Thompson# ------------------------------------------------------------------------------
24777ff853SJeremy L Thompson
25777ff853SJeremy L Thompson
26777ff853SJeremy L Thompsonclass QFunctionContext():
27777ff853SJeremy L Thompson    """Ceed QFunction Context: stores Ceed QFunction user context data."""
28777ff853SJeremy L Thompson
29777ff853SJeremy L Thompson    # Attributes
30*187168c7SJeremy L Thompson    _ceed = None
31777ff853SJeremy L Thompson    _pointer = ffi.NULL
32*187168c7SJeremy L Thompson    _array_reference = None
33777ff853SJeremy L Thompson
34777ff853SJeremy L Thompson    # Constructor
35777ff853SJeremy L Thompson    def __init__(self, ceed):
36777ff853SJeremy L Thompson        # CeedQFunctionContext object
37777ff853SJeremy L Thompson        self._pointer = ffi.new("CeedQFunctionContext *")
38777ff853SJeremy L Thompson
39777ff853SJeremy L Thompson        # Reference to Ceed
40777ff853SJeremy L Thompson        self._ceed = ceed
41777ff853SJeremy L Thompson
42777ff853SJeremy L Thompson        # libCEED call
43777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextCreate(
44777ff853SJeremy L Thompson            self._ceed._pointer[0], self._pointer)
45777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
46777ff853SJeremy L Thompson
47777ff853SJeremy L Thompson    # Destructor
48777ff853SJeremy L Thompson    def __del__(self):
49777ff853SJeremy L Thompson        # libCEED call
50777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextDestroy(self._pointer)
51777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
52777ff853SJeremy L Thompson
53777ff853SJeremy L Thompson    # Representation
54777ff853SJeremy L Thompson    def __repr__(self):
55777ff853SJeremy L Thompson        return "<CeedQFunctionContext instance at " + hex(id(self)) + ">"
56777ff853SJeremy L Thompson
57777ff853SJeremy L Thompson    # String conversion for print() to stdout
58777ff853SJeremy L Thompson    def __str__(self):
59777ff853SJeremy L Thompson        """View a QFunction Context via print()."""
60777ff853SJeremy L Thompson
61777ff853SJeremy L Thompson        # libCEED call
62777ff853SJeremy L Thompson        fmt = ffi.new("char[]", "%f".encode('ascii'))
63777ff853SJeremy L Thompson        with tempfile.NamedTemporaryFile() as key_file:
64777ff853SJeremy L Thompson            with open(key_file.name, 'r+') as stream_file:
65777ff853SJeremy L Thompson                stream = ffi.cast("FILE *", stream_file)
66777ff853SJeremy L Thompson
67777ff853SJeremy L Thompson                err_code = lib.CeedQFunctionContextView(
68777ff853SJeremy L Thompson                    self._pointer[0], stream)
69777ff853SJeremy L Thompson                self._ceed._check_error(err_code)
70777ff853SJeremy L Thompson
71777ff853SJeremy L Thompson                stream_file.seek(0)
72777ff853SJeremy L Thompson                out_string = stream_file.read()
73777ff853SJeremy L Thompson
74777ff853SJeremy L Thompson        return out_string
75777ff853SJeremy L Thompson
76777ff853SJeremy L Thompson    # Set QFunction Context's data
77777ff853SJeremy L Thompson    def set_data(self, data, memtype=MEM_HOST, cmode=COPY_VALUES):
78777ff853SJeremy L Thompson        """Set the data used by a QFunction Context, freeing any previously allocated
79777ff853SJeremy L Thompson           data if applicable.
80777ff853SJeremy L Thompson
81777ff853SJeremy L Thompson           Args:
82777ff853SJeremy L Thompson             *data: Numpy or Numba array to be used
83777ff853SJeremy L Thompson             **memtype: memory type of the array being passed, default CEED_MEM_HOST
84777ff853SJeremy L Thompson             **cmode: copy mode for the array, default CEED_COPY_VALUES"""
85777ff853SJeremy L Thompson
86*187168c7SJeremy L Thompson        # Store array reference if needed
87*187168c7SJeremy L Thompson        if cmode == USE_POINTER:
88*187168c7SJeremy L Thompson            self._array_reference = data
89*187168c7SJeremy L Thompson        else:
90*187168c7SJeremy L Thompson            self._array_reference = None
91*187168c7SJeremy L Thompson
92777ff853SJeremy L Thompson        # Setup the numpy array for the libCEED call
93777ff853SJeremy L Thompson        data_pointer = ffi.new("CeedScalar *")
94777ff853SJeremy L Thompson        if memtype == MEM_HOST:
95777ff853SJeremy L Thompson            data_pointer = ffi.cast(
96777ff853SJeremy L Thompson                "void *",
97777ff853SJeremy L Thompson                data.__array_interface__['data'][0])
98777ff853SJeremy L Thompson        else:
99777ff853SJeremy L Thompson            array_pointer = ffi.cast(
100777ff853SJeremy L Thompson                "void *",
101777ff853SJeremy L Thompson                data.__cuda_array_interface__['data'][0])
102777ff853SJeremy L Thompson
103777ff853SJeremy L Thompson        # libCEED call
104777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextSetData(
105777ff853SJeremy L Thompson            self._pointer[0],
106777ff853SJeremy L Thompson            memtype,
107777ff853SJeremy L Thompson            cmode,
108777ff853SJeremy L Thompson            len(data) * ffi.sizeof("CeedScalar"),
109777ff853SJeremy L Thompson            data_pointer)
110777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
111777ff853SJeremy L Thompson
112777ff853SJeremy L Thompson    # Get QFunction Context's data
113777ff853SJeremy L Thompson    def get_data(self, memtype=MEM_HOST):
114777ff853SJeremy L Thompson        """Get read/write access to a QFunction Context via the specified memory type.
115777ff853SJeremy L Thompson
116777ff853SJeremy L Thompson           Args:
117777ff853SJeremy L Thompson             **memtype: memory type of the array being passed, default CEED_MEM_HOST
118777ff853SJeremy L Thompson
119777ff853SJeremy L Thompson           Returns:
120777ff853SJeremy L Thompson             *data: Numpy or Numba array"""
121777ff853SJeremy L Thompson
122777ff853SJeremy L Thompson        # Retrieve the length of the array
123777ff853SJeremy L Thompson        size_pointer = ffi.new("CeedInt *")
124777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextGetContextSize(
125777ff853SJeremy L Thompson            self._pointer[0], size_pointer)
126777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
127777ff853SJeremy L Thompson
128777ff853SJeremy L Thompson        # Setup the pointer's pointer
129777ff853SJeremy L Thompson        data_pointer = ffi.new("CeedScalar **")
130777ff853SJeremy L Thompson
131777ff853SJeremy L Thompson        # libCEED call
132777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextGetData(
133777ff853SJeremy L Thompson            self._pointer[0], memtype, data_pointer)
134777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
135777ff853SJeremy L Thompson
136777ff853SJeremy L Thompson        # Return array created from buffer
137777ff853SJeremy L Thompson        if memtype == MEM_HOST:
138777ff853SJeremy L Thompson            # Create buffer object from returned pointer
139777ff853SJeremy L Thompson            buff = ffi.buffer(
140777ff853SJeremy L Thompson                data_pointer[0],
141777ff853SJeremy L Thompson                ffi.sizeof("CeedScalar") *
142777ff853SJeremy L Thompson                length_pointer[0])
143777ff853SJeremy L Thompson            # return Numpy array
144777ff853SJeremy L Thompson            return np.frombuffer(buff, dtype="float64")
145777ff853SJeremy L Thompson        else:
146777ff853SJeremy L Thompson            # CUDA array interface
147777ff853SJeremy L Thompson            # https://numba.pydata.org/numba-doc/latest/cuda/cuda_array_interface.html
148777ff853SJeremy L Thompson            import numba.cuda as nbcuda
149777ff853SJeremy L Thompson            desc = {
150777ff853SJeremy L Thompson                'shape': (length_pointer[0]),
151777ff853SJeremy L Thompson                'typestr': '>f8',
152777ff853SJeremy L Thompson                'data': (int(ffi.cast("intptr_t", data_pointer[0])), False),
153777ff853SJeremy L Thompson                'version': 2
154777ff853SJeremy L Thompson            }
155777ff853SJeremy L Thompson            # return Numba array
156777ff853SJeremy L Thompson            return nbcuda.from_cuda_array_interface(desc)
157777ff853SJeremy L Thompson
158777ff853SJeremy L Thompson    # Restore the QFunction Context's data
159777ff853SJeremy L Thompson    def restore_data(self):
160777ff853SJeremy L Thompson        """Restore an array obtained using get_data()."""
161777ff853SJeremy L Thompson
162777ff853SJeremy L Thompson        # Setup the pointer's pointer
163777ff853SJeremy L Thompson        data_pointer = ffi.new("CeedScalar **")
164777ff853SJeremy L Thompson
165777ff853SJeremy L Thompson        # libCEED call
1669647a07eSDavid Medina        err_code = lib.CeedQFunctionDataRestoreData(
1679647a07eSDavid Medina            self._pointer[0], data_pointer)
168777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
169777ff853SJeremy L Thompson
170777ff853SJeremy L Thompson    @contextlib.contextmanager
171777ff853SJeremy L Thompson    def data(self, *shape, memtype=MEM_HOST):
172777ff853SJeremy L Thompson        """Context manager for array access.
173777ff853SJeremy L Thompson
174777ff853SJeremy L Thompson        Args:
175777ff853SJeremy L Thompson          shape (tuple): shape of returned numpy.array
176777ff853SJeremy L Thompson          **memtype: memory type of the data being passed, default CEED_MEM_HOST
177777ff853SJeremy L Thompson
178777ff853SJeremy L Thompson
179777ff853SJeremy L Thompson        Returns:
180777ff853SJeremy L Thompson          np.array: writable view of QFunction Context
181777ff853SJeremy L Thompson        """
182777ff853SJeremy L Thompson        x = self.get_data(memtype=memtype)
183777ff853SJeremy L Thompson        if shape:
184777ff853SJeremy L Thompson            x = x.reshape(shape)
185777ff853SJeremy L Thompson        yield x
186777ff853SJeremy L Thompson        self.restore_data()
187777ff853SJeremy L Thompson
188777ff853SJeremy L Thompson# ------------------------------------------------------------------------------
189