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