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 17 #include <ceed-impl.h> 18 #include <ceed-backend.h> 19 #include <string.h> 20 #include <math.h> 21 22 /// @file 23 /// Implementation of public CeedOperator interfaces 24 /// 25 /// @addtogroup CeedOperator 26 /// @{ 27 28 /** 29 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 30 CeedElemRestriction can be associated with CeedQFunction fields with 31 \ref CeedOperatorSetField. 32 33 @param ceed A Ceed object where the CeedOperator will be created 34 @param qf QFunction defining the action of the operator at quadrature points 35 @param dqf QFunction defining the action of the Jacobian of @a qf (or 36 CEED_QFUNCTION_NONE) 37 @param dqfT QFunction defining the action of the transpose of the Jacobian 38 of @a qf (or CEED_QFUNCTION_NONE) 39 @param[out] op Address of the variable where the newly created 40 CeedOperator will be stored 41 42 @return An error code: 0 - success, otherwise - failure 43 44 @ref Basic 45 */ 46 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 47 CeedQFunction dqfT, CeedOperator *op) { 48 int ierr; 49 50 if (!ceed->OperatorCreate) { 51 Ceed delegate; 52 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 53 54 if (!delegate) 55 // LCOV_EXCL_START 56 return CeedError(ceed, 1, "Backend does not support OperatorCreate"); 57 // LCOV_EXCL_STOP 58 59 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 60 return 0; 61 } 62 63 ierr = CeedCalloc(1, op); CeedChk(ierr); 64 (*op)->ceed = ceed; 65 ceed->refcount++; 66 (*op)->refcount = 1; 67 if (qf == CEED_QFUNCTION_NONE) 68 // LCOV_EXCL_START 69 return CeedError(ceed, 1, "Operator must have a valid QFunction."); 70 // LCOV_EXCL_STOP 71 (*op)->qf = qf; 72 qf->refcount++; 73 if (dqf && dqf != CEED_QFUNCTION_NONE) { 74 (*op)->dqf = dqf; 75 dqf->refcount++; 76 } 77 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 78 (*op)->dqfT = dqfT; 79 dqfT->refcount++; 80 } 81 ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr); 82 ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr); 83 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 84 return 0; 85 } 86 87 /** 88 @brief Create an operator that composes the action of several operators 89 90 @param ceed A Ceed object where the CeedOperator will be created 91 @param[out] op Address of the variable where the newly created 92 Composite CeedOperator will be stored 93 94 @return An error code: 0 - success, otherwise - failure 95 96 @ref Basic 97 */ 98 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 99 int ierr; 100 101 if (!ceed->CompositeOperatorCreate) { 102 Ceed delegate; 103 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 104 105 if (delegate) { 106 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 107 return 0; 108 } 109 } 110 111 ierr = CeedCalloc(1, op); CeedChk(ierr); 112 (*op)->ceed = ceed; 113 ceed->refcount++; 114 (*op)->composite = true; 115 ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr); 116 117 if (ceed->CompositeOperatorCreate) { 118 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 119 } 120 return 0; 121 } 122 123 /** 124 @brief Provide a field to a CeedOperator for use by its CeedQFunction 125 126 This function is used to specify both active and passive fields to a 127 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 128 fields can inputs or outputs (updated in-place when operator is applied). 129 130 Active fields must be specified using this function, but their data (in a 131 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 132 input and at most one active output. 133 134 @param op CeedOperator on which to provide the field 135 @param fieldname Name of the field (to be matched with the name used by 136 CeedQFunction) 137 @param r CeedElemRestriction 138 @param lmode CeedTransposeMode which specifies the ordering of the 139 components of the l-vector used by this CeedOperatorField, 140 CEED_NOTRANSPOSE indicates the component is the 141 outermost index and CEED_TRANSPOSE indicates the component 142 is the innermost index in ordering of the l-vector 143 @param b CeedBasis in which the field resides or CEED_BASIS_COLLOCATED 144 if collocated with quadrature points 145 @param v CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE 146 if field is active or CEED_VECTOR_NONE if using 147 CEED_EVAL_WEIGHT in the QFunction 148 149 @return An error code: 0 - success, otherwise - failure 150 151 @ref Basic 152 **/ 153 int CeedOperatorSetField(CeedOperator op, const char *fieldname, 154 CeedElemRestriction r, CeedTransposeMode lmode, 155 CeedBasis b, CeedVector v) { 156 int ierr; 157 if (op->composite) 158 // LCOV_EXCL_START 159 return CeedError(op->ceed, 1, "Cannot add field to composite operator."); 160 // LCOV_EXCL_STOP 161 if (!r) 162 // LCOV_EXCL_START 163 return CeedError(op->ceed, 1, 164 "ElemRestriction r for field \"%s\" must be non-NULL.", 165 fieldname); 166 // LCOV_EXCL_STOP 167 if (!b) 168 // LCOV_EXCL_START 169 return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.", 170 fieldname); 171 // LCOV_EXCL_STOP 172 if (!v) 173 // LCOV_EXCL_START 174 return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.", 175 fieldname); 176 // LCOV_EXCL_STOP 177 178 CeedInt numelements; 179 ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr); 180 if (op->hasrestriction && op->numelements != numelements) 181 // LCOV_EXCL_START 182 return CeedError(op->ceed, 1, 183 "ElemRestriction with %d elements incompatible with prior " 184 "%d elements", numelements, op->numelements); 185 // LCOV_EXCL_STOP 186 op->numelements = numelements; 187 op->hasrestriction = true; // Restriction set, but numelements may be 0 188 189 if (b != CEED_BASIS_COLLOCATED) { 190 CeedInt numqpoints; 191 ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr); 192 if (op->numqpoints && op->numqpoints != numqpoints) 193 // LCOV_EXCL_START 194 return CeedError(op->ceed, 1, "Basis with %d quadrature points " 195 "incompatible with prior %d points", numqpoints, 196 op->numqpoints); 197 // LCOV_EXCL_STOP 198 op->numqpoints = numqpoints; 199 } 200 CeedOperatorField *ofield; 201 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 202 if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) { 203 ofield = &op->inputfields[i]; 204 goto found; 205 } 206 } 207 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 208 if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) { 209 ofield = &op->outputfields[i]; 210 goto found; 211 } 212 } 213 // LCOV_EXCL_START 214 return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'", 215 fieldname); 216 // LCOV_EXCL_STOP 217 found: 218 ierr = CeedCalloc(1, ofield); CeedChk(ierr); 219 (*ofield)->Erestrict = r; 220 r->refcount += 1; 221 (*ofield)->lmode = lmode; 222 (*ofield)->basis = b; 223 if (b != CEED_BASIS_COLLOCATED) 224 b->refcount += 1; 225 (*ofield)->vec = v; 226 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) 227 v->refcount += 1; 228 op->nfields += 1; 229 return 0; 230 } 231 232 /** 233 @brief Add a sub-operator to a composite CeedOperator 234 235 @param[out] compositeop Composite CeedOperator 236 @param subop Sub-operator CeedOperator 237 238 @return An error code: 0 - success, otherwise - failure 239 240 @ref Basic 241 */ 242 int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) { 243 if (!compositeop->composite) 244 // LCOV_EXCL_START 245 return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite " 246 "operator"); 247 // LCOV_EXCL_STOP 248 249 if (compositeop->numsub == CEED_COMPOSITE_MAX) 250 // LCOV_EXCL_START 251 return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators"); 252 // LCOV_EXCL_STOP 253 254 compositeop->suboperators[compositeop->numsub] = subop; 255 subop->refcount++; 256 compositeop->numsub++; 257 return 0; 258 } 259 260 /** 261 @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced 262 CeedOperator functionality 263 264 @param op CeedOperator to create fallback for 265 266 @return An error code: 0 - success, otherwise - failure 267 268 @ref Developer 269 **/ 270 int CeedOperatorCreateFallback(CeedOperator op) { 271 int ierr; 272 273 // Fallback Ceed 274 const char *resource, *fallbackresource; 275 ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 276 ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource); 277 CeedChk(ierr); 278 if (!strcmp(resource, fallbackresource)) 279 // LCOV_EXCL_START 280 return CeedError(op->ceed, 1, "Backend %s cannot create an operator" 281 "fallback to resource %s", resource, fallbackresource); 282 // LCOV_EXCL_STOP 283 284 Ceed ceedref; 285 ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr); 286 ceedref->opfallbackparent = op->ceed; 287 op->ceed->opfallbackceed = ceedref; 288 289 // Clone Op 290 CeedOperator opref; 291 ierr = CeedCalloc(1, &opref); CeedChk(ierr); 292 memcpy(opref, op, sizeof(*opref)); CeedChk(ierr); 293 opref->data = NULL; 294 opref->setupdone = 0; 295 opref->ceed = ceedref; 296 ierr = ceedref->OperatorCreate(opref); CeedChk(ierr); 297 op->opfallback = opref; 298 299 // Clone QF 300 CeedQFunction qfref; 301 ierr = CeedCalloc(1, &qfref); CeedChk(ierr); 302 memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr); 303 qfref->data = NULL; 304 qfref->ceed = ceedref; 305 ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr); 306 opref->qf = qfref; 307 op->qffallback = qfref; 308 309 return 0; 310 } 311 312 /** 313 @brief Check if a CeedOperator is ready to be used. 314 315 @param[in] ceed Ceed object for error handling 316 @param[in] op CeedOperator to check 317 318 @return An error code: 0 - success, otherwise - failure 319 320 @ref Basic 321 **/ 322 static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) { 323 CeedQFunction qf = op->qf; 324 325 if (op->composite) { 326 if (!op->numsub) 327 // LCOV_EXCL_START 328 return CeedError(ceed, 1, "No suboperators set"); 329 // LCOV_EXCL_STOP 330 } else { 331 if (op->nfields == 0) 332 // LCOV_EXCL_START 333 return CeedError(ceed, 1, "No operator fields set"); 334 // LCOV_EXCL_STOP 335 if (op->nfields < qf->numinputfields + qf->numoutputfields) 336 // LCOV_EXCL_START 337 return CeedError(ceed, 1, "Not all operator fields set"); 338 // LCOV_EXCL_STOP 339 if (!op->hasrestriction) 340 // LCOV_EXCL_START 341 return CeedError(ceed, 1,"At least one restriction required"); 342 // LCOV_EXCL_STOP 343 if (op->numqpoints == 0) 344 // LCOV_EXCL_START 345 return CeedError(ceed, 1,"At least one non-collocated basis required"); 346 // LCOV_EXCL_STOP 347 } 348 349 return 0; 350 } 351 352 /** 353 @brief Assemble a linear CeedQFunction associated with a CeedOperator 354 355 This returns a CeedVector containing a matrix at each quadrature point 356 providing the action of the CeedQFunction associated with the CeedOperator. 357 The vector 'assembled' is of shape 358 [num_elements, num_input_fields, num_output_fields, num_quad_points] 359 and contains column-major matrices representing the action of the 360 CeedQFunction for a corresponding quadrature point on an element. Inputs and 361 outputs are in the order provided by the user when adding CeedOperator fields. 362 For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 363 'v', provided in that order, would result in an assembled QFunction that 364 consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 365 on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 366 367 @param op CeedOperator to assemble CeedQFunction 368 @param[out] assembled CeedVector to store assembled CeedQFunction at 369 quadrature points 370 @param[out] rstr CeedElemRestriction for CeedVector containing assembled 371 CeedQFunction 372 @param request Address of CeedRequest for non-blocking completion, else 373 CEED_REQUEST_IMMEDIATE 374 375 @return An error code: 0 - success, otherwise - failure 376 377 @ref Basic 378 **/ 379 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled, 380 CeedElemRestriction *rstr, 381 CeedRequest *request) { 382 int ierr; 383 Ceed ceed = op->ceed; 384 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 385 386 if (op->AssembleLinearQFunction) { 387 ierr = op->AssembleLinearQFunction(op, assembled, rstr, request); 388 CeedChk(ierr); 389 } else { 390 // Fallback to reference Ceed 391 if (!op->opfallback) { 392 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 393 } 394 // Assemble 395 ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled, 396 rstr, request); CeedChk(ierr); 397 } 398 399 return 0; 400 } 401 402 /** 403 @brief Assemble the diagonal of a square linear Operator 404 405 This returns a CeedVector containing the diagonal of a linear CeedOperator. 406 407 @param op CeedOperator to assemble CeedQFunction 408 @param[out] assembled CeedVector to store assembled CeedOperator diagonal 409 @param request Address of CeedRequest for non-blocking completion, else 410 CEED_REQUEST_IMMEDIATE 411 412 @return An error code: 0 - success, otherwise - failure 413 414 @ref Basic 415 **/ 416 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled, 417 CeedRequest *request) { 418 int ierr; 419 Ceed ceed = op->ceed; 420 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 421 422 // Use backend version, if available 423 if (op->AssembleLinearDiagonal) { 424 ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr); 425 return 0; 426 } 427 428 // Assemble QFunction 429 CeedQFunction qf = op->qf; 430 CeedVector assembledqf; 431 CeedElemRestriction rstr; 432 ierr = CeedOperatorAssembleLinearQFunction(op, &assembledqf, &rstr, request); 433 CeedChk(ierr); 434 ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr); 435 436 // Determine active input basis 437 CeedInt numemodein = 0, ncomp, dim = 1; 438 CeedEvalMode *emodein = NULL; 439 CeedBasis basisin = NULL; 440 CeedElemRestriction rstrin = NULL; 441 for (CeedInt i=0; i<qf->numinputfields; i++) 442 if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) { 443 ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin); 444 CeedChk(ierr); 445 ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr); 446 ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr); 447 ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin); 448 CeedChk(ierr); 449 CeedEvalMode emode; 450 ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode); 451 CeedChk(ierr); 452 switch (emode) { 453 case CEED_EVAL_NONE: 454 case CEED_EVAL_INTERP: 455 ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr); 456 emodein[numemodein] = emode; 457 numemodein += 1; 458 break; 459 case CEED_EVAL_GRAD: 460 ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr); 461 for (CeedInt d=0; d<dim; d++) 462 emodein[numemodein+d] = emode; 463 numemodein += dim; 464 break; 465 case CEED_EVAL_WEIGHT: 466 case CEED_EVAL_DIV: 467 case CEED_EVAL_CURL: 468 break; // Caught by QF Assembly 469 } 470 } 471 472 // Determine active output basis 473 CeedInt numemodeout = 0; 474 CeedEvalMode *emodeout = NULL; 475 CeedBasis basisout = NULL; 476 CeedElemRestriction rstrout = NULL; 477 CeedTransposeMode lmodeout = CEED_NOTRANSPOSE; 478 for (CeedInt i=0; i<qf->numoutputfields; i++) 479 if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) { 480 ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout); 481 CeedChk(ierr); 482 ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout); 483 CeedChk(ierr); 484 ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout); 485 CeedChk(ierr); 486 CeedEvalMode emode; 487 ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode); 488 CeedChk(ierr); 489 switch (emode) { 490 case CEED_EVAL_NONE: 491 case CEED_EVAL_INTERP: 492 ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr); 493 emodeout[numemodeout] = emode; 494 numemodeout += 1; 495 break; 496 case CEED_EVAL_GRAD: 497 ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr); 498 for (CeedInt d=0; d<dim; d++) 499 emodeout[numemodeout+d] = emode; 500 numemodeout += dim; 501 break; 502 case CEED_EVAL_WEIGHT: 503 case CEED_EVAL_DIV: 504 case CEED_EVAL_CURL: 505 break; // Caught by QF Assembly 506 } 507 } 508 509 // Create diagonal vector 510 CeedVector elemdiag; 511 ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag); 512 CeedChk(ierr); 513 514 // Assemble element operator diagonals 515 CeedScalar *elemdiagarray, *assembledqfarray; 516 ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr); 517 ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray); 518 CeedChk(ierr); 519 ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray); 520 CeedChk(ierr); 521 CeedInt nelem, nnodes, nqpts; 522 ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr); 523 ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr); 524 ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr); 525 // Compute the diagonal of B^T D B 526 // Each node, qpt pair 527 for (CeedInt n=0; n<nnodes; n++) 528 for (CeedInt q=0; q<nqpts; q++) { 529 CeedInt dout = -1; 530 // Each basis eval mode pair 531 for (CeedInt eout=0; eout<numemodeout; eout++) { 532 CeedScalar bt = 1.0; 533 if (emodeout[eout] == CEED_EVAL_GRAD) 534 dout += 1; 535 ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt); 536 CeedChk(ierr); 537 CeedInt din = -1; 538 for (CeedInt ein=0; ein<numemodein; ein++) { 539 CeedScalar b = 0.0; 540 if (emodein[ein] == CEED_EVAL_GRAD) 541 din += 1; 542 ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b); 543 CeedChk(ierr); 544 // Each element and component 545 for (CeedInt e=0; e<nelem; e++) 546 for (CeedInt cout=0; cout<ncomp; cout++) { 547 CeedScalar db = 0.0; 548 for (CeedInt cin=0; cin<ncomp; cin++) 549 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)* 550 numemodeout+eout)*ncomp+cout)*nqpts+q]*b; 551 elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db; 552 } 553 } 554 } 555 } 556 557 ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr); 558 ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr); 559 560 // Assemble local operator diagonal 561 ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr); 562 ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag, 563 *assembled, request); CeedChk(ierr); 564 565 // Cleanup 566 ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr); 567 ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr); 568 ierr = CeedFree(&emodein); CeedChk(ierr); 569 ierr = CeedFree(&emodeout); CeedChk(ierr); 570 571 return 0; 572 } 573 574 /** 575 @brief Build a FDM based approximate inverse for each element for a 576 CeedOperator 577 578 This returns a CeedOperator and CeedVector to apply a Fast Diagonalization 579 Method based approximate inverse. This function obtains the simultaneous 580 diagonalization for the 1D mass and Laplacian operators, 581 M = V^T V, K = V^T S V. 582 The assembled QFunction is used to modify the eigenvalues from simultaneous 583 diagonalization and obtain an approximate inverse of the form 584 V^T S^hat V. The CeedOperator must be linear and non-composite. The 585 associated CeedQFunction must therefore also be linear. 586 587 @param op CeedOperator to create element inverses 588 @param[out] fdminv CeedOperator to apply the action of a FDM based inverse 589 for each element 590 @param[out] qdata CeedVector to hold qdata for fdminv 591 @param request Address of CeedRequest for non-blocking completion, else 592 CEED_REQUEST_IMMEDIATE 593 594 @return An error code: 0 - success, otherwise - failure 595 596 @ref Advanced 597 **/ 598 int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv, 599 CeedRequest *request) { 600 int ierr; 601 Ceed ceed = op->ceed; 602 603 // Determine active input basis 604 bool interp = false, grad = false; 605 CeedBasis basis = NULL; 606 CeedElemRestriction rstr = NULL; 607 for (CeedInt i=0; i<op->qf->numinputfields; i++) 608 if (op->inputfields[i] && op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) { 609 basis = op->inputfields[i]->basis; 610 interp = interp || op->qf->inputfields[i]->emode == CEED_EVAL_INTERP; 611 grad = grad || op->qf->inputfields[i]->emode == CEED_EVAL_GRAD; 612 rstr = op->inputfields[i]->Erestrict; 613 } 614 if (!basis) 615 return CeedError(ceed, 1, "No active field set"); 616 CeedInt P1d, Q1d, elemsize, nqpts, dim, ncomp = 1, nelem = 1, nnodes = 1; 617 ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr); 618 ierr = CeedBasisGetNumNodes(basis, &elemsize); CeedChk(ierr); 619 ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr); 620 ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpts); CeedChk(ierr); 621 ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr); 622 ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr); 623 ierr = CeedElemRestrictionGetNumElements(rstr, &nelem); CeedChk(ierr); 624 ierr = CeedElemRestrictionGetNumNodes(rstr, &nnodes); CeedChk(ierr); 625 626 // Build and diagonalize 1D Mass and Laplacian 627 if (!basis->tensorbasis) 628 return CeedError(ceed, 1, "FDMElementInverse only supported for tensor " 629 "bases"); 630 CeedScalar *work, *mass, *laplace, *x, *x2, *lambda; 631 ierr = CeedMalloc(Q1d*P1d, &work); CeedChk(ierr); 632 ierr = CeedMalloc(P1d*P1d, &mass); CeedChk(ierr); 633 ierr = CeedMalloc(P1d*P1d, &laplace); CeedChk(ierr); 634 ierr = CeedMalloc(P1d*P1d, &x); CeedChk(ierr); 635 ierr = CeedMalloc(P1d*P1d, &x2); CeedChk(ierr); 636 ierr = CeedMalloc(P1d, &lambda); CeedChk(ierr); 637 // -- Mass 638 for (CeedInt i=0; i<Q1d; i++) 639 for (CeedInt j=0; j<P1d; j++) 640 work[i+j*Q1d] = basis->interp1d[i*P1d+j]*basis->qweight1d[i]; 641 ierr = CeedMatrixMultiply(ceed, work, basis->interp1d, mass, P1d, P1d, Q1d); 642 CeedChk(ierr); 643 // -- Laplacian 644 for (CeedInt i=0; i<Q1d; i++) 645 for (CeedInt j=0; j<P1d; j++) 646 work[i+j*Q1d] = basis->grad1d[i*P1d+j]*basis->qweight1d[i]; 647 ierr = CeedMatrixMultiply(ceed, work, basis->grad1d, laplace, P1d, P1d, Q1d); 648 CeedChk(ierr); 649 // -- Diagonalize 650 ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P1d); 651 CeedChk(ierr); 652 ierr = CeedFree(&work); CeedChk(ierr); 653 ierr = CeedFree(&mass); CeedChk(ierr); 654 ierr = CeedFree(&laplace); CeedChk(ierr); 655 for (CeedInt i=0; i<P1d; i++) 656 for (CeedInt j=0; j<P1d; j++) 657 x2[i+j*P1d] = x[j+i*P1d]; 658 ierr = CeedFree(&x); CeedChk(ierr); 659 660 // Assemble QFunction 661 CeedVector assembled; 662 CeedElemRestriction rstr_qf; 663 ierr = CeedOperatorAssembleLinearQFunction(op, &assembled, &rstr_qf, 664 request); CeedChk(ierr); 665 ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChk(ierr); 666 667 // Calculate element averages 668 CeedInt nfields = ((interp?1:0) + (grad?dim:0))*((interp?1:0) + (grad?dim:0)); 669 CeedScalar *elemavg; 670 const CeedScalar *assembledarray, *qweightsarray; 671 CeedVector qweights; 672 ierr = CeedVectorCreate(ceed, nqpts, &qweights); CeedChk(ierr); 673 ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, 674 CEED_VECTOR_NONE, qweights); CeedChk(ierr); 675 ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembledarray); 676 CeedChk(ierr); 677 ierr = CeedVectorGetArrayRead(qweights, CEED_MEM_HOST, &qweightsarray); 678 CeedChk(ierr); 679 ierr = CeedCalloc(nelem, &elemavg); CeedChk(ierr); 680 for (CeedInt e=0; e<nelem; e++) { 681 CeedInt count = 0; 682 for (CeedInt q=0; q<nqpts; q++) 683 for (CeedInt i=0; i<ncomp*ncomp*nfields; i++) 684 if (fabs(assembledarray[e*nelem*nqpts*ncomp*ncomp*nfields + 685 i*nqpts + q]) > CEED_EPSILON) { 686 elemavg[e] += assembledarray[e*nelem*nqpts*ncomp*ncomp*nfields + 687 i*nqpts + q] / qweightsarray[q]; 688 count++; 689 } 690 if (count) 691 elemavg[e] /= count; 692 } 693 ierr = CeedVectorRestoreArrayRead(assembled, &assembledarray); CeedChk(ierr); 694 ierr = CeedVectorDestroy(&assembled); CeedChk(ierr); 695 ierr = CeedVectorRestoreArrayRead(qweights, &qweightsarray); CeedChk(ierr); 696 ierr = CeedVectorDestroy(&qweights); CeedChk(ierr); 697 698 // Build FDM diagonal 699 CeedVector qdata; 700 CeedScalar *qdataarray; 701 ierr = CeedVectorCreate(ceed, nelem*ncomp*nnodes, &qdata); CeedChk(ierr); 702 ierr = CeedVectorSetArray(qdata, CEED_MEM_HOST, CEED_COPY_VALUES, NULL); 703 CeedChk(ierr); 704 ierr = CeedVectorGetArray(qdata, CEED_MEM_HOST, &qdataarray); CeedChk(ierr); 705 for (CeedInt e=0; e<nelem; e++) 706 for (CeedInt c=0; c<ncomp; c++) 707 for (CeedInt n=0; n<nnodes; n++) { 708 if (interp) 709 qdataarray[(e*ncomp+c)*nnodes+n] = 1; 710 if (grad) 711 for (CeedInt d=0; d<dim; d++) { 712 CeedInt i = (n / CeedIntPow(P1d, d)) % P1d; 713 qdataarray[(e*ncomp+c)*nnodes+n] += lambda[i]; 714 } 715 qdataarray[(e*ncomp+c)*nnodes+n] = 1 / (elemavg[e] * 716 qdataarray[(e*ncomp+c)*nnodes+n]); 717 } 718 ierr = CeedFree(&elemavg); CeedChk(ierr); 719 ierr = CeedVectorRestoreArray(qdata, &qdataarray); CeedChk(ierr); 720 721 // Setup FDM operator 722 // -- Basis 723 CeedBasis fdm_basis; 724 CeedScalar *graddummy, *qrefdummy, *qweightdummy; 725 ierr = CeedCalloc(P1d*P1d, &graddummy); CeedChk(ierr); 726 ierr = CeedCalloc(P1d, &qrefdummy); CeedChk(ierr); 727 ierr = CeedCalloc(P1d, &qweightdummy); CeedChk(ierr); 728 ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1d, P1d, x2, graddummy, 729 qrefdummy, qweightdummy, &fdm_basis); 730 CeedChk(ierr); 731 ierr = CeedFree(&graddummy); CeedChk(ierr); 732 ierr = CeedFree(&qrefdummy); CeedChk(ierr); 733 ierr = CeedFree(&qweightdummy); CeedChk(ierr); 734 ierr = CeedFree(&x2); CeedChk(ierr); 735 ierr = CeedFree(&lambda); CeedChk(ierr); 736 737 // -- Restriction 738 CeedElemRestriction rstr_i; 739 ierr = CeedElemRestrictionCreateIdentity(ceed, nelem, nnodes, nnodes*nelem, 740 ncomp, &rstr_i); CeedChk(ierr); 741 // -- QFunction 742 CeedQFunction mass_qf; 743 ierr = CeedQFunctionCreateInteriorByName(ceed, "MassApply", &mass_qf); 744 CeedChk(ierr); 745 // -- Operator 746 ierr = CeedOperatorCreate(ceed, mass_qf, NULL, NULL, fdminv); CeedChk(ierr); 747 CeedOperatorSetField(*fdminv, "u", rstr_i, CEED_NOTRANSPOSE, 748 fdm_basis, CEED_VECTOR_ACTIVE); CeedChk(ierr); 749 CeedOperatorSetField(*fdminv, "qdata", rstr_i, CEED_NOTRANSPOSE, 750 CEED_BASIS_COLLOCATED, qdata); CeedChk(ierr); 751 CeedOperatorSetField(*fdminv, "v", rstr_i, CEED_NOTRANSPOSE, 752 fdm_basis, CEED_VECTOR_ACTIVE); CeedChk(ierr); 753 754 // Cleanup 755 ierr = CeedVectorDestroy(&qdata); CeedChk(ierr); 756 ierr = CeedBasisDestroy(&fdm_basis); CeedChk(ierr); 757 ierr = CeedElemRestrictionDestroy(&rstr_i); CeedChk(ierr); 758 ierr = CeedQFunctionDestroy(&mass_qf); CeedChk(ierr); 759 760 return 0; 761 } 762 763 764 /** 765 @brief Apply CeedOperator to a vector 766 767 This computes the action of the operator on the specified (active) input, 768 yielding its (active) output. All inputs and outputs must be specified using 769 CeedOperatorSetField(). 770 771 @param op CeedOperator to apply 772 @param[in] in CeedVector containing input state or CEED_VECTOR_NONE if 773 there are no active inputs 774 @param[out] out CeedVector to store result of applying operator (must be 775 distinct from @a in) or CEED_VECTOR_NONE if there are no 776 active outputs 777 @param request Address of CeedRequest for non-blocking completion, else 778 CEED_REQUEST_IMMEDIATE 779 780 @return An error code: 0 - success, otherwise - failure 781 782 @ref Basic 783 **/ 784 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 785 CeedRequest *request) { 786 int ierr; 787 Ceed ceed = op->ceed; 788 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 789 790 if (op->numelements) { 791 // Standard Operator 792 if (op->Apply) { 793 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 794 } else { 795 // Zero all output vectors 796 CeedQFunction qf = op->qf; 797 for (CeedInt i=0; i<qf->numoutputfields; i++) { 798 CeedVector vec = op->outputfields[i]->vec; 799 if (vec == CEED_VECTOR_ACTIVE) 800 vec = out; 801 if (vec != CEED_VECTOR_NONE) { 802 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 803 } 804 } 805 // Apply 806 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 807 } 808 } else if (op->composite) { 809 // Composite Operator 810 if (op->ApplyComposite) { 811 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 812 } else { 813 CeedInt numsub; 814 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 815 CeedOperator *suboperators; 816 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 817 818 // Zero all output vectors 819 if (out != CEED_VECTOR_NONE) { 820 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 821 } 822 for (CeedInt i=0; i<numsub; i++) { 823 for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) { 824 CeedVector vec = suboperators[i]->outputfields[j]->vec; 825 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 826 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 827 } 828 } 829 } 830 // Apply 831 for (CeedInt i=0; i<op->numsub; i++) { 832 ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request); 833 CeedChk(ierr); 834 } 835 } 836 } 837 838 return 0; 839 } 840 841 /** 842 @brief Apply CeedOperator to a vector and add result to output vector 843 844 This computes the action of the operator on the specified (active) input, 845 yielding its (active) output. All inputs and outputs must be specified using 846 CeedOperatorSetField(). 847 848 @param op CeedOperator to apply 849 @param[in] in CeedVector containing input state or NULL if there are no 850 active inputs 851 @param[out] out CeedVector to sum in result of applying operator (must be 852 distinct from @a in) or NULL if there are no active outputs 853 @param request Address of CeedRequest for non-blocking completion, else 854 CEED_REQUEST_IMMEDIATE 855 856 @return An error code: 0 - success, otherwise - failure 857 858 @ref Basic 859 **/ 860 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 861 CeedRequest *request) { 862 int ierr; 863 Ceed ceed = op->ceed; 864 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 865 866 if (op->numelements) { 867 // Standard Operator 868 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 869 } else if (op->composite) { 870 // Composite Operator 871 if (op->ApplyAddComposite) { 872 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 873 } else { 874 CeedInt numsub; 875 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 876 CeedOperator *suboperators; 877 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 878 879 for (CeedInt i=0; i<numsub; i++) { 880 ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request); 881 CeedChk(ierr); 882 } 883 } 884 } 885 886 return 0; 887 } 888 889 /** 890 @brief Get the Ceed associated with a CeedOperator 891 892 @param op CeedOperator 893 @param[out] ceed Variable to store Ceed 894 895 @return An error code: 0 - success, otherwise - failure 896 897 @ref Advanced 898 **/ 899 900 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 901 *ceed = op->ceed; 902 return 0; 903 } 904 905 /** 906 @brief Get the number of elements associated with a CeedOperator 907 908 @param op CeedOperator 909 @param[out] numelem Variable to store number of elements 910 911 @return An error code: 0 - success, otherwise - failure 912 913 @ref Advanced 914 **/ 915 916 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 917 if (op->composite) 918 // LCOV_EXCL_START 919 return CeedError(op->ceed, 1, "Not defined for composite operator"); 920 // LCOV_EXCL_STOP 921 922 *numelem = op->numelements; 923 return 0; 924 } 925 926 /** 927 @brief Get the number of quadrature points associated with a CeedOperator 928 929 @param op CeedOperator 930 @param[out] numqpts Variable to store vector number of quadrature points 931 932 @return An error code: 0 - success, otherwise - failure 933 934 @ref Advanced 935 **/ 936 937 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 938 if (op->composite) 939 // LCOV_EXCL_START 940 return CeedError(op->ceed, 1, "Not defined for composite operator"); 941 // LCOV_EXCL_STOP 942 943 *numqpts = op->numqpoints; 944 return 0; 945 } 946 947 /** 948 @brief Get the number of arguments associated with a CeedOperator 949 950 @param op CeedOperator 951 @param[out] numargs Variable to store vector number of arguments 952 953 @return An error code: 0 - success, otherwise - failure 954 955 @ref Advanced 956 **/ 957 958 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 959 if (op->composite) 960 // LCOV_EXCL_START 961 return CeedError(op->ceed, 1, "Not defined for composite operators"); 962 // LCOV_EXCL_STOP 963 964 *numargs = op->nfields; 965 return 0; 966 } 967 968 /** 969 @brief Get the setup status of a CeedOperator 970 971 @param op CeedOperator 972 @param[out] setupdone Variable to store setup status 973 974 @return An error code: 0 - success, otherwise - failure 975 976 @ref Advanced 977 **/ 978 979 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 980 *setupdone = op->setupdone; 981 return 0; 982 } 983 984 /** 985 @brief Get the QFunction associated with a CeedOperator 986 987 @param op CeedOperator 988 @param[out] qf Variable to store QFunction 989 990 @return An error code: 0 - success, otherwise - failure 991 992 @ref Advanced 993 **/ 994 995 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 996 if (op->composite) 997 // LCOV_EXCL_START 998 return CeedError(op->ceed, 1, "Not defined for composite operator"); 999 // LCOV_EXCL_STOP 1000 1001 *qf = op->qf; 1002 return 0; 1003 } 1004 1005 /** 1006 @brief Get the number of suboperators associated with a CeedOperator 1007 1008 @param op CeedOperator 1009 @param[out] numsub Variable to store number of suboperators 1010 1011 @return An error code: 0 - success, otherwise - failure 1012 1013 @ref Advanced 1014 **/ 1015 1016 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 1017 if (!op->composite) 1018 // LCOV_EXCL_START 1019 return CeedError(op->ceed, 1, "Not a composite operator"); 1020 // LCOV_EXCL_STOP 1021 1022 *numsub = op->numsub; 1023 return 0; 1024 } 1025 1026 /** 1027 @brief Get the list of suboperators associated with a CeedOperator 1028 1029 @param op CeedOperator 1030 @param[out] suboperators Variable to store list of suboperators 1031 1032 @return An error code: 0 - success, otherwise - failure 1033 1034 @ref Advanced 1035 **/ 1036 1037 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) { 1038 if (!op->composite) 1039 // LCOV_EXCL_START 1040 return CeedError(op->ceed, 1, "Not a composite operator"); 1041 // LCOV_EXCL_STOP 1042 1043 *suboperators = op->suboperators; 1044 return 0; 1045 } 1046 1047 /** 1048 @brief Set the backend data of a CeedOperator 1049 1050 @param[out] op CeedOperator 1051 @param data Data to set 1052 1053 @return An error code: 0 - success, otherwise - failure 1054 1055 @ref Advanced 1056 **/ 1057 1058 int CeedOperatorSetData(CeedOperator op, void **data) { 1059 op->data = *data; 1060 return 0; 1061 } 1062 1063 /** 1064 @brief Get the backend data of a CeedOperator 1065 1066 @param op CeedOperator 1067 @param[out] data Variable to store data 1068 1069 @return An error code: 0 - success, otherwise - failure 1070 1071 @ref Advanced 1072 **/ 1073 1074 int CeedOperatorGetData(CeedOperator op, void **data) { 1075 *data = op->data; 1076 return 0; 1077 } 1078 1079 /** 1080 @brief Set the setup flag of a CeedOperator to True 1081 1082 @param op CeedOperator 1083 1084 @return An error code: 0 - success, otherwise - failure 1085 1086 @ref Advanced 1087 **/ 1088 1089 int CeedOperatorSetSetupDone(CeedOperator op) { 1090 op->setupdone = 1; 1091 return 0; 1092 } 1093 1094 /** 1095 @brief View a field of a CeedOperator 1096 1097 @param[in] field Operator field to view 1098 @param[in] fieldnumber Number of field being viewed 1099 @param[in] stream Stream to view to, e.g., stdout 1100 1101 @return An error code: 0 - success, otherwise - failure 1102 1103 @ref Utility 1104 **/ 1105 static int CeedOperatorFieldView(CeedOperatorField field, 1106 CeedQFunctionField qffield, 1107 CeedInt fieldnumber, bool sub, bool in, 1108 FILE *stream) { 1109 const char *pre = sub ? " " : ""; 1110 const char *inout = in ? "Input" : "Output"; 1111 1112 fprintf(stream, "%s %s Field [%d]:\n" 1113 "%s Name: \"%s\"\n" 1114 "%s Lmode: \"%s\"\n", 1115 pre, inout, fieldnumber, pre, qffield->fieldname, 1116 pre, CeedTransposeModes[field->lmode]); 1117 1118 if (field->basis == CEED_BASIS_COLLOCATED) 1119 fprintf(stream, "%s Collocated basis\n", pre); 1120 1121 if (field->vec == CEED_VECTOR_ACTIVE) 1122 fprintf(stream, "%s Active vector\n", pre); 1123 else if (field->vec == CEED_VECTOR_NONE) 1124 fprintf(stream, "%s No vector\n", pre); 1125 1126 return 0; 1127 } 1128 1129 /** 1130 @brief View a single CeedOperator 1131 1132 @param[in] op CeedOperator to view 1133 @param[in] stream Stream to write; typically stdout/stderr or a file 1134 1135 @return Error code: 0 - success, otherwise - failure 1136 1137 @ref Utility 1138 **/ 1139 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 1140 int ierr; 1141 const char *pre = sub ? " " : ""; 1142 1143 CeedInt totalfields; 1144 ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr); 1145 1146 fprintf(stream, "%s %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : ""); 1147 1148 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->numinputfields, 1149 op->qf->numinputfields>1 ? "s" : ""); 1150 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 1151 ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i], 1152 i, sub, 1, stream); CeedChk(ierr); 1153 } 1154 1155 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->numoutputfields, 1156 op->qf->numoutputfields>1 ? "s" : ""); 1157 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 1158 ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i], 1159 i, sub, 0, stream); CeedChk(ierr); 1160 } 1161 1162 return 0; 1163 } 1164 1165 /** 1166 @brief View a CeedOperator 1167 1168 @param[in] op CeedOperator to view 1169 @param[in] stream Stream to write; typically stdout/stderr or a file 1170 1171 @return Error code: 0 - success, otherwise - failure 1172 1173 @ref Utility 1174 **/ 1175 int CeedOperatorView(CeedOperator op, FILE *stream) { 1176 int ierr; 1177 1178 if (op->composite) { 1179 fprintf(stream, "Composite CeedOperator\n"); 1180 1181 for (CeedInt i=0; i<op->numsub; i++) { 1182 fprintf(stream, " SubOperator [%d]:\n", i); 1183 ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream); 1184 CeedChk(ierr); 1185 } 1186 } else { 1187 fprintf(stream, "CeedOperator\n"); 1188 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1189 } 1190 1191 return 0; 1192 } 1193 1194 /** 1195 @brief Get the CeedOperatorFields of a CeedOperator 1196 1197 @param op CeedOperator 1198 @param[out] inputfields Variable to store inputfields 1199 @param[out] outputfields Variable to store outputfields 1200 1201 @return An error code: 0 - success, otherwise - failure 1202 1203 @ref Advanced 1204 **/ 1205 1206 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields, 1207 CeedOperatorField **outputfields) { 1208 if (op->composite) 1209 // LCOV_EXCL_START 1210 return CeedError(op->ceed, 1, "Not defined for composite operator"); 1211 // LCOV_EXCL_STOP 1212 1213 if (inputfields) *inputfields = op->inputfields; 1214 if (outputfields) *outputfields = op->outputfields; 1215 return 0; 1216 } 1217 1218 /** 1219 @brief Get the L vector CeedTransposeMode of a CeedOperatorField 1220 1221 @param opfield CeedOperatorField 1222 @param[out] lmode Variable to store CeedTransposeMode 1223 1224 @return An error code: 0 - success, otherwise - failure 1225 1226 @ref Advanced 1227 **/ 1228 1229 int CeedOperatorFieldGetLMode(CeedOperatorField opfield, 1230 CeedTransposeMode *lmode) { 1231 *lmode = opfield->lmode; 1232 return 0; 1233 } 1234 1235 /** 1236 @brief Get the CeedElemRestriction of a CeedOperatorField 1237 1238 @param opfield CeedOperatorField 1239 @param[out] rstr Variable to store CeedElemRestriction 1240 1241 @return An error code: 0 - success, otherwise - failure 1242 1243 @ref Advanced 1244 **/ 1245 1246 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 1247 CeedElemRestriction *rstr) { 1248 *rstr = opfield->Erestrict; 1249 return 0; 1250 } 1251 1252 /** 1253 @brief Get the CeedBasis of a CeedOperatorField 1254 1255 @param opfield CeedOperatorField 1256 @param[out] basis Variable to store CeedBasis 1257 1258 @return An error code: 0 - success, otherwise - failure 1259 1260 @ref Advanced 1261 **/ 1262 1263 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) { 1264 *basis = opfield->basis; 1265 return 0; 1266 } 1267 1268 /** 1269 @brief Get the CeedVector of a CeedOperatorField 1270 1271 @param opfield CeedOperatorField 1272 @param[out] vec Variable to store CeedVector 1273 1274 @return An error code: 0 - success, otherwise - failure 1275 1276 @ref Advanced 1277 **/ 1278 1279 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) { 1280 *vec = opfield->vec; 1281 return 0; 1282 } 1283 1284 /** 1285 @brief Destroy a CeedOperator 1286 1287 @param op CeedOperator to destroy 1288 1289 @return An error code: 0 - success, otherwise - failure 1290 1291 @ref Basic 1292 **/ 1293 int CeedOperatorDestroy(CeedOperator *op) { 1294 int ierr; 1295 1296 if (!*op || --(*op)->refcount > 0) return 0; 1297 if ((*op)->Destroy) { 1298 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1299 } 1300 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1301 // Free fields 1302 for (int i=0; i<(*op)->nfields; i++) 1303 if ((*op)->inputfields[i]) { 1304 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 1305 CeedChk(ierr); 1306 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1307 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 1308 } 1309 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 1310 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 1311 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 1312 } 1313 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 1314 } 1315 for (int i=0; i<(*op)->nfields; i++) 1316 if ((*op)->outputfields[i]) { 1317 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 1318 CeedChk(ierr); 1319 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1320 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 1321 } 1322 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 1323 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 1324 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 1325 } 1326 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 1327 } 1328 // Destroy suboperators 1329 for (int i=0; i<(*op)->numsub; i++) 1330 if ((*op)->suboperators[i]) { 1331 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 1332 } 1333 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1334 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1335 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1336 1337 // Destroy fallback 1338 if ((*op)->opfallback) { 1339 ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr); 1340 ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr); 1341 ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr); 1342 ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr); 1343 } 1344 1345 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 1346 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 1347 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 1348 ierr = CeedFree(op); CeedChk(ierr); 1349 return 0; 1350 } 1351 1352 /// @} 1353