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.h> 18 #include <ceed-backend.h> 19 #include <ceed-impl.h> 20 #include <math.h> 21 #include <stdbool.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 /// @file 26 /// Implementation of CeedOperator interfaces 27 28 /// ---------------------------------------------------------------------------- 29 /// CeedOperator Library Internal Functions 30 /// ---------------------------------------------------------------------------- 31 /// @addtogroup CeedOperatorDeveloper 32 /// @{ 33 34 /** 35 @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced 36 CeedOperator functionality 37 38 @param op CeedOperator to create fallback for 39 40 @return An error code: 0 - success, otherwise - failure 41 42 @ref Developer 43 **/ 44 int CeedOperatorCreateFallback(CeedOperator op) { 45 int ierr; 46 47 // Fallback Ceed 48 const char *resource, *fallbackresource; 49 ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr); 50 ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource); 51 CeedChk(ierr); 52 if (!strcmp(resource, fallbackresource)) 53 // LCOV_EXCL_START 54 return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, 55 "Backend %s cannot create an operator" 56 "fallback to resource %s", resource, fallbackresource); 57 // LCOV_EXCL_STOP 58 59 // Fallback Ceed 60 Ceed ceedref; 61 if (!op->ceed->opfallbackceed) { 62 ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr); 63 ceedref->opfallbackparent = op->ceed; 64 ceedref->Error = op->ceed->Error; 65 op->ceed->opfallbackceed = ceedref; 66 } 67 ceedref = op->ceed->opfallbackceed; 68 69 // Clone Op 70 CeedOperator opref; 71 ierr = CeedCalloc(1, &opref); CeedChk(ierr); 72 memcpy(opref, op, sizeof(*opref)); 73 opref->data = NULL; 74 opref->interfacesetup = false; 75 opref->backendsetup = false; 76 opref->ceed = ceedref; 77 ierr = ceedref->OperatorCreate(opref); CeedChk(ierr); 78 op->opfallback = opref; 79 80 // Clone QF 81 CeedQFunction qfref; 82 ierr = CeedCalloc(1, &qfref); CeedChk(ierr); 83 memcpy(qfref, (op->qf), sizeof(*qfref)); 84 qfref->data = NULL; 85 qfref->ceed = ceedref; 86 ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr); 87 opref->qf = qfref; 88 op->qffallback = qfref; 89 return CEED_ERROR_SUCCESS; 90 } 91 92 /** 93 @brief Check if a CeedOperator Field matches the QFunction Field 94 95 @param[in] ceed Ceed object for error handling 96 @param[in] qfield QFunction Field matching Operator Field 97 @param[in] r Operator Field ElemRestriction 98 @param[in] b Operator Field Basis 99 100 @return An error code: 0 - success, otherwise - failure 101 102 @ref Developer 103 **/ 104 static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qfield, 105 CeedElemRestriction r, CeedBasis b) { 106 int ierr; 107 CeedEvalMode emode = qfield->emode; 108 CeedInt dim = 1, ncomp = 1, restr_ncomp = 1, size = qfield->size; 109 // Restriction 110 if (r != CEED_ELEMRESTRICTION_NONE) { 111 ierr = CeedElemRestrictionGetNumComponents(r, &restr_ncomp); 112 } else if (emode != CEED_EVAL_WEIGHT) { 113 // LCOV_EXCL_START 114 return CeedError(ceed, CEED_ERROR_MINOR, 115 "CEED_ELEMRESTRICTION_NONE can only be used " 116 "for a field with eval mode CEED_EVAL_WEIGHT"); 117 // LCOV_EXCL_STOP 118 } 119 // Basis 120 if (b != CEED_BASIS_COLLOCATED) { 121 ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr); 122 ierr = CeedBasisGetNumComponents(b, &ncomp); CeedChk(ierr); 123 if (r != CEED_ELEMRESTRICTION_NONE && restr_ncomp != ncomp) { 124 // LCOV_EXCL_START 125 return CeedError(ceed, CEED_ERROR_DIMENSION, 126 "ElemRestriction and Basis have incompatible numbers of components"); 127 // LCOV_EXCL_STOP 128 } 129 } 130 // Field size 131 switch(emode) { 132 case CEED_EVAL_NONE: 133 if (size != restr_ncomp) 134 // LCOV_EXCL_START 135 return CeedError(ceed, CEED_ERROR_DIMENSION, 136 "Incompatible QFunction field size and Operator field " 137 "ElemRestriction number of components"); 138 // LCOV_EXCL_STOP 139 break; 140 case CEED_EVAL_INTERP: 141 if (size != ncomp) 142 // LCOV_EXCL_START 143 return CeedError(ceed, CEED_ERROR_DIMENSION, 144 "Incompatible QFunction field size and Operator field " 145 "Basis number of components"); 146 // LCOV_EXCL_STOP 147 break; 148 case CEED_EVAL_GRAD: 149 if (size != ncomp * dim) 150 // LCOV_EXCL_START 151 return CeedError(ceed, CEED_ERROR_DIMENSION, 152 "Incompatible QFunction field size and Operator field " 153 "Basis dimension and number of components"); 154 // LCOV_EXCL_STOP 155 break; 156 case CEED_EVAL_WEIGHT: 157 // No addional checks required 158 break; 159 case CEED_EVAL_DIV: 160 // Not implemented 161 break; 162 case CEED_EVAL_CURL: 163 // Not implemented 164 break; 165 } 166 return CEED_ERROR_SUCCESS; 167 } 168 169 /** 170 @brief Check if a CeedOperator is ready to be used. 171 172 @param[in] ceed Ceed object for error handling 173 @param[in] op CeedOperator to check 174 175 @return An error code: 0 - success, otherwise - failure 176 177 @ref Developer 178 **/ 179 static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) { 180 if (op->interfacesetup) 181 return CEED_ERROR_SUCCESS; 182 183 CeedQFunction qf = op->qf; 184 if (op->composite) { 185 if (!op->numsub) 186 // LCOV_EXCL_START 187 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No suboperators set"); 188 // LCOV_EXCL_STOP 189 } else { 190 if (op->nfields == 0) 191 // LCOV_EXCL_START 192 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set"); 193 // LCOV_EXCL_STOP 194 if (op->nfields < qf->numinputfields + qf->numoutputfields) 195 // LCOV_EXCL_START 196 return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set"); 197 // LCOV_EXCL_STOP 198 if (!op->hasrestriction) 199 // LCOV_EXCL_START 200 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 201 "At least one restriction required"); 202 // LCOV_EXCL_STOP 203 if (op->numqpoints == 0) 204 // LCOV_EXCL_START 205 return CeedError(ceed, CEED_ERROR_INCOMPLETE, 206 "At least one non-collocated basis required"); 207 // LCOV_EXCL_STOP 208 } 209 210 // Flag as immutable and ready 211 op->interfacesetup = true; 212 if (op->qf && op->qf != CEED_QFUNCTION_NONE) 213 // LCOV_EXCL_START 214 op->qf->operatorsset++; 215 // LCOV_EXCL_STOP 216 if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) 217 // LCOV_EXCL_START 218 op->dqf->operatorsset++; 219 // LCOV_EXCL_STOP 220 if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) 221 // LCOV_EXCL_START 222 op->dqfT->operatorsset++; 223 // LCOV_EXCL_STOP 224 return CEED_ERROR_SUCCESS; 225 } 226 227 /** 228 @brief View a field of a CeedOperator 229 230 @param[in] field Operator field to view 231 @param[in] qffield QFunction field (carries field name) 232 @param[in] fieldnumber Number of field being viewed 233 @param[in] sub true indicates sub-operator, which increases indentation; false for top-level operator 234 @param[in] in true for an input field; false for output field 235 @param[in] stream Stream to view to, e.g., stdout 236 237 @return An error code: 0 - success, otherwise - failure 238 239 @ref Utility 240 **/ 241 static int CeedOperatorFieldView(CeedOperatorField field, 242 CeedQFunctionField qffield, 243 CeedInt fieldnumber, bool sub, bool in, 244 FILE *stream) { 245 const char *pre = sub ? " " : ""; 246 const char *inout = in ? "Input" : "Output"; 247 248 fprintf(stream, "%s %s Field [%d]:\n" 249 "%s Name: \"%s\"\n", 250 pre, inout, fieldnumber, pre, qffield->fieldname); 251 252 if (field->basis == CEED_BASIS_COLLOCATED) 253 fprintf(stream, "%s Collocated basis\n", pre); 254 255 if (field->vec == CEED_VECTOR_ACTIVE) 256 fprintf(stream, "%s Active vector\n", pre); 257 else if (field->vec == CEED_VECTOR_NONE) 258 fprintf(stream, "%s No vector\n", pre); 259 return CEED_ERROR_SUCCESS; 260 } 261 262 /** 263 @brief View a single CeedOperator 264 265 @param[in] op CeedOperator to view 266 @param[in] sub Boolean flag for sub-operator 267 @param[in] stream Stream to write; typically stdout/stderr or a file 268 269 @return Error code: 0 - success, otherwise - failure 270 271 @ref Utility 272 **/ 273 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) { 274 int ierr; 275 const char *pre = sub ? " " : ""; 276 277 CeedInt totalfields; 278 ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr); 279 280 fprintf(stream, "%s %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : ""); 281 282 fprintf(stream, "%s %d Input Field%s:\n", pre, op->qf->numinputfields, 283 op->qf->numinputfields>1 ? "s" : ""); 284 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 285 ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i], 286 i, sub, 1, stream); CeedChk(ierr); 287 } 288 289 fprintf(stream, "%s %d Output Field%s:\n", pre, op->qf->numoutputfields, 290 op->qf->numoutputfields>1 ? "s" : ""); 291 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 292 ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->outputfields[i], 293 i, sub, 0, stream); CeedChk(ierr); 294 } 295 return CEED_ERROR_SUCCESS; 296 } 297 298 /** 299 @brief Find the active vector basis for a CeedOperator 300 301 @param[in] op CeedOperator to find active basis for 302 @param[out] activeBasis Basis for active input vector 303 304 @return An error code: 0 - success, otherwise - failure 305 306 @ ref Developer 307 **/ 308 static int CeedOperatorGetActiveBasis(CeedOperator op, 309 CeedBasis *activeBasis) { 310 *activeBasis = NULL; 311 for (int i = 0; i < op->qf->numinputfields; i++) 312 if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) { 313 *activeBasis = op->inputfields[i]->basis; 314 break; 315 } 316 317 if (!*activeBasis) { 318 // LCOV_EXCL_START 319 int ierr; 320 Ceed ceed; 321 ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr); 322 return CeedError(ceed, CEED_ERROR_MINOR, 323 "No active basis found for automatic multigrid setup"); 324 // LCOV_EXCL_STOP 325 } 326 return CEED_ERROR_SUCCESS; 327 } 328 329 330 /** 331 @brief Common code for creating a multigrid coarse operator and level 332 transfer operators for a CeedOperator 333 334 @param[in] opFine Fine grid operator 335 @param[in] PMultFine L-vector multiplicity in parallel gather/scatter 336 @param[in] rstrCoarse Coarse grid restriction 337 @param[in] basisCoarse Coarse grid active vector basis 338 @param[in] basisCtoF Basis for coarse to fine interpolation 339 @param[out] opCoarse Coarse grid operator 340 @param[out] opProlong Coarse to fine operator 341 @param[out] opRestrict Fine to coarse operator 342 343 @return An error code: 0 - success, otherwise - failure 344 345 @ref Developer 346 **/ 347 static int CeedOperatorMultigridLevel_Core(CeedOperator opFine, 348 CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse, 349 CeedBasis basisCtoF, CeedOperator *opCoarse, CeedOperator *opProlong, 350 CeedOperator *opRestrict) { 351 int ierr; 352 Ceed ceed; 353 ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr); 354 355 // Check for composite operator 356 bool isComposite; 357 ierr = CeedOperatorIsComposite(opFine, &isComposite); CeedChk(ierr); 358 if (isComposite) 359 // LCOV_EXCL_START 360 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 361 "Automatic multigrid setup for composite operators not supported"); 362 // LCOV_EXCL_STOP 363 364 // Coarse Grid 365 ierr = CeedOperatorCreate(ceed, opFine->qf, opFine->dqf, opFine->dqfT, 366 opCoarse); CeedChk(ierr); 367 CeedElemRestriction rstrFine = NULL; 368 // -- Clone input fields 369 for (int i = 0; i < opFine->qf->numinputfields; i++) { 370 if (opFine->inputfields[i]->vec == CEED_VECTOR_ACTIVE) { 371 rstrFine = opFine->inputfields[i]->Erestrict; 372 ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname, 373 rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE); 374 CeedChk(ierr); 375 } else { 376 ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname, 377 opFine->inputfields[i]->Erestrict, 378 opFine->inputfields[i]->basis, 379 opFine->inputfields[i]->vec); CeedChk(ierr); 380 } 381 } 382 // -- Clone output fields 383 for (int i = 0; i < opFine->qf->numoutputfields; i++) { 384 if (opFine->outputfields[i]->vec == CEED_VECTOR_ACTIVE) { 385 ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname, 386 rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE); 387 CeedChk(ierr); 388 } else { 389 ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname, 390 opFine->outputfields[i]->Erestrict, 391 opFine->outputfields[i]->basis, 392 opFine->outputfields[i]->vec); CeedChk(ierr); 393 } 394 } 395 396 // Multiplicity vector 397 CeedVector multVec, multE; 398 ierr = CeedElemRestrictionCreateVector(rstrFine, &multVec, &multE); 399 CeedChk(ierr); 400 ierr = CeedVectorSetValue(multE, 0.0); CeedChk(ierr); 401 ierr = CeedElemRestrictionApply(rstrFine, CEED_NOTRANSPOSE, PMultFine, multE, 402 CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 403 ierr = CeedVectorSetValue(multVec, 0.0); CeedChk(ierr); 404 ierr = CeedElemRestrictionApply(rstrFine, CEED_TRANSPOSE, multE, multVec, 405 CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 406 ierr = CeedVectorDestroy(&multE); CeedChk(ierr); 407 ierr = CeedVectorReciprocal(multVec); CeedChk(ierr); 408 409 // Restriction 410 CeedInt ncomp; 411 ierr = CeedBasisGetNumComponents(basisCoarse, &ncomp); CeedChk(ierr); 412 CeedQFunction qfRestrict; 413 ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfRestrict); 414 CeedChk(ierr); 415 CeedInt *ncompRData; 416 ierr = CeedCalloc(1, &ncompRData); CeedChk(ierr); 417 ncompRData[0] = ncomp; 418 CeedQFunctionContext ctxR; 419 ierr = CeedQFunctionContextCreate(ceed, &ctxR); CeedChk(ierr); 420 ierr = CeedQFunctionContextSetData(ctxR, CEED_MEM_HOST, CEED_OWN_POINTER, 421 sizeof(*ncompRData), ncompRData); 422 CeedChk(ierr); 423 ierr = CeedQFunctionSetContext(qfRestrict, ctxR); CeedChk(ierr); 424 ierr = CeedQFunctionContextDestroy(&ctxR); CeedChk(ierr); 425 ierr = CeedQFunctionAddInput(qfRestrict, "input", ncomp, CEED_EVAL_NONE); 426 CeedChk(ierr); 427 ierr = CeedQFunctionAddInput(qfRestrict, "scale", ncomp, CEED_EVAL_NONE); 428 CeedChk(ierr); 429 ierr = CeedQFunctionAddOutput(qfRestrict, "output", ncomp, CEED_EVAL_INTERP); 430 CeedChk(ierr); 431 432 ierr = CeedOperatorCreate(ceed, qfRestrict, CEED_QFUNCTION_NONE, 433 CEED_QFUNCTION_NONE, opRestrict); 434 CeedChk(ierr); 435 ierr = CeedOperatorSetField(*opRestrict, "input", rstrFine, 436 CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 437 CeedChk(ierr); 438 ierr = CeedOperatorSetField(*opRestrict, "scale", rstrFine, 439 CEED_BASIS_COLLOCATED, multVec); 440 CeedChk(ierr); 441 ierr = CeedOperatorSetField(*opRestrict, "output", rstrCoarse, basisCtoF, 442 CEED_VECTOR_ACTIVE); CeedChk(ierr); 443 444 // Prolongation 445 CeedQFunction qfProlong; 446 ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfProlong); 447 CeedChk(ierr); 448 CeedInt *ncompPData; 449 ierr = CeedCalloc(1, &ncompPData); CeedChk(ierr); 450 ncompPData[0] = ncomp; 451 CeedQFunctionContext ctxP; 452 ierr = CeedQFunctionContextCreate(ceed, &ctxP); CeedChk(ierr); 453 ierr = CeedQFunctionContextSetData(ctxP, CEED_MEM_HOST, CEED_OWN_POINTER, 454 sizeof(*ncompPData), ncompPData); 455 CeedChk(ierr); 456 ierr = CeedQFunctionSetContext(qfProlong, ctxP); CeedChk(ierr); 457 ierr = CeedQFunctionContextDestroy(&ctxP); CeedChk(ierr); 458 ierr = CeedQFunctionAddInput(qfProlong, "input", ncomp, CEED_EVAL_INTERP); 459 CeedChk(ierr); 460 ierr = CeedQFunctionAddInput(qfProlong, "scale", ncomp, CEED_EVAL_NONE); 461 CeedChk(ierr); 462 ierr = CeedQFunctionAddOutput(qfProlong, "output", ncomp, CEED_EVAL_NONE); 463 CeedChk(ierr); 464 465 ierr = CeedOperatorCreate(ceed, qfProlong, CEED_QFUNCTION_NONE, 466 CEED_QFUNCTION_NONE, opProlong); 467 CeedChk(ierr); 468 ierr = CeedOperatorSetField(*opProlong, "input", rstrCoarse, basisCtoF, 469 CEED_VECTOR_ACTIVE); CeedChk(ierr); 470 ierr = CeedOperatorSetField(*opProlong, "scale", rstrFine, 471 CEED_BASIS_COLLOCATED, multVec); 472 CeedChk(ierr); 473 ierr = CeedOperatorSetField(*opProlong, "output", rstrFine, 474 CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE); 475 CeedChk(ierr); 476 477 // Cleanup 478 ierr = CeedVectorDestroy(&multVec); CeedChk(ierr); 479 ierr = CeedBasisDestroy(&basisCtoF); CeedChk(ierr); 480 ierr = CeedQFunctionDestroy(&qfRestrict); CeedChk(ierr); 481 ierr = CeedQFunctionDestroy(&qfProlong); CeedChk(ierr); 482 return CEED_ERROR_SUCCESS; 483 } 484 485 /// @} 486 487 /// ---------------------------------------------------------------------------- 488 /// CeedOperator Backend API 489 /// ---------------------------------------------------------------------------- 490 /// @addtogroup CeedOperatorBackend 491 /// @{ 492 493 /** 494 @brief Get the Ceed associated with a CeedOperator 495 496 @param op CeedOperator 497 @param[out] ceed Variable to store Ceed 498 499 @return An error code: 0 - success, otherwise - failure 500 501 @ref Backend 502 **/ 503 504 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 505 *ceed = op->ceed; 506 return CEED_ERROR_SUCCESS; 507 } 508 509 /** 510 @brief Get the number of elements associated with a CeedOperator 511 512 @param op CeedOperator 513 @param[out] numelem Variable to store number of elements 514 515 @return An error code: 0 - success, otherwise - failure 516 517 @ref Backend 518 **/ 519 520 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 521 if (op->composite) 522 // LCOV_EXCL_START 523 return CeedError(op->ceed, CEED_ERROR_MINOR, 524 "Not defined for composite operator"); 525 // LCOV_EXCL_STOP 526 527 *numelem = op->numelements; 528 return CEED_ERROR_SUCCESS; 529 } 530 531 /** 532 @brief Get the number of quadrature points associated with a CeedOperator 533 534 @param op CeedOperator 535 @param[out] numqpts Variable to store vector number of quadrature points 536 537 @return An error code: 0 - success, otherwise - failure 538 539 @ref Backend 540 **/ 541 542 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 543 if (op->composite) 544 // LCOV_EXCL_START 545 return CeedError(op->ceed, CEED_ERROR_MINOR, 546 "Not defined for composite operator"); 547 // LCOV_EXCL_STOP 548 549 *numqpts = op->numqpoints; 550 return CEED_ERROR_SUCCESS; 551 } 552 553 /** 554 @brief Get the number of arguments associated with a CeedOperator 555 556 @param op CeedOperator 557 @param[out] numargs Variable to store vector number of arguments 558 559 @return An error code: 0 - success, otherwise - failure 560 561 @ref Backend 562 **/ 563 564 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 565 if (op->composite) 566 // LCOV_EXCL_START 567 return CeedError(op->ceed, CEED_ERROR_MINOR, 568 "Not defined for composite operators"); 569 // LCOV_EXCL_STOP 570 571 *numargs = op->nfields; 572 return CEED_ERROR_SUCCESS; 573 } 574 575 /** 576 @brief Get the setup status of a CeedOperator 577 578 @param op CeedOperator 579 @param[out] issetupdone Variable to store setup status 580 581 @return An error code: 0 - success, otherwise - failure 582 583 @ref Backend 584 **/ 585 586 int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) { 587 *issetupdone = op->backendsetup; 588 return CEED_ERROR_SUCCESS; 589 } 590 591 /** 592 @brief Get the QFunction associated with a CeedOperator 593 594 @param op CeedOperator 595 @param[out] qf Variable to store QFunction 596 597 @return An error code: 0 - success, otherwise - failure 598 599 @ref Backend 600 **/ 601 602 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 603 if (op->composite) 604 // LCOV_EXCL_START 605 return CeedError(op->ceed, CEED_ERROR_MINOR, 606 "Not defined for composite operator"); 607 // LCOV_EXCL_STOP 608 609 *qf = op->qf; 610 return CEED_ERROR_SUCCESS; 611 } 612 613 /** 614 @brief Get a boolean value indicating if the CeedOperator is composite 615 616 @param op CeedOperator 617 @param[out] iscomposite Variable to store composite status 618 619 @return An error code: 0 - success, otherwise - failure 620 621 @ref Backend 622 **/ 623 624 int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) { 625 *iscomposite = op->composite; 626 return CEED_ERROR_SUCCESS; 627 } 628 629 /** 630 @brief Get the number of suboperators associated with a CeedOperator 631 632 @param op CeedOperator 633 @param[out] numsub Variable to store number of suboperators 634 635 @return An error code: 0 - success, otherwise - failure 636 637 @ref Backend 638 **/ 639 640 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 641 if (!op->composite) 642 // LCOV_EXCL_START 643 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 644 // LCOV_EXCL_STOP 645 646 *numsub = op->numsub; 647 return CEED_ERROR_SUCCESS; 648 } 649 650 /** 651 @brief Get the list of suboperators associated with a CeedOperator 652 653 @param op CeedOperator 654 @param[out] suboperators Variable to store list of suboperators 655 656 @return An error code: 0 - success, otherwise - failure 657 658 @ref Backend 659 **/ 660 661 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) { 662 if (!op->composite) 663 // LCOV_EXCL_START 664 return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator"); 665 // LCOV_EXCL_STOP 666 667 *suboperators = op->suboperators; 668 return CEED_ERROR_SUCCESS; 669 } 670 671 /** 672 @brief Get the backend data of a CeedOperator 673 674 @param op CeedOperator 675 @param[out] data Variable to store data 676 677 @return An error code: 0 - success, otherwise - failure 678 679 @ref Backend 680 **/ 681 682 int CeedOperatorGetData(CeedOperator op, void *data) { 683 *(void **)data = op->data; 684 return CEED_ERROR_SUCCESS; 685 } 686 687 /** 688 @brief Set the backend data of a CeedOperator 689 690 @param[out] op CeedOperator 691 @param data Data to set 692 693 @return An error code: 0 - success, otherwise - failure 694 695 @ref Backend 696 **/ 697 698 int CeedOperatorSetData(CeedOperator op, void *data) { 699 op->data = data; 700 return CEED_ERROR_SUCCESS; 701 } 702 703 /** 704 @brief Set the setup flag of a CeedOperator to True 705 706 @param op CeedOperator 707 708 @return An error code: 0 - success, otherwise - failure 709 710 @ref Backend 711 **/ 712 713 int CeedOperatorSetSetupDone(CeedOperator op) { 714 op->backendsetup = true; 715 return CEED_ERROR_SUCCESS; 716 } 717 718 /** 719 @brief Get the CeedOperatorFields of a CeedOperator 720 721 @param op CeedOperator 722 @param[out] inputfields Variable to store inputfields 723 @param[out] outputfields Variable to store outputfields 724 725 @return An error code: 0 - success, otherwise - failure 726 727 @ref Backend 728 **/ 729 730 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields, 731 CeedOperatorField **outputfields) { 732 if (op->composite) 733 // LCOV_EXCL_START 734 return CeedError(op->ceed, CEED_ERROR_MINOR, 735 "Not defined for composite operator"); 736 // LCOV_EXCL_STOP 737 738 if (inputfields) *inputfields = op->inputfields; 739 if (outputfields) *outputfields = op->outputfields; 740 return CEED_ERROR_SUCCESS; 741 } 742 743 /** 744 @brief Get the CeedElemRestriction of a CeedOperatorField 745 746 @param opfield CeedOperatorField 747 @param[out] rstr Variable to store CeedElemRestriction 748 749 @return An error code: 0 - success, otherwise - failure 750 751 @ref Backend 752 **/ 753 754 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 755 CeedElemRestriction *rstr) { 756 *rstr = opfield->Erestrict; 757 return CEED_ERROR_SUCCESS; 758 } 759 760 /** 761 @brief Get the CeedBasis of a CeedOperatorField 762 763 @param opfield CeedOperatorField 764 @param[out] basis Variable to store CeedBasis 765 766 @return An error code: 0 - success, otherwise - failure 767 768 @ref Backend 769 **/ 770 771 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) { 772 *basis = opfield->basis; 773 return CEED_ERROR_SUCCESS; 774 } 775 776 /** 777 @brief Get the CeedVector of a CeedOperatorField 778 779 @param opfield CeedOperatorField 780 @param[out] vec Variable to store CeedVector 781 782 @return An error code: 0 - success, otherwise - failure 783 784 @ref Backend 785 **/ 786 787 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) { 788 *vec = opfield->vec; 789 return CEED_ERROR_SUCCESS; 790 } 791 792 /// @} 793 794 /// ---------------------------------------------------------------------------- 795 /// CeedOperator Public API 796 /// ---------------------------------------------------------------------------- 797 /// @addtogroup CeedOperatorUser 798 /// @{ 799 800 /** 801 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 802 CeedElemRestriction can be associated with CeedQFunction fields with 803 \ref CeedOperatorSetField. 804 805 @param ceed A Ceed object where the CeedOperator will be created 806 @param qf QFunction defining the action of the operator at quadrature points 807 @param dqf QFunction defining the action of the Jacobian of @a qf (or 808 @ref CEED_QFUNCTION_NONE) 809 @param dqfT QFunction defining the action of the transpose of the Jacobian 810 of @a qf (or @ref CEED_QFUNCTION_NONE) 811 @param[out] op Address of the variable where the newly created 812 CeedOperator will be stored 813 814 @return An error code: 0 - success, otherwise - failure 815 816 @ref User 817 */ 818 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 819 CeedQFunction dqfT, CeedOperator *op) { 820 int ierr; 821 822 if (!ceed->OperatorCreate) { 823 Ceed delegate; 824 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 825 826 if (!delegate) 827 // LCOV_EXCL_START 828 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 829 "Backend does not support OperatorCreate"); 830 // LCOV_EXCL_STOP 831 832 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 833 return CEED_ERROR_SUCCESS; 834 } 835 836 if (!qf || qf == CEED_QFUNCTION_NONE) 837 // LCOV_EXCL_START 838 return CeedError(ceed, CEED_ERROR_MINOR, 839 "Operator must have a valid QFunction."); 840 // LCOV_EXCL_STOP 841 ierr = CeedCalloc(1, op); CeedChk(ierr); 842 (*op)->ceed = ceed; 843 ceed->refcount++; 844 (*op)->refcount = 1; 845 (*op)->qf = qf; 846 qf->refcount++; 847 if (dqf && dqf != CEED_QFUNCTION_NONE) { 848 (*op)->dqf = dqf; 849 dqf->refcount++; 850 } 851 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 852 (*op)->dqfT = dqfT; 853 dqfT->refcount++; 854 } 855 ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr); 856 ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr); 857 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 858 return CEED_ERROR_SUCCESS; 859 } 860 861 /** 862 @brief Create an operator that composes the action of several operators 863 864 @param ceed A Ceed object where the CeedOperator will be created 865 @param[out] op Address of the variable where the newly created 866 Composite CeedOperator will be stored 867 868 @return An error code: 0 - success, otherwise - failure 869 870 @ref User 871 */ 872 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 873 int ierr; 874 875 if (!ceed->CompositeOperatorCreate) { 876 Ceed delegate; 877 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 878 879 if (delegate) { 880 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 881 return CEED_ERROR_SUCCESS; 882 } 883 } 884 885 ierr = CeedCalloc(1, op); CeedChk(ierr); 886 (*op)->ceed = ceed; 887 ceed->refcount++; 888 (*op)->composite = true; 889 ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr); 890 891 if (ceed->CompositeOperatorCreate) { 892 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 893 } 894 return CEED_ERROR_SUCCESS; 895 } 896 897 /** 898 @brief Provide a field to a CeedOperator for use by its CeedQFunction 899 900 This function is used to specify both active and passive fields to a 901 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 902 fields can inputs or outputs (updated in-place when operator is applied). 903 904 Active fields must be specified using this function, but their data (in a 905 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 906 input and at most one active output. 907 908 @param op CeedOperator on which to provide the field 909 @param fieldname Name of the field (to be matched with the name used by 910 CeedQFunction) 911 @param r CeedElemRestriction 912 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 913 if collocated with quadrature points 914 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 915 if field is active or @ref CEED_VECTOR_NONE if using 916 @ref CEED_EVAL_WEIGHT in the QFunction 917 918 @return An error code: 0 - success, otherwise - failure 919 920 @ref User 921 **/ 922 int CeedOperatorSetField(CeedOperator op, const char *fieldname, 923 CeedElemRestriction r, CeedBasis b, CeedVector v) { 924 int ierr; 925 if (op->composite) 926 // LCOV_EXCL_START 927 return CeedError(op->ceed, CEED_ERROR_MINOR, 928 "Cannot add field to composite operator."); 929 // LCOV_EXCL_STOP 930 if (!r) 931 // LCOV_EXCL_START 932 return CeedError(op->ceed, CEED_ERROR_MINOR, 933 "ElemRestriction r for field \"%s\" must be non-NULL.", 934 fieldname); 935 // LCOV_EXCL_STOP 936 if (!b) 937 // LCOV_EXCL_START 938 return CeedError(op->ceed, CEED_ERROR_MINOR, 939 "Basis b for field \"%s\" must be non-NULL.", 940 fieldname); 941 // LCOV_EXCL_STOP 942 if (!v) 943 // LCOV_EXCL_START 944 return CeedError(op->ceed, CEED_ERROR_MINOR, 945 "Vector v for field \"%s\" must be non-NULL.", 946 fieldname); 947 // LCOV_EXCL_STOP 948 949 CeedInt numelements; 950 ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr); 951 if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction && 952 op->numelements != numelements) 953 // LCOV_EXCL_START 954 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 955 "ElemRestriction with %d elements incompatible with prior " 956 "%d elements", numelements, op->numelements); 957 // LCOV_EXCL_STOP 958 959 CeedInt numqpoints; 960 if (b != CEED_BASIS_COLLOCATED) { 961 ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr); 962 if (op->numqpoints && op->numqpoints != numqpoints) 963 // LCOV_EXCL_START 964 return CeedError(op->ceed, CEED_ERROR_DIMENSION, 965 "Basis with %d quadrature points " 966 "incompatible with prior %d points", numqpoints, 967 op->numqpoints); 968 // LCOV_EXCL_STOP 969 } 970 CeedQFunctionField qfield; 971 CeedOperatorField *ofield; 972 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 973 if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) { 974 qfield = op->qf->inputfields[i]; 975 ofield = &op->inputfields[i]; 976 goto found; 977 } 978 } 979 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 980 if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) { 981 qfield = op->qf->outputfields[i]; 982 ofield = &op->outputfields[i]; 983 goto found; 984 } 985 } 986 // LCOV_EXCL_START 987 return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, 988 "QFunction has no knowledge of field '%s'", 989 fieldname); 990 // LCOV_EXCL_STOP 991 found: 992 ierr = CeedOperatorCheckField(op->ceed, qfield, r, b); CeedChk(ierr); 993 ierr = CeedCalloc(1, ofield); CeedChk(ierr); 994 995 (*ofield)->vec = v; 996 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) { 997 v->refcount += 1; 998 } 999 1000 (*ofield)->Erestrict = r; 1001 r->refcount += 1; 1002 if (r != CEED_ELEMRESTRICTION_NONE) { 1003 op->numelements = numelements; 1004 op->hasrestriction = true; // Restriction set, but numelements may be 0 1005 } 1006 1007 (*ofield)->basis = b; 1008 if (b != CEED_BASIS_COLLOCATED) { 1009 op->numqpoints = numqpoints; 1010 b->refcount += 1; 1011 } 1012 1013 op->nfields += 1; 1014 size_t len = strlen(fieldname); 1015 char *tmp; 1016 ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr); 1017 memcpy(tmp, fieldname, len+1); 1018 (*ofield)->fieldname = tmp; 1019 return CEED_ERROR_SUCCESS; 1020 } 1021 1022 /** 1023 @brief Add a sub-operator to a composite CeedOperator 1024 1025 @param[out] compositeop Composite CeedOperator 1026 @param subop Sub-operator CeedOperator 1027 1028 @return An error code: 0 - success, otherwise - failure 1029 1030 @ref User 1031 */ 1032 int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) { 1033 if (!compositeop->composite) 1034 // LCOV_EXCL_START 1035 return CeedError(compositeop->ceed, CEED_ERROR_MINOR, 1036 "CeedOperator is not a composite " 1037 "operator"); 1038 // LCOV_EXCL_STOP 1039 1040 if (compositeop->numsub == CEED_COMPOSITE_MAX) 1041 // LCOV_EXCL_START 1042 return CeedError(compositeop->ceed, CEED_ERROR_UNSUPPORTED, 1043 "Cannot add additional suboperators"); 1044 // LCOV_EXCL_STOP 1045 1046 compositeop->suboperators[compositeop->numsub] = subop; 1047 subop->refcount++; 1048 compositeop->numsub++; 1049 return CEED_ERROR_SUCCESS; 1050 } 1051 1052 /** 1053 @brief Assemble a linear CeedQFunction associated with a CeedOperator 1054 1055 This returns a CeedVector containing a matrix at each quadrature point 1056 providing the action of the CeedQFunction associated with the CeedOperator. 1057 The vector 'assembled' is of shape 1058 [num_elements, num_input_fields, num_output_fields, num_quad_points] 1059 and contains column-major matrices representing the action of the 1060 CeedQFunction for a corresponding quadrature point on an element. Inputs and 1061 outputs are in the order provided by the user when adding CeedOperator fields. 1062 For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 1063 'v', provided in that order, would result in an assembled QFunction that 1064 consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 1065 on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 1066 1067 @param op CeedOperator to assemble CeedQFunction 1068 @param[out] assembled CeedVector to store assembled CeedQFunction at 1069 quadrature points 1070 @param[out] rstr CeedElemRestriction for CeedVector containing assembled 1071 CeedQFunction 1072 @param request Address of CeedRequest for non-blocking completion, else 1073 @ref CEED_REQUEST_IMMEDIATE 1074 1075 @return An error code: 0 - success, otherwise - failure 1076 1077 @ref User 1078 **/ 1079 int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled, 1080 CeedElemRestriction *rstr, 1081 CeedRequest *request) { 1082 int ierr; 1083 Ceed ceed = op->ceed; 1084 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1085 1086 // Backend version 1087 if (op->LinearAssembleQFunction) { 1088 ierr = op->LinearAssembleQFunction(op, assembled, rstr, request); 1089 CeedChk(ierr); 1090 } else { 1091 // Fallback to reference Ceed 1092 if (!op->opfallback) { 1093 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1094 } 1095 // Assemble 1096 ierr = op->opfallback->LinearAssembleQFunction(op->opfallback, assembled, 1097 rstr, request); CeedChk(ierr); 1098 } 1099 return CEED_ERROR_SUCCESS; 1100 } 1101 1102 /** 1103 @brief Assemble the diagonal of a square linear CeedOperator 1104 1105 This overwrites a CeedVector with the diagonal of a linear CeedOperator. 1106 1107 Note: Currently only non-composite CeedOperators with a single field and 1108 composite CeedOperators with single field sub-operators are supported. 1109 1110 @param op CeedOperator to assemble CeedQFunction 1111 @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1112 @param request Address of CeedRequest for non-blocking completion, else 1113 @ref CEED_REQUEST_IMMEDIATE 1114 1115 @return An error code: 0 - success, otherwise - failure 1116 1117 @ref User 1118 **/ 1119 int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled, 1120 CeedRequest *request) { 1121 int ierr; 1122 Ceed ceed = op->ceed; 1123 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1124 1125 // Use backend version, if available 1126 if (op->LinearAssembleDiagonal) { 1127 ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr); 1128 } else if (op->LinearAssembleAddDiagonal) { 1129 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1130 return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request); 1131 } else { 1132 // Fallback to reference Ceed 1133 if (!op->opfallback) { 1134 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1135 } 1136 // Assemble 1137 if (op->opfallback->LinearAssembleDiagonal) { 1138 ierr = op->opfallback->LinearAssembleDiagonal(op->opfallback, assembled, 1139 request); CeedChk(ierr); 1140 } else { 1141 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1142 return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request); 1143 } 1144 } 1145 return CEED_ERROR_SUCCESS; 1146 } 1147 1148 /** 1149 @brief Assemble the diagonal of a square linear CeedOperator 1150 1151 This sums into a CeedVector the diagonal of a linear CeedOperator. 1152 1153 Note: Currently only non-composite CeedOperators with a single field and 1154 composite CeedOperators with single field sub-operators are supported. 1155 1156 @param op CeedOperator to assemble CeedQFunction 1157 @param[out] assembled CeedVector to store assembled CeedOperator diagonal 1158 @param request Address of CeedRequest for non-blocking completion, else 1159 @ref CEED_REQUEST_IMMEDIATE 1160 1161 @return An error code: 0 - success, otherwise - failure 1162 1163 @ref User 1164 **/ 1165 int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled, 1166 CeedRequest *request) { 1167 int ierr; 1168 Ceed ceed = op->ceed; 1169 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1170 1171 // Use backend version, if available 1172 if (op->LinearAssembleAddDiagonal) { 1173 ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr); 1174 } else { 1175 // Fallback to reference Ceed 1176 if (!op->opfallback) { 1177 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1178 } 1179 // Assemble 1180 ierr = op->opfallback->LinearAssembleAddDiagonal(op->opfallback, assembled, 1181 request); CeedChk(ierr); 1182 } 1183 return CEED_ERROR_SUCCESS; 1184 } 1185 1186 /** 1187 @brief Assemble the point block diagonal of a square linear CeedOperator 1188 1189 This overwrites a CeedVector with the point block diagonal of a linear 1190 CeedOperator. 1191 1192 Note: Currently only non-composite CeedOperators with a single field and 1193 composite CeedOperators with single field sub-operators are supported. 1194 1195 @param op CeedOperator to assemble CeedQFunction 1196 @param[out] assembled CeedVector to store assembled CeedOperator point block 1197 diagonal, provided in row-major form with an 1198 @a ncomp * @a ncomp block at each node. The dimensions 1199 of this vector are derived from the active vector 1200 for the CeedOperator. The array has shape 1201 [nodes, component out, component in]. 1202 @param request Address of CeedRequest for non-blocking completion, else 1203 CEED_REQUEST_IMMEDIATE 1204 1205 @return An error code: 0 - success, otherwise - failure 1206 1207 @ref User 1208 **/ 1209 int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op, 1210 CeedVector assembled, CeedRequest *request) { 1211 int ierr; 1212 Ceed ceed = op->ceed; 1213 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1214 1215 // Use backend version, if available 1216 if (op->LinearAssemblePointBlockDiagonal) { 1217 ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request); 1218 CeedChk(ierr); 1219 } else if (op->LinearAssembleAddPointBlockDiagonal) { 1220 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1221 return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, 1222 request); 1223 } else { 1224 // Fallback to reference Ceed 1225 if (!op->opfallback) { 1226 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1227 } 1228 // Assemble 1229 if (op->opfallback->LinearAssemblePointBlockDiagonal) { 1230 ierr = op->opfallback->LinearAssemblePointBlockDiagonal(op->opfallback, 1231 assembled, request); CeedChk(ierr); 1232 } else { 1233 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 1234 return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, 1235 request); 1236 } 1237 } 1238 return CEED_ERROR_SUCCESS; 1239 } 1240 1241 /** 1242 @brief Assemble the point block diagonal of a square linear CeedOperator 1243 1244 This sums into a CeedVector with the point block diagonal of a linear 1245 CeedOperator. 1246 1247 Note: Currently only non-composite CeedOperators with a single field and 1248 composite CeedOperators with single field sub-operators are supported. 1249 1250 @param op CeedOperator to assemble CeedQFunction 1251 @param[out] assembled CeedVector to store assembled CeedOperator point block 1252 diagonal, provided in row-major form with an 1253 @a ncomp * @a ncomp block at each node. The dimensions 1254 of this vector are derived from the active vector 1255 for the CeedOperator. The array has shape 1256 [nodes, component out, component in]. 1257 @param request Address of CeedRequest for non-blocking completion, else 1258 CEED_REQUEST_IMMEDIATE 1259 1260 @return An error code: 0 - success, otherwise - failure 1261 1262 @ref User 1263 **/ 1264 int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op, 1265 CeedVector assembled, CeedRequest *request) { 1266 int ierr; 1267 Ceed ceed = op->ceed; 1268 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1269 1270 // Use backend version, if available 1271 if (op->LinearAssembleAddPointBlockDiagonal) { 1272 ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request); 1273 CeedChk(ierr); 1274 } else { 1275 // Fallback to reference Ceed 1276 if (!op->opfallback) { 1277 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1278 } 1279 // Assemble 1280 ierr = op->opfallback->LinearAssembleAddPointBlockDiagonal(op->opfallback, 1281 assembled, request); CeedChk(ierr); 1282 } 1283 return CEED_ERROR_SUCCESS; 1284 } 1285 1286 /** 1287 @brief Create a multigrid coarse operator and level transfer operators 1288 for a CeedOperator, creating the prolongation basis from the 1289 fine and coarse grid interpolation 1290 1291 @param[in] opFine Fine grid operator 1292 @param[in] PMultFine L-vector multiplicity in parallel gather/scatter 1293 @param[in] rstrCoarse Coarse grid restriction 1294 @param[in] basisCoarse Coarse grid active vector basis 1295 @param[out] opCoarse Coarse grid operator 1296 @param[out] opProlong Coarse to fine operator 1297 @param[out] opRestrict Fine to coarse operator 1298 1299 @return An error code: 0 - success, otherwise - failure 1300 1301 @ref User 1302 **/ 1303 int CeedOperatorMultigridLevelCreate(CeedOperator opFine, CeedVector PMultFine, 1304 CeedElemRestriction rstrCoarse, CeedBasis basisCoarse, 1305 CeedOperator *opCoarse, CeedOperator *opProlong, CeedOperator *opRestrict) { 1306 int ierr; 1307 Ceed ceed; 1308 ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr); 1309 1310 // Check for compatible quadrature spaces 1311 CeedBasis basisFine; 1312 ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr); 1313 CeedInt Qf, Qc; 1314 ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr); 1315 ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr); 1316 if (Qf != Qc) 1317 // LCOV_EXCL_START 1318 return CeedError(ceed, CEED_ERROR_DIMENSION, 1319 "Bases must have compatible quadrature spaces"); 1320 // LCOV_EXCL_STOP 1321 1322 // Coarse to fine basis 1323 CeedInt Pf, Pc, Q = Qf; 1324 bool isTensorF, isTensorC; 1325 ierr = CeedBasisIsTensor(basisFine, &isTensorF); CeedChk(ierr); 1326 ierr = CeedBasisIsTensor(basisCoarse, &isTensorC); CeedChk(ierr); 1327 CeedScalar *interpC, *interpF, *interpCtoF, *tau; 1328 if (isTensorF && isTensorC) { 1329 ierr = CeedBasisGetNumNodes1D(basisFine, &Pf); CeedChk(ierr); 1330 ierr = CeedBasisGetNumNodes1D(basisCoarse, &Pc); CeedChk(ierr); 1331 ierr = CeedBasisGetNumQuadraturePoints1D(basisCoarse, &Q); CeedChk(ierr); 1332 } else if (!isTensorF && !isTensorC) { 1333 ierr = CeedBasisGetNumNodes(basisFine, &Pf); CeedChk(ierr); 1334 ierr = CeedBasisGetNumNodes(basisCoarse, &Pc); CeedChk(ierr); 1335 } else { 1336 // LCOV_EXCL_START 1337 return CeedError(ceed, CEED_ERROR_MINOR, 1338 "Bases must both be tensor or non-tensor"); 1339 // LCOV_EXCL_STOP 1340 } 1341 1342 ierr = CeedMalloc(Q*Pf, &interpF); CeedChk(ierr); 1343 ierr = CeedMalloc(Q*Pc, &interpC); CeedChk(ierr); 1344 ierr = CeedCalloc(Pc*Pf, &interpCtoF); CeedChk(ierr); 1345 ierr = CeedMalloc(Q, &tau); CeedChk(ierr); 1346 if (isTensorF) { 1347 memcpy(interpF, basisFine->interp1d, Q*Pf*sizeof basisFine->interp1d[0]); 1348 memcpy(interpC, basisCoarse->interp1d, Q*Pc*sizeof basisCoarse->interp1d[0]); 1349 } else { 1350 memcpy(interpF, basisFine->interp, Q*Pf*sizeof basisFine->interp[0]); 1351 memcpy(interpC, basisCoarse->interp, Q*Pc*sizeof basisCoarse->interp[0]); 1352 } 1353 1354 // -- QR Factorization, interpF = Q R 1355 ierr = CeedQRFactorization(ceed, interpF, tau, Q, Pf); CeedChk(ierr); 1356 1357 // -- Apply Qtranspose, interpC = Qtranspose interpC 1358 CeedHouseholderApplyQ(interpC, interpF, tau, CEED_TRANSPOSE, 1359 Q, Pc, Pf, Pc, 1); 1360 1361 // -- Apply Rinv, interpCtoF = Rinv interpC 1362 for (CeedInt j=0; j<Pc; j++) { // Column j 1363 interpCtoF[j+Pc*(Pf-1)] = interpC[j+Pc*(Pf-1)]/interpF[Pf*Pf-1]; 1364 for (CeedInt i=Pf-2; i>=0; i--) { // Row i 1365 interpCtoF[j+Pc*i] = interpC[j+Pc*i]; 1366 for (CeedInt k=i+1; k<Pf; k++) 1367 interpCtoF[j+Pc*i] -= interpF[k+Pf*i]*interpCtoF[j+Pc*k]; 1368 interpCtoF[j+Pc*i] /= interpF[i+Pf*i]; 1369 } 1370 } 1371 ierr = CeedFree(&tau); CeedChk(ierr); 1372 ierr = CeedFree(&interpC); CeedChk(ierr); 1373 ierr = CeedFree(&interpF); CeedChk(ierr); 1374 1375 // Complete with interpCtoF versions of code 1376 if (isTensorF) { 1377 ierr = CeedOperatorMultigridLevelCreateTensorH1(opFine, PMultFine, 1378 rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict); 1379 CeedChk(ierr); 1380 } else { 1381 ierr = CeedOperatorMultigridLevelCreateH1(opFine, PMultFine, 1382 rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict); 1383 CeedChk(ierr); 1384 } 1385 1386 // Cleanup 1387 ierr = CeedFree(&interpCtoF); CeedChk(ierr); 1388 return CEED_ERROR_SUCCESS; 1389 } 1390 1391 /** 1392 @brief Create a multigrid coarse operator and level transfer operators 1393 for a CeedOperator with a tensor basis for the active basis 1394 1395 @param[in] opFine Fine grid operator 1396 @param[in] PMultFine L-vector multiplicity in parallel gather/scatter 1397 @param[in] rstrCoarse Coarse grid restriction 1398 @param[in] basisCoarse Coarse grid active vector basis 1399 @param[in] interpCtoF Matrix for coarse to fine interpolation 1400 @param[out] opCoarse Coarse grid operator 1401 @param[out] opProlong Coarse to fine operator 1402 @param[out] opRestrict Fine to coarse operator 1403 1404 @return An error code: 0 - success, otherwise - failure 1405 1406 @ref User 1407 **/ 1408 int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator opFine, 1409 CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse, 1410 const CeedScalar *interpCtoF, CeedOperator *opCoarse, 1411 CeedOperator *opProlong, CeedOperator *opRestrict) { 1412 int ierr; 1413 Ceed ceed; 1414 ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr); 1415 1416 // Check for compatible quadrature spaces 1417 CeedBasis basisFine; 1418 ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr); 1419 CeedInt Qf, Qc; 1420 ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr); 1421 ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr); 1422 if (Qf != Qc) 1423 // LCOV_EXCL_START 1424 return CeedError(ceed, CEED_ERROR_DIMENSION, 1425 "Bases must have compatible quadrature spaces"); 1426 // LCOV_EXCL_STOP 1427 1428 // Coarse to fine basis 1429 CeedInt dim, ncomp, nnodesCoarse, P1dFine, P1dCoarse; 1430 ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr); 1431 ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr); 1432 ierr = CeedBasisGetNumNodes1D(basisFine, &P1dFine); CeedChk(ierr); 1433 ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse); 1434 CeedChk(ierr); 1435 P1dCoarse = dim == 1 ? nnodesCoarse : 1436 dim == 2 ? sqrt(nnodesCoarse) : 1437 cbrt(nnodesCoarse); 1438 CeedScalar *qref, *qweight, *grad; 1439 ierr = CeedCalloc(P1dFine, &qref); CeedChk(ierr); 1440 ierr = CeedCalloc(P1dFine, &qweight); CeedChk(ierr); 1441 ierr = CeedCalloc(P1dFine*P1dCoarse*dim, &grad); CeedChk(ierr); 1442 CeedBasis basisCtoF; 1443 ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1dCoarse, P1dFine, 1444 interpCtoF, grad, qref, qweight, &basisCtoF); 1445 CeedChk(ierr); 1446 ierr = CeedFree(&qref); CeedChk(ierr); 1447 ierr = CeedFree(&qweight); CeedChk(ierr); 1448 ierr = CeedFree(&grad); CeedChk(ierr); 1449 1450 // Core code 1451 ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse, 1452 basisCoarse, basisCtoF, opCoarse, 1453 opProlong, opRestrict); 1454 CeedChk(ierr); 1455 return CEED_ERROR_SUCCESS; 1456 } 1457 1458 /** 1459 @brief Create a multigrid coarse operator and level transfer operators 1460 for a CeedOperator with a non-tensor basis for the active vector 1461 1462 @param[in] opFine Fine grid operator 1463 @param[in] PMultFine L-vector multiplicity in parallel gather/scatter 1464 @param[in] rstrCoarse Coarse grid restriction 1465 @param[in] basisCoarse Coarse grid active vector basis 1466 @param[in] interpCtoF Matrix for coarse to fine interpolation 1467 @param[out] opCoarse Coarse grid operator 1468 @param[out] opProlong Coarse to fine operator 1469 @param[out] opRestrict Fine to coarse operator 1470 1471 @return An error code: 0 - success, otherwise - failure 1472 1473 @ref User 1474 **/ 1475 int CeedOperatorMultigridLevelCreateH1(CeedOperator opFine, 1476 CeedVector PMultFine, 1477 CeedElemRestriction rstrCoarse, 1478 CeedBasis basisCoarse, 1479 const CeedScalar *interpCtoF, 1480 CeedOperator *opCoarse, 1481 CeedOperator *opProlong, 1482 CeedOperator *opRestrict) { 1483 int ierr; 1484 Ceed ceed; 1485 ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr); 1486 1487 // Check for compatible quadrature spaces 1488 CeedBasis basisFine; 1489 ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr); 1490 CeedInt Qf, Qc; 1491 ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr); 1492 ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr); 1493 if (Qf != Qc) 1494 // LCOV_EXCL_START 1495 return CeedError(ceed, CEED_ERROR_DIMENSION, 1496 "Bases must have compatible quadrature spaces"); 1497 // LCOV_EXCL_STOP 1498 1499 // Coarse to fine basis 1500 CeedElemTopology topo; 1501 ierr = CeedBasisGetTopology(basisFine, &topo); CeedChk(ierr); 1502 CeedInt dim, ncomp, nnodesCoarse, nnodesFine; 1503 ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr); 1504 ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr); 1505 ierr = CeedBasisGetNumNodes(basisFine, &nnodesFine); CeedChk(ierr); 1506 ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse); 1507 CeedChk(ierr); 1508 CeedScalar *qref, *qweight, *grad; 1509 ierr = CeedCalloc(nnodesFine, &qref); CeedChk(ierr); 1510 ierr = CeedCalloc(nnodesFine, &qweight); CeedChk(ierr); 1511 ierr = CeedCalloc(nnodesFine*nnodesCoarse*dim, &grad); CeedChk(ierr); 1512 CeedBasis basisCtoF; 1513 ierr = CeedBasisCreateH1(ceed, topo, ncomp, nnodesCoarse, nnodesFine, 1514 interpCtoF, grad, qref, qweight, &basisCtoF); 1515 CeedChk(ierr); 1516 ierr = CeedFree(&qref); CeedChk(ierr); 1517 ierr = CeedFree(&qweight); CeedChk(ierr); 1518 ierr = CeedFree(&grad); CeedChk(ierr); 1519 1520 // Core code 1521 ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse, 1522 basisCoarse, basisCtoF, opCoarse, 1523 opProlong, opRestrict); 1524 CeedChk(ierr); 1525 return CEED_ERROR_SUCCESS; 1526 } 1527 1528 /** 1529 @brief Build a FDM based approximate inverse for each element for a 1530 CeedOperator 1531 1532 This returns a CeedOperator and CeedVector to apply a Fast Diagonalization 1533 Method based approximate inverse. This function obtains the simultaneous 1534 diagonalization for the 1D mass and Laplacian operators, 1535 M = V^T V, K = V^T S V. 1536 The assembled QFunction is used to modify the eigenvalues from simultaneous 1537 diagonalization and obtain an approximate inverse of the form 1538 V^T S^hat V. The CeedOperator must be linear and non-composite. The 1539 associated CeedQFunction must therefore also be linear. 1540 1541 @param op CeedOperator to create element inverses 1542 @param[out] fdminv CeedOperator to apply the action of a FDM based inverse 1543 for each element 1544 @param request Address of CeedRequest for non-blocking completion, else 1545 @ref CEED_REQUEST_IMMEDIATE 1546 1547 @return An error code: 0 - success, otherwise - failure 1548 1549 @ref Backend 1550 **/ 1551 int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv, 1552 CeedRequest *request) { 1553 int ierr; 1554 Ceed ceed = op->ceed; 1555 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1556 1557 // Use backend version, if available 1558 if (op->CreateFDMElementInverse) { 1559 ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr); 1560 } else { 1561 // Fallback to reference Ceed 1562 if (!op->opfallback) { 1563 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1564 } 1565 // Assemble 1566 ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv, 1567 request); CeedChk(ierr); 1568 } 1569 return CEED_ERROR_SUCCESS; 1570 } 1571 1572 /** 1573 @brief View a CeedOperator 1574 1575 @param[in] op CeedOperator to view 1576 @param[in] stream Stream to write; typically stdout/stderr or a file 1577 1578 @return Error code: 0 - success, otherwise - failure 1579 1580 @ref User 1581 **/ 1582 int CeedOperatorView(CeedOperator op, FILE *stream) { 1583 int ierr; 1584 1585 if (op->composite) { 1586 fprintf(stream, "Composite CeedOperator\n"); 1587 1588 for (CeedInt i=0; i<op->numsub; i++) { 1589 fprintf(stream, " SubOperator [%d]:\n", i); 1590 ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream); 1591 CeedChk(ierr); 1592 } 1593 } else { 1594 fprintf(stream, "CeedOperator\n"); 1595 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1596 } 1597 return CEED_ERROR_SUCCESS; 1598 } 1599 1600 /** 1601 @brief Apply CeedOperator to a vector 1602 1603 This computes the action of the operator on the specified (active) input, 1604 yielding its (active) output. All inputs and outputs must be specified using 1605 CeedOperatorSetField(). 1606 1607 @param op CeedOperator to apply 1608 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1609 there are no active inputs 1610 @param[out] out CeedVector to store result of applying operator (must be 1611 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1612 active outputs 1613 @param request Address of CeedRequest for non-blocking completion, else 1614 @ref CEED_REQUEST_IMMEDIATE 1615 1616 @return An error code: 0 - success, otherwise - failure 1617 1618 @ref User 1619 **/ 1620 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1621 CeedRequest *request) { 1622 int ierr; 1623 Ceed ceed = op->ceed; 1624 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1625 1626 if (op->numelements) { 1627 // Standard Operator 1628 if (op->Apply) { 1629 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1630 } else { 1631 // Zero all output vectors 1632 CeedQFunction qf = op->qf; 1633 for (CeedInt i=0; i<qf->numoutputfields; i++) { 1634 CeedVector vec = op->outputfields[i]->vec; 1635 if (vec == CEED_VECTOR_ACTIVE) 1636 vec = out; 1637 if (vec != CEED_VECTOR_NONE) { 1638 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1639 } 1640 } 1641 // Apply 1642 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1643 } 1644 } else if (op->composite) { 1645 // Composite Operator 1646 if (op->ApplyComposite) { 1647 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1648 } else { 1649 CeedInt numsub; 1650 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 1651 CeedOperator *suboperators; 1652 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 1653 1654 // Zero all output vectors 1655 if (out != CEED_VECTOR_NONE) { 1656 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1657 } 1658 for (CeedInt i=0; i<numsub; i++) { 1659 for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) { 1660 CeedVector vec = suboperators[i]->outputfields[j]->vec; 1661 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1662 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1663 } 1664 } 1665 } 1666 // Apply 1667 for (CeedInt i=0; i<op->numsub; i++) { 1668 ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request); 1669 CeedChk(ierr); 1670 } 1671 } 1672 } 1673 return CEED_ERROR_SUCCESS; 1674 } 1675 1676 /** 1677 @brief Apply CeedOperator to a vector and add result to output vector 1678 1679 This computes the action of the operator on the specified (active) input, 1680 yielding its (active) output. All inputs and outputs must be specified using 1681 CeedOperatorSetField(). 1682 1683 @param op CeedOperator to apply 1684 @param[in] in CeedVector containing input state or NULL if there are no 1685 active inputs 1686 @param[out] out CeedVector to sum in result of applying operator (must be 1687 distinct from @a in) or NULL if there are no active outputs 1688 @param request Address of CeedRequest for non-blocking completion, else 1689 @ref CEED_REQUEST_IMMEDIATE 1690 1691 @return An error code: 0 - success, otherwise - failure 1692 1693 @ref User 1694 **/ 1695 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1696 CeedRequest *request) { 1697 int ierr; 1698 Ceed ceed = op->ceed; 1699 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1700 1701 if (op->numelements) { 1702 // Standard Operator 1703 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1704 } else if (op->composite) { 1705 // Composite Operator 1706 if (op->ApplyAddComposite) { 1707 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1708 } else { 1709 CeedInt numsub; 1710 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 1711 CeedOperator *suboperators; 1712 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 1713 1714 for (CeedInt i=0; i<numsub; i++) { 1715 ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request); 1716 CeedChk(ierr); 1717 } 1718 } 1719 } 1720 return CEED_ERROR_SUCCESS; 1721 } 1722 1723 /** 1724 @brief Destroy a CeedOperator 1725 1726 @param op CeedOperator to destroy 1727 1728 @return An error code: 0 - success, otherwise - failure 1729 1730 @ref User 1731 **/ 1732 int CeedOperatorDestroy(CeedOperator *op) { 1733 int ierr; 1734 1735 if (!*op || --(*op)->refcount > 0) return CEED_ERROR_SUCCESS; 1736 if ((*op)->Destroy) { 1737 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1738 } 1739 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1740 // Free fields 1741 for (int i=0; i<(*op)->nfields; i++) 1742 if ((*op)->inputfields[i]) { 1743 if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) { 1744 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 1745 CeedChk(ierr); 1746 } 1747 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1748 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 1749 } 1750 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 1751 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 1752 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 1753 } 1754 ierr = CeedFree(&(*op)->inputfields[i]->fieldname); CeedChk(ierr); 1755 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 1756 } 1757 for (int i=0; i<(*op)->nfields; i++) 1758 if ((*op)->outputfields[i]) { 1759 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 1760 CeedChk(ierr); 1761 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1762 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 1763 } 1764 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 1765 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 1766 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 1767 } 1768 ierr = CeedFree(&(*op)->outputfields[i]->fieldname); CeedChk(ierr); 1769 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 1770 } 1771 // Destroy suboperators 1772 for (int i=0; i<(*op)->numsub; i++) 1773 if ((*op)->suboperators[i]) { 1774 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 1775 } 1776 if ((*op)->qf) 1777 // LCOV_EXCL_START 1778 (*op)->qf->operatorsset--; 1779 // LCOV_EXCL_STOP 1780 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1781 if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE) 1782 // LCOV_EXCL_START 1783 (*op)->dqf->operatorsset--; 1784 // LCOV_EXCL_STOP 1785 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1786 if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE) 1787 // LCOV_EXCL_START 1788 (*op)->dqfT->operatorsset--; 1789 // LCOV_EXCL_STOP 1790 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1791 1792 // Destroy fallback 1793 if ((*op)->opfallback) { 1794 ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr); 1795 ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr); 1796 ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr); 1797 ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr); 1798 } 1799 1800 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 1801 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 1802 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 1803 ierr = CeedFree(op); CeedChk(ierr); 1804 return CEED_ERROR_SUCCESS; 1805 } 1806 1807 /// @} 1808