xref: /libCEED/python/ceed_operator.py (revision e9f4dca0bc4c408418619183f355fdd735c60606)
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
19from abc import ABC
20from .ceed_constants import REQUEST_IMMEDIATE, REQUEST_ORDERED, NOTRANSPOSE
21
22# ------------------------------------------------------------------------------
23
24
25class _OperatorBase(ABC):
26    """Ceed Operator: composed FE-type operations on vectors."""
27
28    # Attributes
29    _ceed = ffi.NULL
30    _pointer = ffi.NULL
31
32    # Destructor
33    def __del__(self):
34        # libCEED call
35        err_code = lib.CeedOperatorDestroy(self._pointer)
36        self._ceed._check_error(err_code)
37
38    # Representation
39    def __repr__(self):
40        return "<CeedOperator instance at " + hex(id(self)) + ">"
41
42    # String conversion for print() to stdout
43    def __str__(self):
44        """View an Operator via print()."""
45
46        # libCEED call
47        with tempfile.NamedTemporaryFile() as key_file:
48            with open(key_file.name, 'r+') as stream_file:
49                stream = ffi.cast("FILE *", stream_file)
50
51                err_code = lib.CeedOperatorView(self._pointer[0], stream)
52                self._ceed._check_error(err_code)
53
54                stream_file.seek(0)
55                out_string = stream_file.read()
56
57        return out_string
58
59    # Assemble linear diagonal
60    def linear_assemble_diagonal(self, d, request=REQUEST_IMMEDIATE):
61        """Assemble the diagonal of a square linear Operator
62
63           Args:
64             d: Vector to store assembled Operator diagonal
65             **request: Ceed request, default CEED_REQUEST_IMMEDIATE"""
66
67        # libCEED call
68        err_code = lib.CeedOperatorLinearAssembleDiagonal(self._pointer[0],
69                                                          d._pointer[0], request)
70        self._ceed._check_error(err_code)
71
72    # Assemble add linear diagonal
73    def linear_assemble_add_diagonal(self, d, request=REQUEST_IMMEDIATE):
74        """Sum the diagonal of a square linear Operator into a Vector
75
76           Args:
77             d: Vector to store assembled Operator diagonal
78             **request: Ceed request, default CEED_REQUEST_IMMEDIATE"""
79
80        # libCEED call
81        err_code = lib.CeedOperatorLinearAssembleAddDiagonal(self._pointer[0],
82                                                             d._pointer[0], request)
83        self._ceed._check_error(err_code)
84
85    # Assemble linear point block diagonal
86    def linear_assemble_point_block_diagonal(
87            self, d, request=REQUEST_IMMEDIATE):
88        """Assemble the point block diagonal of a square linear Operator
89
90           Args:
91             d: Vector to store assembled Operator point block diagonal,
92                  provided in row-major form with an ncomp*ncomp block
93                  at each node
94             **request: Ceed request, default CEED_REQUEST_IMMEDIATE"""
95
96        # libCEED call
97        err_code = lib.CeedOperatorLinearAssemblePointBlockDiagonal(self._pointer[0],
98                                                                    d._pointer[0], request)
99        self._ceed._check_error(err_code)
100
101    # Assemble linear point block diagonal
102    def linear_assemble_add_point_block_diagonal(
103            self, d, request=REQUEST_IMMEDIATE):
104        """Sum the point block diagonal of a square linear Operator into a Vector
105
106           Args:
107             d: Vector to store assembled Operator point block diagonal,
108                  provided in row-major form with an ncomp*ncomp block
109                  at each node
110             **request: Ceed request, default CEED_REQUEST_IMMEDIATE"""
111
112        # libCEED call
113        err_code = lib.CeedOperatorLinearAssembleAddPointBlockDiagonal(self._pointer[0],
114                                                                       d._pointer[0], request)
115        self._ceed._check_error(err_code)
116
117    # Apply CeedOperator
118    def apply(self, u, v, request=REQUEST_IMMEDIATE):
119        """Apply Operator to a vector.
120
121           Args:
122             u: Vector containing input state or CEED_VECTOR_NONE if there are no
123                  active inputs
124             v: Vector to store result of applying operator (must be distinct from u)
125                  or CEED_VECTOR_NONE if there are no active outputs
126             **request: Ceed request, default CEED_REQUEST_IMMEDIATE"""
127
128        # libCEED call
129        err_code = lib.CeedOperatorApply(self._pointer[0], u._pointer[0], v._pointer[0],
130                                         request)
131        self._ceed._check_error(err_code)
132
133    # Apply CeedOperator
134    def apply_add(self, u, v, request=REQUEST_IMMEDIATE):
135        """Apply Operator to a vector and add result to output vector.
136
137           Args:
138             u: Vector containing input state or CEED_VECTOR_NONE if there are no
139                  active inputs
140             v: Vector to sum in result of applying operator (must be distinct from u)
141                  or CEED_VECTOR_NONE if there are no active outputs
142             **request: Ceed request, default CEED_REQUEST_IMMEDIATE"""
143
144        # libCEED call
145        err_code = lib.CeedOperatorApplyAdd(self._pointer[0], u._pointer[0], v._pointer[0],
146                                            request)
147        self._ceed._check_error(err_code)
148
149# ------------------------------------------------------------------------------
150
151
152class Operator(_OperatorBase):
153    """Ceed Operator: composed FE-type operations on vectors."""
154
155    # Constructor
156    def __init__(self, ceed, qf, dqf=None, dqfT=None):
157        # CeedOperator object
158        self._pointer = ffi.new("CeedOperator *")
159
160        # Reference to Ceed
161        self._ceed = ceed
162
163        # libCEED call
164        err_code = lib.CeedOperatorCreate(self._ceed._pointer[0], qf._pointer[0],
165                                          dqf._pointer[0] if dqf else ffi.NULL,
166                                          dqfT._pointer[0] if dqfT else ffi.NULL,
167                                          self._pointer)
168        self._ceed._check_error(err_code)
169
170    # Add field to CeedOperator
171    def set_field(self, fieldname, restriction, basis, vector):
172        """Provide a field to an Operator for use by its QFunction.
173
174           Args:
175             fieldname: name of the field (to be matched with the same name used
176                          by QFunction)
177             restriction: ElemRestriction
178             basis: Basis in which the field resides or CEED_BASIS_COLLOCATED
179                      if collocated with quadrature points
180             vector: Vector to be used by Operator or CEED_VECTOR_ACTIVE
181                       if field is active or CEED_VECTOR_NONE if using
182                       CEED_EVAL_WEIGHT in the QFunction"""
183
184        # libCEED call
185        fieldnameAscii = ffi.new("char[]", fieldname.encode('ascii'))
186        err_code = lib.CeedOperatorSetField(self._pointer[0], fieldnameAscii,
187                                            restriction._pointer[0], basis._pointer[0],
188                                            vector._pointer[0])
189        self._ceed._check_error(err_code)
190
191# ------------------------------------------------------------------------------
192
193
194class CompositeOperator(_OperatorBase):
195    """Ceed Composite Operator: composition of multiple Operators."""
196
197    # Constructor
198    def __init__(self, ceed):
199        # CeedOperator object
200        self._pointer = ffi.new("CeedOperator *")
201
202        # Reference to Ceed
203        self._ceed = ceed
204        # libCEED call
205        err_code = lib.CeedCompositeOperatorCreate(
206            self._ceed._pointer[0], self._pointer)
207        self._ceed._check_error(err_code)
208
209    # Add sub operators
210    def add_sub(self, subop):
211        """Add a sub-operator to a composite CeedOperator.
212
213           Args:
214             subop: sub-operator Operator"""
215
216        # libCEED call
217        err_code = lib.CeedCompositeOperatorAddSub(
218            self._pointer[0], subop._pointer[0])
219        self._ceed._check_error(err_code)
220
221# ------------------------------------------------------------------------------
222