xref: /libCEED/python/ceed_vector.py (revision dfa8e3298603c4ff7970d9c72c103860d4fc0517)
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# ------------------------------------------------------------------------------
24class Vector():
25  """Ceed Vector: storing and manipulating vectors."""
26
27  # Attributes
28  _ceed = ffi.NULL
29  _pointer = ffi.NULL
30
31  # Constructor
32  def __init__(self, ceed, size):
33    # CeedVector object
34    self._pointer = ffi.new("CeedVector *")
35
36    # Reference to Ceed
37    self._ceed = ceed
38
39    # libCEED call
40    lib.CeedVectorCreate(self._ceed._pointer[0], size, self._pointer)
41
42  # Destructor
43  def __del__(self):
44    # libCEED call
45    lib.CeedVectorDestroy(self._pointer)
46
47  # Representation
48  def __repr__(self):
49    return "<CeedVector instance at " + hex(id(self)) + ">"
50
51  # String conversion for print() to stdout
52  def __str__(self):
53    """View a Vector via print()."""
54
55    # libCEED call
56    fmt = ffi.new("char[]", "%f".encode('ascii'))
57    with tempfile.NamedTemporaryFile() as key_file:
58      with open(key_file.name, 'r+') as stream_file:
59        stream = ffi.cast("FILE *", stream_file)
60
61        lib.CeedVectorView(self._pointer[0], fmt, stream)
62
63        stream_file.seek(0)
64        out_string = stream_file.read()
65
66    return out_string
67
68  # Set Vector's data array
69  def set_array(self, array, memtype=MEM_HOST, cmode=COPY_VALUES):
70    """Set the array used by a Vector, freeing any previously allocated
71       array if applicable.
72
73       Args:
74         *array: Numpy array to be used
75         **memtype: memory type of the array being passed, default CEED_MEM_HOST
76         **cmode: copy mode for the array, default CEED_COPY_VALUES"""
77
78    # Setup the numpy array for the libCEED call
79    array_pointer = ffi.new("CeedScalar *")
80    array_pointer = ffi.cast("CeedScalar *", array.__array_interface__['data'][0])
81
82    # libCEED call
83    lib.CeedVectorSetArray(self._pointer[0], memtype, cmode, array_pointer)
84
85  # Get Vector's data array
86  def get_array(self, memtype=MEM_HOST):
87    """Get read/write access to a Vector via the specified memory type.
88
89       Args:
90         **memtype: memory type of the array being passed, default CEED_MEM_HOST
91
92       Returns:
93         *array: Numpy array"""
94
95    # Retrieve the length of the array
96    length_pointer = ffi.new("CeedInt *")
97    lib.CeedVectorGetLength(self._pointer[0], length_pointer)
98
99    # Setup the pointer's pointer
100    array_pointer = ffi.new("CeedScalar **")
101
102    # libCEED call
103    lib.CeedVectorGetArray(self._pointer[0], memtype, array_pointer)
104
105    # Create buffer object from returned pointer
106    buff = ffi.buffer(array_pointer[0], ffi.sizeof("CeedScalar") * length_pointer[0])
107    # Return numpy array created from buffer
108    return np.frombuffer(buff, dtype="float64")
109
110  # Get Vector's data array in read-only mode
111  def get_array_read(self, memtype=MEM_HOST):
112    """Get read-only access to a Vector via the specified memory type.
113
114       Args:
115         **memtype: memory type of the array being passed, default CEED_MEM_HOST
116
117       Returns:
118         *array: Numpy array"""
119
120    # Retrieve the length of the array
121    length_pointer = ffi.new("CeedInt *")
122    lib.CeedVectorGetLength(self._pointer[0], length_pointer)
123
124    # Setup the pointer's pointer
125    array_pointer = ffi.new("CeedScalar **")
126
127    # libCEED call
128    lib.CeedVectorGetArrayRead(self._pointer[0], memtype, array_pointer)
129
130    # Create buffer object from returned pointer
131    buff = ffi.buffer(array_pointer[0], ffi.sizeof("CeedScalar") * length_pointer[0])
132    # Create numpy array from buffer
133    ret = np.frombuffer(buff, dtype="float64")
134    # Make the numpy array read-only
135    ret.flags['WRITEABLE'] = False
136    return ret
137
138  # Restore the Vector's data array
139  def restore_array(self):
140    """Restore an array obtained using get_array()."""
141
142    # Setup the pointer's pointer
143    array_pointer = ffi.new("CeedScalar **")
144
145    # libCEED call
146    lib.CeedVectorRestoreArray(self._pointer[0], array_pointer)
147
148  # Restore an array obtained using getArrayRead
149  def restore_array_read(self):
150    """Restore an array obtained using get_array_read()."""
151
152    # Setup the pointer's pointer
153    array_pointer = ffi.new("CeedScalar **")
154
155    # libCEED call
156    lib.CeedVectorRestoreArrayRead(self._pointer[0], array_pointer)
157
158  @contextlib.contextmanager
159  def array(self, *shape):
160    """Context manager for array access.
161
162    Args:
163      shape (tuple): shape of returned numpy.array
164
165    Returns:
166      np.array: writable view of vector
167
168    Examples:
169      Constructing the identity inside a libceed.Vector:
170
171      >>> vec = ceed.Vector(16)
172      >>> with vec.array(4, 4) as x:
173      >>>     x[...] = np.eye(4)
174    """
175    x = self.get_array()
176    if shape:
177      x = x.reshape(shape)
178    yield x
179    self.restore_array()
180
181  @contextlib.contextmanager
182  def array_read(self, *shape):
183    """Context manager for read-only array access.
184
185    Args:
186      shape (tuple): shape of returned numpy.array
187
188    Returns:
189      np.array: read-only view of vector
190
191    Examples:
192      Constructing the identity inside a libceed.Vector:
193
194      >>> vec = ceed.Vector(6)
195      >>> vec.set_value(1.3)
196      >>> with vec.array_read(2, 3) as x:
197      >>>     print(x)
198    """
199    x = self.get_array_read()
200    if shape:
201      x = x.reshape(shape)
202    yield x
203    self.restore_array_read()
204
205  # Get the length of a Vector
206  def get_length(self):
207    """Get the length of a Vector.
208
209       Returns:
210         length: length of the Vector"""
211
212    length_pointer = ffi.new("CeedInt *")
213
214    # libCEED call
215    lib.CeedVectorGetLength(self._pointer[0], length_pointer)
216
217    return length_pointer[0]
218
219  # Get the length of a Vector
220  def __len__(self):
221    """Get the length of a Vector.
222
223       Returns:
224         length: length of the Vector"""
225
226    length_pointer = ffi.new("CeedInt *")
227
228    # libCEED call
229    lib.CeedVectorGetLength(self._pointer[0], length_pointer)
230
231    return length_pointer[0]
232
233  # Set the Vector to a given constant value
234  def set_value(self, value):
235    """Set the Vector to a constant value.
236
237       Args:
238         value: value to be used"""
239
240    # libCEED call
241    lib.CeedVectorSetValue(self._pointer[0], value)
242
243  # Sync the Vector to a specified memtype
244  def sync_array(self, memtype=MEM_HOST):
245    """Sync the Vector to a specified memtype.
246
247       Args:
248         **memtype: memtype to be synced"""
249
250    # libCEED call
251    lib.CeedVectorSyncArray(self._pointer[0], memtype)
252
253  # Compute the norm of a vector
254  def norm(self, normtype=NORM_2):
255    """Get the norm of a Vector.
256
257       Args:
258         **normtype: type of norm to be computed"""
259
260    norm_pointer = ffi.new("CeedScalar *")
261
262    # libCEED call
263    lib.CeedVectorNorm(self._pointer[0], normtype, norm_pointer)
264
265    return norm_pointer[0]
266
267# ------------------------------------------------------------------------------
268class _VectorWrap(Vector):
269  """Wrap a CeedVector pointer in a Vector object."""
270
271  # Constructor
272  def __init__(self, ceed, pointer):
273    # CeedVector object
274    self._pointer = pointer
275
276    # Reference to Ceed
277    self._ceed = ceed
278
279# ------------------------------------------------------------------------------
280