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