xref: /libCEED/python/ceed_qfunctioncontext.py (revision 80a9ef0545a39c00cdcaab1ca26f8053604f3120)
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*80a9ef05SNatalie Beamsfrom .ceed_constants import MEM_HOST, USE_POINTER, COPY_VALUES, scalar_types
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    # Constructor
30777ff853SJeremy L Thompson    def __init__(self, ceed):
31777ff853SJeremy L Thompson        # CeedQFunctionContext object
32777ff853SJeremy L Thompson        self._pointer = ffi.new("CeedQFunctionContext *")
33777ff853SJeremy L Thompson
34777ff853SJeremy L Thompson        # Reference to Ceed
35777ff853SJeremy L Thompson        self._ceed = ceed
36777ff853SJeremy L Thompson
37777ff853SJeremy L Thompson        # libCEED call
38777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextCreate(
39777ff853SJeremy L Thompson            self._ceed._pointer[0], self._pointer)
40777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
41777ff853SJeremy L Thompson
42777ff853SJeremy L Thompson    # Destructor
43777ff853SJeremy L Thompson    def __del__(self):
44777ff853SJeremy L Thompson        # libCEED call
45777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextDestroy(self._pointer)
46777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
47777ff853SJeremy L Thompson
48777ff853SJeremy L Thompson    # Representation
49777ff853SJeremy L Thompson    def __repr__(self):
50777ff853SJeremy L Thompson        return "<CeedQFunctionContext instance at " + hex(id(self)) + ">"
51777ff853SJeremy L Thompson
52777ff853SJeremy L Thompson    # String conversion for print() to stdout
53777ff853SJeremy L Thompson    def __str__(self):
54777ff853SJeremy L Thompson        """View a QFunction Context via print()."""
55777ff853SJeremy L Thompson
56777ff853SJeremy L Thompson        # libCEED call
57777ff853SJeremy L Thompson        fmt = ffi.new("char[]", "%f".encode('ascii'))
58777ff853SJeremy L Thompson        with tempfile.NamedTemporaryFile() as key_file:
59777ff853SJeremy L Thompson            with open(key_file.name, 'r+') as stream_file:
60777ff853SJeremy L Thompson                stream = ffi.cast("FILE *", stream_file)
61777ff853SJeremy L Thompson
62777ff853SJeremy L Thompson                err_code = lib.CeedQFunctionContextView(
63777ff853SJeremy L Thompson                    self._pointer[0], stream)
64777ff853SJeremy L Thompson                self._ceed._check_error(err_code)
65777ff853SJeremy L Thompson
66777ff853SJeremy L Thompson                stream_file.seek(0)
67777ff853SJeremy L Thompson                out_string = stream_file.read()
68777ff853SJeremy L Thompson
69777ff853SJeremy L Thompson        return out_string
70777ff853SJeremy L Thompson
71777ff853SJeremy L Thompson    # Set QFunction Context's data
72777ff853SJeremy L Thompson    def set_data(self, data, memtype=MEM_HOST, cmode=COPY_VALUES):
73777ff853SJeremy L Thompson        """Set the data used by a QFunction Context, freeing any previously allocated
74777ff853SJeremy L Thompson           data if applicable.
75777ff853SJeremy L Thompson
76777ff853SJeremy L Thompson           Args:
77777ff853SJeremy L Thompson             *data: Numpy or Numba array to be used
78777ff853SJeremy L Thompson             **memtype: memory type of the array being passed, default CEED_MEM_HOST
79777ff853SJeremy L Thompson             **cmode: copy mode for the array, default CEED_COPY_VALUES"""
80777ff853SJeremy L Thompson
81187168c7SJeremy L Thompson        # Store array reference if needed
82187168c7SJeremy L Thompson        if cmode == USE_POINTER:
83187168c7SJeremy L Thompson            self._array_reference = data
84187168c7SJeremy L Thompson        else:
85187168c7SJeremy L Thompson            self._array_reference = None
86187168c7SJeremy L Thompson
87777ff853SJeremy L Thompson        # Setup the numpy array for the libCEED call
88777ff853SJeremy L Thompson        data_pointer = ffi.new("CeedScalar *")
89777ff853SJeremy L Thompson        if memtype == MEM_HOST:
90777ff853SJeremy L Thompson            data_pointer = ffi.cast(
91777ff853SJeremy L Thompson                "void *",
92777ff853SJeremy L Thompson                data.__array_interface__['data'][0])
93777ff853SJeremy L Thompson        else:
94777ff853SJeremy L Thompson            array_pointer = ffi.cast(
95777ff853SJeremy L Thompson                "void *",
96777ff853SJeremy L Thompson                data.__cuda_array_interface__['data'][0])
97777ff853SJeremy L Thompson
98777ff853SJeremy L Thompson        # libCEED call
99777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextSetData(
100777ff853SJeremy L Thompson            self._pointer[0],
101777ff853SJeremy L Thompson            memtype,
102777ff853SJeremy L Thompson            cmode,
103777ff853SJeremy L Thompson            len(data) * ffi.sizeof("CeedScalar"),
104777ff853SJeremy L Thompson            data_pointer)
105777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
106777ff853SJeremy L Thompson
107777ff853SJeremy L Thompson    # Get QFunction Context's data
108777ff853SJeremy L Thompson    def get_data(self, memtype=MEM_HOST):
109777ff853SJeremy L Thompson        """Get read/write access to a QFunction Context via the specified memory type.
110777ff853SJeremy L Thompson
111777ff853SJeremy L Thompson           Args:
112777ff853SJeremy L Thompson             **memtype: memory type of the array being passed, default CEED_MEM_HOST
113777ff853SJeremy L Thompson
114777ff853SJeremy L Thompson           Returns:
115777ff853SJeremy L Thompson             *data: Numpy or Numba array"""
116777ff853SJeremy L Thompson
117777ff853SJeremy L Thompson        # Retrieve the length of the array
118*80a9ef05SNatalie Beams        size_pointer = ffi.new("size_t *")
119777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextGetContextSize(
120777ff853SJeremy L Thompson            self._pointer[0], size_pointer)
121777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
122777ff853SJeremy L Thompson
123777ff853SJeremy L Thompson        # Setup the pointer's pointer
124777ff853SJeremy L Thompson        data_pointer = ffi.new("CeedScalar **")
125777ff853SJeremy L Thompson
126777ff853SJeremy L Thompson        # libCEED call
127777ff853SJeremy L Thompson        err_code = lib.CeedQFunctionContextGetData(
128777ff853SJeremy L Thompson            self._pointer[0], memtype, data_pointer)
129777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
130777ff853SJeremy L Thompson
131777ff853SJeremy L Thompson        # Return array created from buffer
132777ff853SJeremy L Thompson        if memtype == MEM_HOST:
133777ff853SJeremy L Thompson            # Create buffer object from returned pointer
134777ff853SJeremy L Thompson            buff = ffi.buffer(
135777ff853SJeremy L Thompson                data_pointer[0],
136*80a9ef05SNatalie Beams                size_pointer[0])
137777ff853SJeremy L Thompson            # return Numpy array
138*80a9ef05SNatalie Beams            return np.frombuffer(buff, dtype=scalar_types[lib.CEED_SCALAR_TYPE])
139777ff853SJeremy L Thompson        else:
140777ff853SJeremy L Thompson            # CUDA array interface
141777ff853SJeremy L Thompson            # https://numba.pydata.org/numba-doc/latest/cuda/cuda_array_interface.html
142777ff853SJeremy L Thompson            import numba.cuda as nbcuda
143*80a9ef05SNatalie Beams            if lib.CEED_SCALAR_TYPE == lib.CEED_SCALAR_FP32:
144*80a9ef05SNatalie Beams                scalar_type_str = '>f4'
145*80a9ef05SNatalie Beams            else:
146*80a9ef05SNatalie Beams                scalar_type_str = '>f8'
147777ff853SJeremy L Thompson            desc = {
148*80a9ef05SNatalie Beams                'shape': (size_pointer[0] / ffi.sizeof("CeedScalar")),
149*80a9ef05SNatalie Beams                'typestr': scalar_type_str,
150777ff853SJeremy L Thompson                'data': (int(ffi.cast("intptr_t", data_pointer[0])), False),
151777ff853SJeremy L Thompson                'version': 2
152777ff853SJeremy L Thompson            }
153777ff853SJeremy L Thompson            # return Numba array
154777ff853SJeremy L Thompson            return nbcuda.from_cuda_array_interface(desc)
155777ff853SJeremy L Thompson
156777ff853SJeremy L Thompson    # Restore the QFunction Context's data
157777ff853SJeremy L Thompson    def restore_data(self):
158777ff853SJeremy L Thompson        """Restore an array obtained using get_data()."""
159777ff853SJeremy L Thompson
160777ff853SJeremy L Thompson        # Setup the pointer's pointer
161777ff853SJeremy L Thompson        data_pointer = ffi.new("CeedScalar **")
162777ff853SJeremy L Thompson
163777ff853SJeremy L Thompson        # libCEED call
1649647a07eSDavid Medina        err_code = lib.CeedQFunctionDataRestoreData(
1659647a07eSDavid Medina            self._pointer[0], data_pointer)
166777ff853SJeremy L Thompson        self._ceed._check_error(err_code)
167777ff853SJeremy L Thompson
168777ff853SJeremy L Thompson    @contextlib.contextmanager
169777ff853SJeremy L Thompson    def data(self, *shape, memtype=MEM_HOST):
170777ff853SJeremy L Thompson        """Context manager for array access.
171777ff853SJeremy L Thompson
172777ff853SJeremy L Thompson        Args:
173777ff853SJeremy L Thompson          shape (tuple): shape of returned numpy.array
174777ff853SJeremy L Thompson          **memtype: memory type of the data being passed, default CEED_MEM_HOST
175777ff853SJeremy L Thompson
176777ff853SJeremy L Thompson
177777ff853SJeremy L Thompson        Returns:
178777ff853SJeremy L Thompson          np.array: writable view of QFunction Context
179777ff853SJeremy L Thompson        """
180777ff853SJeremy L Thompson        x = self.get_data(memtype=memtype)
181777ff853SJeremy L Thompson        if shape:
182777ff853SJeremy L Thompson            x = x.reshape(shape)
183777ff853SJeremy L Thompson        yield x
184777ff853SJeremy L Thompson        self.restore_data()
185777ff853SJeremy L Thompson
186777ff853SJeremy L Thompson# ------------------------------------------------------------------------------
187