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