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