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