xref: /libCEED/python/ceed_vector.py (revision e1ef875599c3a6b02a7bf1f21ab905966273ff45)
1# Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2# the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3# reserved. See files LICENSE and NOTICE for details.
4#
5# This file is part of CEED, a collection of benchmarks, miniapps, software
6# libraries and APIs for efficient high-order finite element and spectral
7# element discretizations for exascale applications. For more information and
8# source code availability see http://github.com/ceed.
9#
10# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11# a collaborative effort of two U.S. Department of Energy organizations (Office
12# of Science and the National Nuclear Security Administration) responsible for
13# the planning and preparation of a capable exascale ecosystem, including
14# software, applications, hardware, advanced system engineering and early
15# testbed platforms, in support of the nation's exascale computing imperative.
16
17from _ceed_cffi import ffi, lib
18import tempfile
19import numpy as np
20import contextlib
21from .ceed_constants import MEM_HOST, COPY_VALUES, NORM_2
22
23# ------------------------------------------------------------------------------
24
25
26class Vector():
27    """Ceed Vector: storing and manipulating vectors."""
28
29    # Attributes
30    _ceed = ffi.NULL
31    _pointer = ffi.NULL
32
33    # Constructor
34    def __init__(self, ceed, size):
35        # CeedVector object
36        self._pointer = ffi.new("CeedVector *")
37
38        # Reference to Ceed
39        self._ceed = ceed
40
41        # libCEED call
42        lib.CeedVectorCreate(self._ceed._pointer[0], size, self._pointer)
43
44    # Destructor
45    def __del__(self):
46        # libCEED call
47        lib.CeedVectorDestroy(self._pointer)
48
49    # Representation
50    def __repr__(self):
51        return "<CeedVector instance at " + hex(id(self)) + ">"
52
53    # String conversion for print() to stdout
54    def __str__(self):
55        """View a Vector via print()."""
56
57        # libCEED call
58        fmt = ffi.new("char[]", "%f".encode('ascii'))
59        with tempfile.NamedTemporaryFile() as key_file:
60            with open(key_file.name, 'r+') as stream_file:
61                stream = ffi.cast("FILE *", stream_file)
62
63                lib.CeedVectorView(self._pointer[0], fmt, stream)
64
65                stream_file.seek(0)
66                out_string = stream_file.read()
67
68        return out_string
69
70    # Set Vector's data array
71    def set_array(self, array, memtype=MEM_HOST, cmode=COPY_VALUES):
72        """Set the array used by a Vector, freeing any previously allocated
73           array if applicable.
74
75           Args:
76             *array: Numpy array to be used
77             **memtype: memory type of the array being passed, default CEED_MEM_HOST
78             **cmode: copy mode for the array, default CEED_COPY_VALUES"""
79
80        # Setup the numpy array for the libCEED call
81        array_pointer = ffi.new("CeedScalar *")
82        array_pointer = ffi.cast(
83            "CeedScalar *",
84            array.__array_interface__['data'][0])
85
86        # libCEED call
87        lib.CeedVectorSetArray(self._pointer[0], memtype, cmode, array_pointer)
88
89    # Get Vector's data array
90    def get_array(self, memtype=MEM_HOST):
91        """Get read/write access to a Vector via the specified memory type.
92
93           Args:
94             **memtype: memory type of the array being passed, default CEED_MEM_HOST
95
96           Returns:
97             *array: Numpy array"""
98
99        # Retrieve the length of the array
100        length_pointer = ffi.new("CeedInt *")
101        lib.CeedVectorGetLength(self._pointer[0], length_pointer)
102
103        # Setup the pointer's pointer
104        array_pointer = ffi.new("CeedScalar **")
105
106        # libCEED call
107        lib.CeedVectorGetArray(self._pointer[0], memtype, array_pointer)
108
109        # Create buffer object from returned pointer
110        buff = ffi.buffer(
111            array_pointer[0],
112            ffi.sizeof("CeedScalar") *
113            length_pointer[0])
114        # Return numpy array created from buffer
115        return np.frombuffer(buff, dtype="float64")
116
117    # Get Vector's data array in read-only mode
118    def get_array_read(self, memtype=MEM_HOST):
119        """Get read-only access to a Vector via the specified memory type.
120
121           Args:
122             **memtype: memory type of the array being passed, default CEED_MEM_HOST
123
124           Returns:
125             *array: Numpy array"""
126
127        # Retrieve the length of the array
128        length_pointer = ffi.new("CeedInt *")
129        lib.CeedVectorGetLength(self._pointer[0], length_pointer)
130
131        # Setup the pointer's pointer
132        array_pointer = ffi.new("CeedScalar **")
133
134        # libCEED call
135        lib.CeedVectorGetArrayRead(self._pointer[0], memtype, array_pointer)
136
137        # Create buffer object from returned pointer
138        buff = ffi.buffer(
139            array_pointer[0],
140            ffi.sizeof("CeedScalar") *
141            length_pointer[0])
142        # Create numpy array from buffer
143        ret = np.frombuffer(buff, dtype="float64")
144        # Make the numpy array read-only
145        ret.flags['WRITEABLE'] = False
146        return ret
147
148    # Restore the Vector's data array
149    def restore_array(self):
150        """Restore an array obtained using get_array()."""
151
152        # Setup the pointer's pointer
153        array_pointer = ffi.new("CeedScalar **")
154
155        # libCEED call
156        lib.CeedVectorRestoreArray(self._pointer[0], array_pointer)
157
158    # Restore an array obtained using getArrayRead
159    def restore_array_read(self):
160        """Restore an array obtained using get_array_read()."""
161
162        # Setup the pointer's pointer
163        array_pointer = ffi.new("CeedScalar **")
164
165        # libCEED call
166        lib.CeedVectorRestoreArrayRead(self._pointer[0], array_pointer)
167
168    @contextlib.contextmanager
169    def array(self, *shape):
170        """Context manager for array access.
171
172        Args:
173          shape (tuple): shape of returned numpy.array
174
175        Returns:
176          np.array: writable view of vector
177
178        Examples:
179          Constructing the identity inside a libceed.Vector:
180
181          >>> vec = ceed.Vector(16)
182          >>> with vec.array(4, 4) as x:
183          >>>     x[...] = np.eye(4)
184        """
185        x = self.get_array()
186        if shape:
187            x = x.reshape(shape)
188        yield x
189        self.restore_array()
190
191    @contextlib.contextmanager
192    def array_read(self, *shape):
193        """Context manager for read-only array access.
194
195        Args:
196          shape (tuple): shape of returned numpy.array
197
198        Returns:
199          np.array: read-only view of vector
200
201        Examples:
202          Constructing the identity inside a libceed.Vector:
203
204          >>> vec = ceed.Vector(6)
205          >>> vec.set_value(1.3)
206          >>> with vec.array_read(2, 3) as x:
207          >>>     print(x)
208        """
209        x = self.get_array_read()
210        if shape:
211            x = x.reshape(shape)
212        yield x
213        self.restore_array_read()
214
215    # Get the length of a Vector
216    def get_length(self):
217        """Get the length of a Vector.
218
219           Returns:
220             length: length of the Vector"""
221
222        length_pointer = ffi.new("CeedInt *")
223
224        # libCEED call
225        lib.CeedVectorGetLength(self._pointer[0], length_pointer)
226
227        return length_pointer[0]
228
229    # Get the length of a Vector
230    def __len__(self):
231        """Get the length of a Vector.
232
233           Returns:
234             length: length of the Vector"""
235
236        length_pointer = ffi.new("CeedInt *")
237
238        # libCEED call
239        lib.CeedVectorGetLength(self._pointer[0], length_pointer)
240
241        return length_pointer[0]
242
243    # Set the Vector to a given constant value
244    def set_value(self, value):
245        """Set the Vector to a constant value.
246
247           Args:
248             value: value to be used"""
249
250        # libCEED call
251        lib.CeedVectorSetValue(self._pointer[0], value)
252
253    # Sync the Vector to a specified memtype
254    def sync_array(self, memtype=MEM_HOST):
255        """Sync the Vector to a specified memtype.
256
257           Args:
258             **memtype: memtype to be synced"""
259
260        # libCEED call
261        lib.CeedVectorSyncArray(self._pointer[0], memtype)
262
263    # Compute the norm of a vector
264    def norm(self, normtype=NORM_2):
265        """Get the norm of a Vector.
266
267           Args:
268             **normtype: type of norm to be computed"""
269
270        norm_pointer = ffi.new("CeedScalar *")
271
272        # libCEED call
273        lib.CeedVectorNorm(self._pointer[0], normtype, norm_pointer)
274
275        return norm_pointer[0]
276
277# ------------------------------------------------------------------------------
278
279
280class _VectorWrap(Vector):
281    """Wrap a CeedVector pointer in a Vector object."""
282
283    # Constructor
284    def __init__(self, ceed, pointer):
285        # CeedVector object
286        self._pointer = pointer
287
288        # Reference to Ceed
289        self._ceed = ceed
290
291# ------------------------------------------------------------------------------
292