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 202 /// ---------------------------------------------------------------------------- 203 /// CeedOperator Backend API 204 /// ---------------------------------------------------------------------------- 205 /// @addtogroup CeedOperatorBackend 206 /// @{ 207 208 /** 209 @brief Get the Ceed associated with a CeedOperator 210 211 @param op CeedOperator 212 @param[out] ceed Variable to store Ceed 213 214 @return An error code: 0 - success, otherwise - failure 215 216 @ref Backend 217 **/ 218 219 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 220 *ceed = op->ceed; 221 return 0; 222 } 223 224 /** 225 @brief Get the number of elements associated with a CeedOperator 226 227 @param op CeedOperator 228 @param[out] numelem Variable to store number of elements 229 230 @return An error code: 0 - success, otherwise - failure 231 232 @ref Backend 233 **/ 234 235 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 236 if (op->composite) 237 // LCOV_EXCL_START 238 return CeedError(op->ceed, 1, "Not defined for composite operator"); 239 // LCOV_EXCL_STOP 240 241 *numelem = op->numelements; 242 return 0; 243 } 244 245 /** 246 @brief Get the number of quadrature points associated with a CeedOperator 247 248 @param op CeedOperator 249 @param[out] numqpts Variable to store vector number of quadrature points 250 251 @return An error code: 0 - success, otherwise - failure 252 253 @ref Backend 254 **/ 255 256 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 257 if (op->composite) 258 // LCOV_EXCL_START 259 return CeedError(op->ceed, 1, "Not defined for composite operator"); 260 // LCOV_EXCL_STOP 261 262 *numqpts = op->numqpoints; 263 return 0; 264 } 265 266 /** 267 @brief Get the number of arguments associated with a CeedOperator 268 269 @param op CeedOperator 270 @param[out] numargs Variable to store vector number of arguments 271 272 @return An error code: 0 - success, otherwise - failure 273 274 @ref Backend 275 **/ 276 277 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 278 if (op->composite) 279 // LCOV_EXCL_START 280 return CeedError(op->ceed, 1, "Not defined for composite operators"); 281 // LCOV_EXCL_STOP 282 283 *numargs = op->nfields; 284 return 0; 285 } 286 287 /** 288 @brief Get the setup status of a CeedOperator 289 290 @param op CeedOperator 291 @param[out] issetupdone Variable to store setup status 292 293 @return An error code: 0 - success, otherwise - failure 294 295 @ref Backend 296 **/ 297 298 int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) { 299 *issetupdone = op->setupdone; 300 return 0; 301 } 302 303 /** 304 @brief Get the QFunction associated with a CeedOperator 305 306 @param op CeedOperator 307 @param[out] qf Variable to store QFunction 308 309 @return An error code: 0 - success, otherwise - failure 310 311 @ref Backend 312 **/ 313 314 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 315 if (op->composite) 316 // LCOV_EXCL_START 317 return CeedError(op->ceed, 1, "Not defined for composite operator"); 318 // LCOV_EXCL_STOP 319 320 *qf = op->qf; 321 return 0; 322 } 323 324 /** 325 @brief Get a boolean value indicating if the CeedOperator is composite 326 327 @param op CeedOperator 328 @param[out] iscomposite Variable to store composite status 329 330 @return An error code: 0 - success, otherwise - failure 331 332 @ref Backend 333 **/ 334 335 int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) { 336 *iscomposite = op->composite; 337 return 0; 338 } 339 340 /** 341 @brief Get the number of suboperators associated with a CeedOperator 342 343 @param op CeedOperator 344 @param[out] numsub Variable to store number of suboperators 345 346 @return An error code: 0 - success, otherwise - failure 347 348 @ref Backend 349 **/ 350 351 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 352 if (!op->composite) 353 // LCOV_EXCL_START 354 return CeedError(op->ceed, 1, "Not a composite operator"); 355 // LCOV_EXCL_STOP 356 357 *numsub = op->numsub; 358 return 0; 359 } 360 361 /** 362 @brief Get the list of suboperators associated with a CeedOperator 363 364 @param op CeedOperator 365 @param[out] suboperators Variable to store list of suboperators 366 367 @return An error code: 0 - success, otherwise - failure 368 369 @ref Backend 370 **/ 371 372 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) { 373 if (!op->composite) 374 // LCOV_EXCL_START 375 return CeedError(op->ceed, 1, "Not a composite operator"); 376 // LCOV_EXCL_STOP 377 378 *suboperators = op->suboperators; 379 return 0; 380 } 381 382 /** 383 @brief Get the backend data of a CeedOperator 384 385 @param op CeedOperator 386 @param[out] data Variable to store data 387 388 @return An error code: 0 - success, otherwise - failure 389 390 @ref Backend 391 **/ 392 393 int CeedOperatorGetData(CeedOperator op, void **data) { 394 *data = op->data; 395 return 0; 396 } 397 398 /** 399 @brief Set the backend data of a CeedOperator 400 401 @param[out] op CeedOperator 402 @param data Data to set 403 404 @return An error code: 0 - success, otherwise - failure 405 406 @ref Backend 407 **/ 408 409 int CeedOperatorSetData(CeedOperator op, void **data) { 410 op->data = *data; 411 return 0; 412 } 413 414 /** 415 @brief Set the setup flag of a CeedOperator to True 416 417 @param op CeedOperator 418 419 @return An error code: 0 - success, otherwise - failure 420 421 @ref Backend 422 **/ 423 424 int CeedOperatorSetSetupDone(CeedOperator op) { 425 op->setupdone = 1; 426 return 0; 427 } 428 429 /** 430 @brief Get the CeedOperatorFields of a CeedOperator 431 432 @param op CeedOperator 433 @param[out] inputfields Variable to store inputfields 434 @param[out] outputfields Variable to store outputfields 435 436 @return An error code: 0 - success, otherwise - failure 437 438 @ref Backend 439 **/ 440 441 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields, 442 CeedOperatorField **outputfields) { 443 if (op->composite) 444 // LCOV_EXCL_START 445 return CeedError(op->ceed, 1, "Not defined for composite operator"); 446 // LCOV_EXCL_STOP 447 448 if (inputfields) *inputfields = op->inputfields; 449 if (outputfields) *outputfields = op->outputfields; 450 return 0; 451 } 452 453 /** 454 @brief Get the CeedElemRestriction of a CeedOperatorField 455 456 @param opfield CeedOperatorField 457 @param[out] rstr Variable to store CeedElemRestriction 458 459 @return An error code: 0 - success, otherwise - failure 460 461 @ref Backend 462 **/ 463 464 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 465 CeedElemRestriction *rstr) { 466 *rstr = opfield->Erestrict; 467 return 0; 468 } 469 470 /** 471 @brief Get the CeedBasis of a CeedOperatorField 472 473 @param opfield CeedOperatorField 474 @param[out] basis Variable to store CeedBasis 475 476 @return An error code: 0 - success, otherwise - failure 477 478 @ref Backend 479 **/ 480 481 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) { 482 *basis = opfield->basis; 483 return 0; 484 } 485 486 /** 487 @brief Get the CeedVector of a CeedOperatorField 488 489 @param opfield CeedOperatorField 490 @param[out] vec Variable to store CeedVector 491 492 @return An error code: 0 - success, otherwise - failure 493 494 @ref Backend 495 **/ 496 497 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) { 498 *vec = opfield->vec; 499 return 0; 500 } 501 502 /// @} 503 504 /// ---------------------------------------------------------------------------- 505 /// CeedOperator Public API 506 /// ---------------------------------------------------------------------------- 507 /// @addtogroup CeedOperatorUser 508 /// @{ 509 510 /** 511 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 512 CeedElemRestriction can be associated with CeedQFunction fields with 513 \ref CeedOperatorSetField. 514 515 @param ceed A Ceed object where the CeedOperator will be created 516 @param qf QFunction defining the action of the operator at quadrature points 517 @param dqf QFunction defining the action of the Jacobian of @a qf (or 518 @ref CEED_QFUNCTION_NONE) 519 @param dqfT QFunction defining the action of the transpose of the Jacobian 520 of @a qf (or @ref CEED_QFUNCTION_NONE) 521 @param[out] op Address of the variable where the newly created 522 CeedOperator will be stored 523 524 @return An error code: 0 - success, otherwise - failure 525 526 @ref User 527 */ 528 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 529 CeedQFunction dqfT, CeedOperator *op) { 530 int ierr; 531 532 if (!ceed->OperatorCreate) { 533 Ceed delegate; 534 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 535 536 if (!delegate) 537 // LCOV_EXCL_START 538 return CeedError(ceed, 1, "Backend does not support OperatorCreate"); 539 // LCOV_EXCL_STOP 540 541 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 542 return 0; 543 } 544 545 if (!qf || qf == CEED_QFUNCTION_NONE) 546 // LCOV_EXCL_START 547 return CeedError(ceed, 1, "Operator must have a valid QFunction."); 548 // LCOV_EXCL_STOP 549 ierr = CeedCalloc(1, op); CeedChk(ierr); 550 (*op)->ceed = ceed; 551 ceed->refcount++; 552 (*op)->refcount = 1; 553 (*op)->qf = qf; 554 qf->refcount++; 555 if (dqf && dqf != CEED_QFUNCTION_NONE) { 556 (*op)->dqf = dqf; 557 dqf->refcount++; 558 } 559 if (dqfT && dqfT != CEED_QFUNCTION_NONE) { 560 (*op)->dqfT = dqfT; 561 dqfT->refcount++; 562 } 563 ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr); 564 ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr); 565 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 566 return 0; 567 } 568 569 /** 570 @brief Create an operator that composes the action of several operators 571 572 @param ceed A Ceed object where the CeedOperator will be created 573 @param[out] op Address of the variable where the newly created 574 Composite CeedOperator will be stored 575 576 @return An error code: 0 - success, otherwise - failure 577 578 @ref User 579 */ 580 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 581 int ierr; 582 583 if (!ceed->CompositeOperatorCreate) { 584 Ceed delegate; 585 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 586 587 if (delegate) { 588 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 589 return 0; 590 } 591 } 592 593 ierr = CeedCalloc(1, op); CeedChk(ierr); 594 (*op)->ceed = ceed; 595 ceed->refcount++; 596 (*op)->composite = true; 597 ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr); 598 599 if (ceed->CompositeOperatorCreate) { 600 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 601 } 602 return 0; 603 } 604 605 /** 606 @brief Provide a field to a CeedOperator for use by its CeedQFunction 607 608 This function is used to specify both active and passive fields to a 609 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 610 fields can inputs or outputs (updated in-place when operator is applied). 611 612 Active fields must be specified using this function, but their data (in a 613 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 614 input and at most one active output. 615 616 @param op CeedOperator on which to provide the field 617 @param fieldname Name of the field (to be matched with the name used by 618 CeedQFunction) 619 @param r CeedElemRestriction 620 @param b CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED 621 if collocated with quadrature points 622 @param v CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE 623 if field is active or @ref CEED_VECTOR_NONE if using 624 @ref CEED_EVAL_WEIGHT in the QFunction 625 626 @return An error code: 0 - success, otherwise - failure 627 628 @ref User 629 **/ 630 int CeedOperatorSetField(CeedOperator op, const char *fieldname, 631 CeedElemRestriction r, CeedBasis b, CeedVector v) { 632 int ierr; 633 if (op->composite) 634 // LCOV_EXCL_START 635 return CeedError(op->ceed, 1, "Cannot add field to composite operator."); 636 // LCOV_EXCL_STOP 637 if (!r) 638 // LCOV_EXCL_START 639 return CeedError(op->ceed, 1, 640 "ElemRestriction r for field \"%s\" must be non-NULL.", 641 fieldname); 642 // LCOV_EXCL_STOP 643 if (!b) 644 // LCOV_EXCL_START 645 return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.", 646 fieldname); 647 // LCOV_EXCL_STOP 648 if (!v) 649 // LCOV_EXCL_START 650 return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.", 651 fieldname); 652 // LCOV_EXCL_STOP 653 654 CeedInt numelements; 655 ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr); 656 if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction && 657 op->numelements != numelements) 658 // LCOV_EXCL_START 659 return CeedError(op->ceed, 1, 660 "ElemRestriction with %d elements incompatible with prior " 661 "%d elements", numelements, op->numelements); 662 // LCOV_EXCL_STOP 663 if (r != CEED_ELEMRESTRICTION_NONE) { 664 op->numelements = numelements; 665 op->hasrestriction = true; // Restriction set, but numelements may be 0 666 } 667 668 if (b != CEED_BASIS_COLLOCATED) { 669 CeedInt numqpoints; 670 ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr); 671 if (op->numqpoints && op->numqpoints != numqpoints) 672 // LCOV_EXCL_START 673 return CeedError(op->ceed, 1, "Basis with %d quadrature points " 674 "incompatible with prior %d points", numqpoints, 675 op->numqpoints); 676 // LCOV_EXCL_STOP 677 op->numqpoints = numqpoints; 678 } 679 CeedQFunctionField qfield; 680 CeedOperatorField *ofield; 681 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 682 if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) { 683 qfield = op->qf->inputfields[i]; 684 ofield = &op->inputfields[i]; 685 goto found; 686 } 687 } 688 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 689 if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) { 690 qfield = op->qf->inputfields[i]; 691 ofield = &op->outputfields[i]; 692 goto found; 693 } 694 } 695 // LCOV_EXCL_START 696 return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'", 697 fieldname); 698 // LCOV_EXCL_STOP 699 found: 700 if (r == CEED_ELEMRESTRICTION_NONE && qfield->emode != CEED_EVAL_WEIGHT) 701 // LCOV_EXCL_START 702 return CeedError(op->ceed, 1, "CEED_ELEMRESTRICTION_NONE can only be used " 703 "for a field with eval mode CEED_EVAL_WEIGHT"); 704 // LCOV_EXCL_STOP 705 ierr = CeedCalloc(1, ofield); CeedChk(ierr); 706 (*ofield)->Erestrict = r; 707 r->refcount += 1; 708 (*ofield)->basis = b; 709 if (b != CEED_BASIS_COLLOCATED) 710 b->refcount += 1; 711 (*ofield)->vec = v; 712 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) 713 v->refcount += 1; 714 op->nfields += 1; 715 return 0; 716 } 717 718 /** 719 @brief Add a sub-operator to a composite CeedOperator 720 721 @param[out] compositeop Composite CeedOperator 722 @param subop Sub-operator CeedOperator 723 724 @return An error code: 0 - success, otherwise - failure 725 726 @ref User 727 */ 728 int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) { 729 if (!compositeop->composite) 730 // LCOV_EXCL_START 731 return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite " 732 "operator"); 733 // LCOV_EXCL_STOP 734 735 if (compositeop->numsub == CEED_COMPOSITE_MAX) 736 // LCOV_EXCL_START 737 return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators"); 738 // LCOV_EXCL_STOP 739 740 compositeop->suboperators[compositeop->numsub] = subop; 741 subop->refcount++; 742 compositeop->numsub++; 743 return 0; 744 } 745 746 /** 747 @brief Assemble a linear CeedQFunction associated with a CeedOperator 748 749 This returns a CeedVector containing a matrix at each quadrature point 750 providing the action of the CeedQFunction associated with the CeedOperator. 751 The vector 'assembled' is of shape 752 [num_elements, num_input_fields, num_output_fields, num_quad_points] 753 and contains column-major matrices representing the action of the 754 CeedQFunction for a corresponding quadrature point on an element. Inputs and 755 outputs are in the order provided by the user when adding CeedOperator fields. 756 For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and 757 'v', provided in that order, would result in an assembled QFunction that 758 consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting 759 on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v]. 760 761 @param op CeedOperator to assemble CeedQFunction 762 @param[out] assembled CeedVector to store assembled CeedQFunction at 763 quadrature points 764 @param[out] rstr CeedElemRestriction for CeedVector containing assembled 765 CeedQFunction 766 @param request Address of CeedRequest for non-blocking completion, else 767 @ref CEED_REQUEST_IMMEDIATE 768 769 @return An error code: 0 - success, otherwise - failure 770 771 @ref User 772 **/ 773 int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled, 774 CeedElemRestriction *rstr, 775 CeedRequest *request) { 776 int ierr; 777 Ceed ceed = op->ceed; 778 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 779 780 // Backend version 781 if (op->LinearAssembleQFunction) { 782 ierr = op->LinearAssembleQFunction(op, assembled, rstr, request); 783 CeedChk(ierr); 784 } else { 785 // Fallback to reference Ceed 786 if (!op->opfallback) { 787 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 788 } 789 // Assemble 790 ierr = op->opfallback->LinearAssembleQFunction(op->opfallback, assembled, 791 rstr, request); CeedChk(ierr); 792 } 793 794 return 0; 795 } 796 797 /** 798 @brief Assemble the diagonal of a square linear CeedOperator 799 800 This overwrites a CeedVector with the diagonal of a linear CeedOperator. 801 802 Note: Currently only non-composite CeedOperators with a single field and 803 composite CeedOperators with single field sub-operators are supported. 804 805 @param op CeedOperator to assemble CeedQFunction 806 @param[out] assembled CeedVector to store assembled CeedOperator diagonal 807 @param request Address of CeedRequest for non-blocking completion, else 808 @ref CEED_REQUEST_IMMEDIATE 809 810 @return An error code: 0 - success, otherwise - failure 811 812 @ref User 813 **/ 814 int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled, 815 CeedRequest *request) { 816 int ierr; 817 Ceed ceed = op->ceed; 818 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 819 820 // Use backend version, if available 821 if (op->LinearAssembleDiagonal) { 822 ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr); 823 } else if (op->LinearAssembleAddDiagonal) { 824 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 825 return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request); 826 } else { 827 // Fallback to reference Ceed 828 if (!op->opfallback) { 829 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 830 } 831 // Assemble 832 if (op->opfallback->LinearAssembleDiagonal) { 833 ierr = op->opfallback->LinearAssembleDiagonal(op->opfallback, assembled, 834 request); CeedChk(ierr); 835 } else { 836 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 837 return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request); 838 } 839 } 840 841 return 0; 842 } 843 844 /** 845 @brief Assemble the diagonal of a square linear CeedOperator 846 847 This sums into a CeedVector the diagonal of a linear CeedOperator. 848 849 Note: Currently only non-composite CeedOperators with a single field and 850 composite CeedOperators with single field sub-operators are supported. 851 852 @param op CeedOperator to assemble CeedQFunction 853 @param[out] assembled CeedVector to store assembled CeedOperator diagonal 854 @param request Address of CeedRequest for non-blocking completion, else 855 @ref CEED_REQUEST_IMMEDIATE 856 857 @return An error code: 0 - success, otherwise - failure 858 859 @ref User 860 **/ 861 int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled, 862 CeedRequest *request) { 863 int ierr; 864 Ceed ceed = op->ceed; 865 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 866 867 // Use backend version, if available 868 if (op->LinearAssembleAddDiagonal) { 869 ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr); 870 } else { 871 // Fallback to reference Ceed 872 if (!op->opfallback) { 873 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 874 } 875 // Assemble 876 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 877 ierr = op->opfallback->LinearAssembleAddDiagonal(op->opfallback, assembled, 878 request); CeedChk(ierr); 879 } 880 881 return 0; 882 } 883 884 /** 885 @brief Assemble the point block diagonal of a square linear CeedOperator 886 887 This overwrites a CeedVector with the point block diagonal of a linear 888 CeedOperator. 889 890 Note: Currently only non-composite CeedOperators with a single field and 891 composite CeedOperators with single field sub-operators are supported. 892 893 @param op CeedOperator to assemble CeedQFunction 894 @param[out] assembled CeedVector to store assembled CeedOperator point block 895 diagonal, provided in row-major form with an 896 @a ncomp * @a ncomp block at each node. The dimensions 897 of this vector are derived from the active vector 898 for the CeedOperator. The array has shape 899 [nodes, component out, component in]. 900 @param request Address of CeedRequest for non-blocking completion, else 901 CEED_REQUEST_IMMEDIATE 902 903 @return An error code: 0 - success, otherwise - failure 904 905 @ref User 906 **/ 907 int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op, 908 CeedVector assembled, CeedRequest *request) { 909 int ierr; 910 Ceed ceed = op->ceed; 911 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 912 913 // Use backend version, if available 914 if (op->LinearAssemblePointBlockDiagonal) { 915 ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request); 916 CeedChk(ierr); 917 } else if (op->LinearAssembleAddPointBlockDiagonal) { 918 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 919 return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, 920 request); 921 } else { 922 // Fallback to reference Ceed 923 if (!op->opfallback) { 924 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 925 } 926 // Assemble 927 if (op->opfallback->LinearAssemblePointBlockDiagonal) { 928 ierr = op->opfallback->LinearAssemblePointBlockDiagonal(op->opfallback, 929 assembled, request); CeedChk(ierr); 930 } else { 931 ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr); 932 return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled, 933 request); 934 } 935 } 936 937 return 0; 938 } 939 940 /** 941 @brief Assemble the point block diagonal of a square linear CeedOperator 942 943 This sums into a CeedVector with the point block diagonal of a linear 944 CeedOperator. 945 946 Note: Currently only non-composite CeedOperators with a single field and 947 composite CeedOperators with single field sub-operators are supported. 948 949 @param op CeedOperator to assemble CeedQFunction 950 @param[out] assembled CeedVector to store assembled CeedOperator point block 951 diagonal, provided in row-major form with an 952 @a ncomp * @a ncomp block at each node. The dimensions 953 of this vector are derived from the active vector 954 for the CeedOperator. The array has shape 955 [nodes, component out, component in]. 956 @param request Address of CeedRequest for non-blocking completion, else 957 CEED_REQUEST_IMMEDIATE 958 959 @return An error code: 0 - success, otherwise - failure 960 961 @ref User 962 **/ 963 int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op, 964 CeedVector assembled, CeedRequest *request) { 965 int ierr; 966 Ceed ceed = op->ceed; 967 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 968 969 // Use backend version, if available 970 if (op->LinearAssembleAddPointBlockDiagonal) { 971 ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request); 972 CeedChk(ierr); 973 } else { 974 // Fallback to reference Ceed 975 if (!op->opfallback) { 976 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 977 } 978 // Assemble 979 ierr = op->opfallback->LinearAssembleAddPointBlockDiagonal(op->opfallback, 980 assembled, request); CeedChk(ierr); 981 } 982 983 return 0; 984 } 985 986 /** 987 @brief Build a FDM based approximate inverse for each element for a 988 CeedOperator 989 990 This returns a CeedOperator and CeedVector to apply a Fast Diagonalization 991 Method based approximate inverse. This function obtains the simultaneous 992 diagonalization for the 1D mass and Laplacian operators, 993 M = V^T V, K = V^T S V. 994 The assembled QFunction is used to modify the eigenvalues from simultaneous 995 diagonalization and obtain an approximate inverse of the form 996 V^T S^hat V. The CeedOperator must be linear and non-composite. The 997 associated CeedQFunction must therefore also be linear. 998 999 @param op CeedOperator to create element inverses 1000 @param[out] fdminv CeedOperator to apply the action of a FDM based inverse 1001 for each element 1002 @param request Address of CeedRequest for non-blocking completion, else 1003 @ref CEED_REQUEST_IMMEDIATE 1004 1005 @return An error code: 0 - success, otherwise - failure 1006 1007 @ref Backend 1008 **/ 1009 int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv, 1010 CeedRequest *request) { 1011 int ierr; 1012 Ceed ceed = op->ceed; 1013 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1014 1015 // Use backend version, if available 1016 if (op->CreateFDMElementInverse) { 1017 ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr); 1018 } else { 1019 // Fallback to reference Ceed 1020 if (!op->opfallback) { 1021 ierr = CeedOperatorCreateFallback(op); CeedChk(ierr); 1022 } 1023 // Assemble 1024 ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv, 1025 request); CeedChk(ierr); 1026 } 1027 1028 return 0; 1029 } 1030 1031 /** 1032 @brief View a CeedOperator 1033 1034 @param[in] op CeedOperator to view 1035 @param[in] stream Stream to write; typically stdout/stderr or a file 1036 1037 @return Error code: 0 - success, otherwise - failure 1038 1039 @ref User 1040 **/ 1041 int CeedOperatorView(CeedOperator op, FILE *stream) { 1042 int ierr; 1043 1044 if (op->composite) { 1045 fprintf(stream, "Composite CeedOperator\n"); 1046 1047 for (CeedInt i=0; i<op->numsub; i++) { 1048 fprintf(stream, " SubOperator [%d]:\n", i); 1049 ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream); 1050 CeedChk(ierr); 1051 } 1052 } else { 1053 fprintf(stream, "CeedOperator\n"); 1054 ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr); 1055 } 1056 1057 return 0; 1058 } 1059 1060 /** 1061 @brief Apply CeedOperator to a vector 1062 1063 This computes the action of the operator on the specified (active) input, 1064 yielding its (active) output. All inputs and outputs must be specified using 1065 CeedOperatorSetField(). 1066 1067 @param op CeedOperator to apply 1068 @param[in] in CeedVector containing input state or @ref CEED_VECTOR_NONE if 1069 there are no active inputs 1070 @param[out] out CeedVector to store result of applying operator (must be 1071 distinct from @a in) or @ref CEED_VECTOR_NONE if there are no 1072 active outputs 1073 @param request Address of CeedRequest for non-blocking completion, else 1074 @ref CEED_REQUEST_IMMEDIATE 1075 1076 @return An error code: 0 - success, otherwise - failure 1077 1078 @ref User 1079 **/ 1080 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, 1081 CeedRequest *request) { 1082 int ierr; 1083 Ceed ceed = op->ceed; 1084 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1085 1086 if (op->numelements) { 1087 // Standard Operator 1088 if (op->Apply) { 1089 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 1090 } else { 1091 // Zero all output vectors 1092 CeedQFunction qf = op->qf; 1093 for (CeedInt i=0; i<qf->numoutputfields; i++) { 1094 CeedVector vec = op->outputfields[i]->vec; 1095 if (vec == CEED_VECTOR_ACTIVE) 1096 vec = out; 1097 if (vec != CEED_VECTOR_NONE) { 1098 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1099 } 1100 } 1101 // Apply 1102 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1103 } 1104 } else if (op->composite) { 1105 // Composite Operator 1106 if (op->ApplyComposite) { 1107 ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr); 1108 } else { 1109 CeedInt numsub; 1110 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 1111 CeedOperator *suboperators; 1112 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 1113 1114 // Zero all output vectors 1115 if (out != CEED_VECTOR_NONE) { 1116 ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr); 1117 } 1118 for (CeedInt i=0; i<numsub; i++) { 1119 for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) { 1120 CeedVector vec = suboperators[i]->outputfields[j]->vec; 1121 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) { 1122 ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr); 1123 } 1124 } 1125 } 1126 // Apply 1127 for (CeedInt i=0; i<op->numsub; i++) { 1128 ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request); 1129 CeedChk(ierr); 1130 } 1131 } 1132 } 1133 1134 return 0; 1135 } 1136 1137 /** 1138 @brief Apply CeedOperator to a vector and add result to output vector 1139 1140 This computes the action of the operator on the specified (active) input, 1141 yielding its (active) output. All inputs and outputs must be specified using 1142 CeedOperatorSetField(). 1143 1144 @param op CeedOperator to apply 1145 @param[in] in CeedVector containing input state or NULL if there are no 1146 active inputs 1147 @param[out] out CeedVector to sum in result of applying operator (must be 1148 distinct from @a in) or NULL if there are no active outputs 1149 @param request Address of CeedRequest for non-blocking completion, else 1150 @ref CEED_REQUEST_IMMEDIATE 1151 1152 @return An error code: 0 - success, otherwise - failure 1153 1154 @ref User 1155 **/ 1156 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, 1157 CeedRequest *request) { 1158 int ierr; 1159 Ceed ceed = op->ceed; 1160 ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr); 1161 1162 if (op->numelements) { 1163 // Standard Operator 1164 ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr); 1165 } else if (op->composite) { 1166 // Composite Operator 1167 if (op->ApplyAddComposite) { 1168 ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr); 1169 } else { 1170 CeedInt numsub; 1171 ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr); 1172 CeedOperator *suboperators; 1173 ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr); 1174 1175 for (CeedInt i=0; i<numsub; i++) { 1176 ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request); 1177 CeedChk(ierr); 1178 } 1179 } 1180 } 1181 1182 return 0; 1183 } 1184 1185 /** 1186 @brief Destroy a CeedOperator 1187 1188 @param op CeedOperator to destroy 1189 1190 @return An error code: 0 - success, otherwise - failure 1191 1192 @ref User 1193 **/ 1194 int CeedOperatorDestroy(CeedOperator *op) { 1195 int ierr; 1196 1197 if (!*op || --(*op)->refcount > 0) return 0; 1198 if ((*op)->Destroy) { 1199 ierr = (*op)->Destroy(*op); CeedChk(ierr); 1200 } 1201 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 1202 // Free fields 1203 for (int i=0; i<(*op)->nfields; i++) 1204 if ((*op)->inputfields[i]) { 1205 if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) { 1206 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 1207 CeedChk(ierr); 1208 } 1209 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1210 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 1211 } 1212 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 1213 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 1214 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 1215 } 1216 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 1217 } 1218 for (int i=0; i<(*op)->nfields; i++) 1219 if ((*op)->outputfields[i]) { 1220 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 1221 CeedChk(ierr); 1222 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 1223 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 1224 } 1225 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 1226 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 1227 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 1228 } 1229 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 1230 } 1231 // Destroy suboperators 1232 for (int i=0; i<(*op)->numsub; i++) 1233 if ((*op)->suboperators[i]) { 1234 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 1235 } 1236 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 1237 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 1238 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 1239 1240 // Destroy fallback 1241 if ((*op)->opfallback) { 1242 ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr); 1243 ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr); 1244 ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr); 1245 ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr); 1246 } 1247 1248 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 1249 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 1250 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 1251 ierr = CeedFree(op); CeedChk(ierr); 1252 return 0; 1253 } 1254 1255 /// @} 1256