1# Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors 2# All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3# 4# SPDX-License-Identifier: BSD-2-Clause 5# 6# This file is part of CEED: http://github.com/ceed 7 8from _ceed_cffi import ffi, lib 9import tempfile 10from abc import ABC 11from .ceed_constants import REQUEST_IMMEDIATE, REQUEST_ORDERED, NOTRANSPOSE 12 13# ------------------------------------------------------------------------------ 14 15 16class _OperatorBase(ABC): 17 """Ceed Operator: composed FE-type operations on vectors.""" 18 19 # Destructor 20 def __del__(self): 21 # libCEED call 22 err_code = lib.CeedOperatorDestroy(self._pointer) 23 self._ceed._check_error(err_code) 24 25 # Representation 26 def __repr__(self): 27 return "<CeedOperator instance at " + hex(id(self)) + ">" 28 29 # String conversion for print() to stdout 30 def __str__(self): 31 """View an Operator via print().""" 32 33 # libCEED call 34 with tempfile.NamedTemporaryFile() as key_file: 35 with open(key_file.name, 'r+') as stream_file: 36 stream = ffi.cast("FILE *", stream_file) 37 38 err_code = lib.CeedOperatorView(self._pointer[0], stream) 39 self._ceed._check_error(err_code) 40 41 stream_file.seek(0) 42 out_string = stream_file.read() 43 44 return out_string 45 46 # Check Operator setup 47 def check(self): 48 """Check if a CeedOperator is ready to be used""" 49 # libCEED call 50 err_code = lib.CeedOperatorCheckReady(self._pointer[0]) 51 self._ceed._check_error(err_code) 52 53 # Assemble linear diagonal 54 def linear_assemble_diagonal(self, d, request=REQUEST_IMMEDIATE): 55 """Assemble the diagonal of a square linear Operator 56 57 Args: 58 d: Vector to store assembled Operator diagonal 59 **request: Ceed request, default CEED_REQUEST_IMMEDIATE""" 60 61 # libCEED call 62 err_code = lib.CeedOperatorLinearAssembleDiagonal(self._pointer[0], 63 d._pointer[0], request) 64 self._ceed._check_error(err_code) 65 66 # Assemble add linear diagonal 67 def linear_assemble_add_diagonal(self, d, request=REQUEST_IMMEDIATE): 68 """Sum the diagonal of a square linear Operator into a Vector 69 70 Args: 71 d: Vector to store assembled Operator diagonal 72 **request: Ceed request, default CEED_REQUEST_IMMEDIATE""" 73 74 # libCEED call 75 err_code = lib.CeedOperatorLinearAssembleAddDiagonal(self._pointer[0], 76 d._pointer[0], request) 77 self._ceed._check_error(err_code) 78 79 # Assemble linear point block diagonal 80 def linear_assemble_point_block_diagonal( 81 self, d, request=REQUEST_IMMEDIATE): 82 """Assemble the point block diagonal of a square linear Operator 83 84 Args: 85 d: Vector to store assembled Operator point block diagonal, 86 provided in row-major form with an ncomp*ncomp block 87 at each node 88 **request: Ceed request, default CEED_REQUEST_IMMEDIATE""" 89 90 # libCEED call 91 err_code = lib.CeedOperatorLinearAssemblePointBlockDiagonal(self._pointer[0], 92 d._pointer[0], request) 93 self._ceed._check_error(err_code) 94 95 # Assemble linear point block diagonal 96 def linear_assemble_add_point_block_diagonal( 97 self, d, request=REQUEST_IMMEDIATE): 98 """Sum the point block diagonal of a square linear Operator into a Vector 99 100 Args: 101 d: Vector to store assembled Operator point block diagonal, 102 provided in row-major form with an ncomp*ncomp block 103 at each node 104 **request: Ceed request, default CEED_REQUEST_IMMEDIATE""" 105 106 # libCEED call 107 err_code = lib.CeedOperatorLinearAssembleAddPointBlockDiagonal(self._pointer[0], 108 d._pointer[0], request) 109 self._ceed._check_error(err_code) 110 111 # Apply CeedOperator 112 def apply(self, u, v, request=REQUEST_IMMEDIATE): 113 """Apply Operator to a vector. 114 115 Args: 116 u: Vector containing input state or CEED_VECTOR_NONE if there are no 117 active inputs 118 v: Vector to store result of applying operator (must be distinct from u) 119 or CEED_VECTOR_NONE if there are no active outputs 120 **request: Ceed request, default CEED_REQUEST_IMMEDIATE""" 121 122 # libCEED call 123 err_code = lib.CeedOperatorApply(self._pointer[0], u._pointer[0], v._pointer[0], 124 request) 125 self._ceed._check_error(err_code) 126 127 # Apply CeedOperator 128 def apply_add(self, u, v, request=REQUEST_IMMEDIATE): 129 """Apply Operator to a vector and add result to output vector. 130 131 Args: 132 u: Vector containing input state or CEED_VECTOR_NONE if there are no 133 active inputs 134 v: Vector to sum in result of applying operator (must be distinct from u) 135 or CEED_VECTOR_NONE if there are no active outputs 136 **request: Ceed request, default CEED_REQUEST_IMMEDIATE""" 137 138 # libCEED call 139 err_code = lib.CeedOperatorApplyAdd(self._pointer[0], u._pointer[0], v._pointer[0], 140 request) 141 self._ceed._check_error(err_code) 142 143 # Create Multigrid Level 144 def multigrid_create(self, p_mult_fine, rstr_coarse, basis_coarse): 145 """ Create a multigrid coarse operator and level transfer operators 146 for a CeedOperator with a Lagrange tensor basis for the active basis 147 148 Args: 149 p_mult_fine: L-vector multiplicity in parallel gather/scatter 150 basis_coarse: Coarse grid active vector basis 151 degree_coarse: Coarse grid basis polynomial order""" 152 153 # Operator pointers 154 opCoarsePointer = ffi.new("CeedOperator *") 155 opProlongPointer = ffi.new("CeedOperator *") 156 opRestrictPointer = ffi.new("CeedOperator *") 157 158 # libCEED call 159 lib.CeedOperatorMultigridLevelCreate(self._pointer[0], 160 p_mult_fine._pointer[0], 161 rstr_coarse._pointer[0], 162 basis_coarse._pointer[0], 163 opCoarsePointer, 164 opProlongPointer, 165 opRestrictPointer) 166 167 # Wrap operators 168 opCoarse = _OperatorWrap( 169 self._ceed, opCoarsePointer) 170 opProlong = _OperatorWrap( 171 self._ceed, opProlongPointer) 172 opRestrict = _OperatorWrap( 173 self._ceed, opRestrictPointer) 174 175 # Return 176 return [opCoarse, opProlong, opRestrict] 177 178 # Create Multigrid Level 179 def multigrid_create_tensor_h1(self, p_mult_fine, rstr_coarse, basis_coarse, 180 interp_C_to_F): 181 """ Create a multigrid coarse operator and level transfer operators 182 for a CeedOperator with a non-tensor basis for the active basis 183 184 Args: 185 p_mult_fine: L-vector multiplicity in parallel gather/scatter 186 rstr_coarse: Coarse grid restriction 187 basis_coarse: Coarse grid active vector basis 188 interp_C_to_F: Matrix for coarse to fine interpolation""" 189 190 # Setup arguments 191 interpCtoF_pointer = ffi.new("CeedScalar *") 192 interpCtoF_pointer = ffi.cast( 193 "CeedScalar *", 194 interp_C_to_F.__array_interface__['data'][0]) 195 196 # Operator pointers 197 opCoarsePointer = ffi.new("CeedOperator *") 198 opProlongPointer = ffi.new("CeedOperator *") 199 opRestrictPointer = ffi.new("CeedOperator *") 200 201 # libCEED call 202 lib.CeedOperatorMultigridLevelCreateTensorH1(self._pointer[0], 203 p_mult_fine._pointer[0], 204 rstr_coarse._pointer[0], 205 basis_coarse._pointer[0], 206 interpCtoF_pointer, 207 opCoarsePointer, 208 opProlongPointer, 209 opRestrictPointer) 210 211 # Wrap operators 212 opCoarse = _OperatorWrap( 213 self._ceed, opCoarsePointer) 214 opProlong = _OperatorWrap( 215 self._ceed, opProlongPointer) 216 opRestrict = _OperatorWrap( 217 self._ceed, opRestrictPointer) 218 219 # Return 220 return [opCoarse, opProlong, opRestrict] 221 222 # Create Multigrid Level 223 def multigrid_create_h1(self, p_mult_fine, rstr_coarse, basis_coarse, 224 interp_C_to_F): 225 """ Create a multigrid coarse operator and level transfer operators 226 for a CeedOperator with a Lagrange tensor basis for the active basis 227 228 Args: 229 p_mult_fine: L-vector multiplicity in parallel gather/scatter 230 rstr_coarse: Coarse grid restriction 231 basis_coarse: Coarse grid active vector basis 232 interp_C_to_F: Matrix for coarse to fine interpolation""" 233 234 # Setup arguments 235 interpCtoF_pointer = ffi.new("CeedScalar *") 236 interpCtoF_pointer = ffi.cast( 237 "CeedScalar *", 238 interp_C_to_F.__array_interface__['data'][0]) 239 240 # Operator pointers 241 opCoarsePointer = ffi.new("CeedOperator *") 242 opProlongPointer = ffi.new("CeedOperator *") 243 opRestrictPointer = ffi.new("CeedOperator *") 244 245 # libCEED call 246 lib.CeedOperatorMultigridLevelCreateH1(self._pointer[0], 247 p_mult_fine._pointer[0], 248 rstr_coarse._pointer[0], 249 basis_coarse._pointer[0], 250 interpCtoF_pointer, 251 opCoarsePointer, 252 opProlongPointer, 253 opRestrictPointer) 254 255 # Wrap operators 256 opCoarse = _OperatorWrap( 257 self._ceed, opCoarsePointer) 258 opProlong = _OperatorWrap( 259 self._ceed, opProlongPointer) 260 opRestrict = _OperatorWrap( 261 self._ceed, opRestrictPointer) 262 263 # Return 264 return [opCoarse, opProlong, opRestrict] 265 266 267# ------------------------------------------------------------------------------ 268 269 270class Operator(_OperatorBase): 271 """Ceed Operator: composed FE-type operations on vectors.""" 272 273 # Constructor 274 def __init__(self, ceed, qf, dqf=None, dqfT=None): 275 # CeedOperator object 276 self._pointer = ffi.new("CeedOperator *") 277 278 # Reference to Ceed 279 self._ceed = ceed 280 281 # libCEED call 282 err_code = lib.CeedOperatorCreate(self._ceed._pointer[0], qf._pointer[0], 283 dqf._pointer[0] if dqf else ffi.NULL, 284 dqfT._pointer[0] if dqfT else ffi.NULL, 285 self._pointer) 286 self._ceed._check_error(err_code) 287 288 # Add field to CeedOperator 289 def set_field(self, fieldname, restriction, basis, vector): 290 """Provide a field to an Operator for use by its QFunction. 291 292 Args: 293 fieldname: name of the field (to be matched with the same name used 294 by QFunction) 295 restriction: ElemRestriction 296 basis: Basis in which the field resides or CEED_BASIS_COLLOCATED 297 if collocated with quadrature points 298 vector: Vector to be used by Operator or CEED_VECTOR_ACTIVE 299 if field is active or CEED_VECTOR_NONE if using 300 CEED_EVAL_WEIGHT in the QFunction""" 301 302 # libCEED call 303 fieldnameAscii = ffi.new("char[]", fieldname.encode('ascii')) 304 err_code = lib.CeedOperatorSetField(self._pointer[0], fieldnameAscii, 305 restriction._pointer[0], basis._pointer[0], 306 vector._pointer[0]) 307 self._ceed._check_error(err_code) 308 309# ------------------------------------------------------------------------------ 310 311 312class CompositeOperator(_OperatorBase): 313 """Ceed Composite Operator: composition of multiple Operators.""" 314 315 # Constructor 316 def __init__(self, ceed): 317 # CeedOperator object 318 self._pointer = ffi.new("CeedOperator *") 319 320 # Reference to Ceed 321 self._ceed = ceed 322 # libCEED call 323 err_code = lib.CeedCompositeOperatorCreate( 324 self._ceed._pointer[0], self._pointer) 325 self._ceed._check_error(err_code) 326 327 # Add sub operators 328 def add_sub(self, subop): 329 """Add a sub-operator to a composite CeedOperator. 330 331 Args: 332 subop: sub-operator Operator""" 333 334 # libCEED call 335 err_code = lib.CeedCompositeOperatorAddSub( 336 self._pointer[0], subop._pointer[0]) 337 self._ceed._check_error(err_code) 338 339# ------------------------------------------------------------------------------ 340 341 342class _OperatorWrap(Operator): 343 """Wrap a CeedOperator pointer in a Operator object.""" 344 345 # Constructor 346 def __init__(self, ceed, pointer): 347 # CeedOperator object 348 self._pointer = pointer 349 350 # Reference to Ceed 351 self._ceed = ceed 352 353# ------------------------------------------------------------------------------ 354