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 21 /// @file 22 /// Implementation of public CeedOperator interfaces 23 /// 24 /// @addtogroup CeedOperator 25 /// @{ 26 27 /** 28 @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and 29 CeedElemRestriction can be associated with CeedQFunction fields with 30 \ref CeedOperatorSetField. 31 32 @param ceed A Ceed object where the CeedOperator will be created 33 @param qf QFunction defining the action of the operator at quadrature points 34 @param dqf QFunction defining the action of the Jacobian of @a qf (or NULL) 35 @param dqfT QFunction defining the action of the transpose of the Jacobian 36 of @a qf (or NULL) 37 @param[out] op Address of the variable where the newly created 38 CeedOperator will be stored 39 40 @return An error code: 0 - success, otherwise - failure 41 42 @ref Basic 43 */ 44 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, 45 CeedQFunction dqfT, CeedOperator *op) { 46 int ierr; 47 48 if (!ceed->OperatorCreate) { 49 Ceed delegate; 50 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 51 52 if (!delegate) 53 // LCOV_EXCL_START 54 return CeedError(ceed, 1, "Backend does not support OperatorCreate"); 55 // LCOV_EXCL_STOP 56 57 ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr); 58 return 0; 59 } 60 61 ierr = CeedCalloc(1,op); CeedChk(ierr); 62 (*op)->ceed = ceed; 63 ceed->refcount++; 64 (*op)->refcount = 1; 65 (*op)->qf = qf; 66 qf->refcount++; 67 (*op)->dqf = dqf; 68 if (dqf) dqf->refcount++; 69 (*op)->dqfT = dqfT; 70 if (dqfT) dqfT->refcount++; 71 ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr); 72 ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr); 73 ierr = ceed->OperatorCreate(*op); CeedChk(ierr); 74 return 0; 75 } 76 77 /** 78 @brief Create an operator that composes the action of several operators 79 80 @param ceed A Ceed object where the CeedOperator will be created 81 @param[out] op Address of the variable where the newly created 82 Composite CeedOperator will be stored 83 84 @return An error code: 0 - success, otherwise - failure 85 86 @ref Basic 87 */ 88 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) { 89 int ierr; 90 91 if (!ceed->CompositeOperatorCreate) { 92 Ceed delegate; 93 ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr); 94 95 if (!delegate) 96 // LCOV_EXCL_START 97 return CeedError(ceed, 1, "Backend does not support CompositeOperatorCreate"); 98 // LCOV_EXCL_STOP 99 100 ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr); 101 return 0; 102 } 103 104 ierr = CeedCalloc(1,op); CeedChk(ierr); 105 (*op)->ceed = ceed; 106 ceed->refcount++; 107 (*op)->composite = true; 108 ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr); 109 ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr); 110 return 0; 111 } 112 113 /** 114 @brief Provide a field to a CeedOperator for use by its CeedQFunction 115 116 This function is used to specify both active and passive fields to a 117 CeedOperator. For passive fields, a vector @arg v must be provided. Passive 118 fields can inputs or outputs (updated in-place when operator is applied). 119 120 Active fields must be specified using this function, but their data (in a 121 CeedVector) is passed in CeedOperatorApply(). There can be at most one active 122 input and at most one active output. 123 124 @param op CeedOperator on which to provide the field 125 @param fieldname Name of the field (to be matched with the name used by 126 CeedQFunction) 127 @param r CeedElemRestriction 128 @param lmode CeedTransposeMode which specifies the ordering of the 129 components of the l-vector used by this CeedOperatorField, 130 CEED_NOTRANSPOSE indicates the component is the 131 outermost index and CEED_TRANSPOSE indicates the component 132 is the innermost index in ordering of the l-vector 133 @param b CeedBasis in which the field resides or CEED_BASIS_COLLOCATED 134 if collocated with quadrature points 135 @param v CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE 136 if field is active or CEED_VECTOR_NONE if using 137 CEED_EVAL_WEIGHT in the QFunction 138 139 @return An error code: 0 - success, otherwise - failure 140 141 @ref Basic 142 **/ 143 int CeedOperatorSetField(CeedOperator op, const char *fieldname, 144 CeedElemRestriction r, CeedTransposeMode lmode, 145 CeedBasis b, CeedVector v) { 146 int ierr; 147 if (op->composite) 148 // LCOV_EXCL_START 149 return CeedError(op->ceed, 1, "Cannot add field to composite operator."); 150 // LCOV_EXCL_STOP 151 if (!r) 152 // LCOV_EXCL_START 153 return CeedError(op->ceed, 1, 154 "ElemRestriction r for field \"%s\" must be non-NULL.", 155 fieldname); 156 // LCOV_EXCL_STOP 157 if (!b) 158 // LCOV_EXCL_START 159 return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.", 160 fieldname); 161 // LCOV_EXCL_STOP 162 if (!v) 163 // LCOV_EXCL_START 164 return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.", 165 fieldname); 166 // LCOV_EXCL_STOP 167 168 CeedInt numelements; 169 ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr); 170 if (op->numelements && op->numelements != numelements) 171 // LCOV_EXCL_START 172 return CeedError(op->ceed, 1, 173 "ElemRestriction with %d elements incompatible with prior %d elements", 174 numelements, op->numelements); 175 // LCOV_EXCL_STOP 176 op->numelements = numelements; 177 178 if (b != CEED_BASIS_COLLOCATED) { 179 CeedInt numqpoints; 180 ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr); 181 if (op->numqpoints && op->numqpoints != numqpoints) 182 // LCOV_EXCL_START 183 return CeedError(op->ceed, 1, 184 "Basis with %d quadrature points incompatible with prior %d points", 185 numqpoints, op->numqpoints); 186 // LCOV_EXCL_STOP 187 op->numqpoints = numqpoints; 188 } 189 CeedOperatorField *ofield; 190 for (CeedInt i=0; i<op->qf->numinputfields; i++) { 191 if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) { 192 ofield = &op->inputfields[i]; 193 goto found; 194 } 195 } 196 for (CeedInt i=0; i<op->qf->numoutputfields; i++) { 197 if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) { 198 ofield = &op->outputfields[i]; 199 goto found; 200 } 201 } 202 // LCOV_EXCL_START 203 return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'", 204 fieldname); 205 // LCOV_EXCL_STOP 206 found: 207 ierr = CeedCalloc(1, ofield); CeedChk(ierr); 208 (*ofield)->Erestrict = r; 209 r->refcount += 1; 210 (*ofield)->lmode = lmode; 211 (*ofield)->basis = b; 212 if (b != CEED_BASIS_COLLOCATED) 213 b->refcount += 1; 214 (*ofield)->vec = v; 215 if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) 216 v->refcount += 1; 217 op->nfields += 1; 218 return 0; 219 } 220 221 /** 222 @brief Add a sub-operator to a composite CeedOperator 223 224 @param[out] compositeop Address of the composite CeedOperator 225 @param subop Address of the sub-operator CeedOperator 226 227 @return An error code: 0 - success, otherwise - failure 228 229 @ref Basic 230 */ 231 int CeedCompositeOperatorAddSub(CeedOperator compositeop, 232 CeedOperator subop) { 233 if (!compositeop->composite) 234 // LCOV_EXCL_START 235 return CeedError(compositeop->ceed, 1, 236 "CeedOperator is not a composite operator"); 237 // LCOV_EXCL_STOP 238 239 if (compositeop->numsub == CEED_COMPOSITE_MAX) 240 // LCOV_EXCL_START 241 return CeedError(compositeop->ceed, 1, 242 "Cannot add additional suboperators"); 243 // LCOV_EXCL_STOP 244 245 compositeop->suboperators[compositeop->numsub] = subop; 246 subop->refcount++; 247 compositeop->numsub++; 248 return 0; 249 } 250 251 /** 252 @brief Apply CeedOperator to a vector 253 254 This computes the action of the operator on the specified (active) input, 255 yielding its (active) output. All inputs and outputs must be specified using 256 CeedOperatorSetField(). 257 258 @param op CeedOperator to apply 259 @param[in] in CeedVector containing input state or NULL if there are no 260 active inputs 261 @param[out] out CeedVector to store result of applying operator (must be 262 distinct from @a in) or NULL if there are no active outputs 263 @param request Address of CeedRequest for non-blocking completion, else 264 CEED_REQUEST_IMMEDIATE 265 266 @return An error code: 0 - success, otherwise - failure 267 268 @ref Basic 269 **/ 270 int CeedOperatorApply(CeedOperator op, CeedVector in, 271 CeedVector out, CeedRequest *request) { 272 int ierr; 273 Ceed ceed = op->ceed; 274 CeedQFunction qf = op->qf; 275 276 if (op->composite) { 277 if (!op->numsub) 278 // LCOV_EXCL_START 279 return CeedError(ceed, 1, "No suboperators set"); 280 // LCOV_EXCL_STOP 281 } else { 282 if (op->nfields == 0) 283 // LCOV_EXCL_START 284 return CeedError(ceed, 1, "No operator fields set"); 285 // LCOV_EXCL_STOP 286 if (op->nfields < qf->numinputfields + qf->numoutputfields) 287 // LCOV_EXCL_START 288 return CeedError(ceed, 1, "Not all operator fields set"); 289 // LCOV_EXCL_STOP 290 if (op->numelements == 0) 291 // LCOV_EXCL_START 292 return CeedError(ceed, 1,"At least one restriction required"); 293 // LCOV_EXCL_STOP 294 if (op->numqpoints == 0) 295 // LCOV_EXCL_START 296 return CeedError(ceed, 1,"At least one non-collocated basis required"); 297 // LCOV_EXCL_STOP 298 } 299 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 300 return 0; 301 } 302 303 /** 304 @brief Get the Ceed associated with a CeedOperator 305 306 @param op CeedOperator 307 @param[out] ceed Variable to store Ceed 308 309 @return An error code: 0 - success, otherwise - failure 310 311 @ref Advanced 312 **/ 313 314 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 315 *ceed = op->ceed; 316 return 0; 317 } 318 319 /** 320 @brief Get the number of elements associated with a CeedOperator 321 322 @param op CeedOperator 323 @param[out] numelem Variable to store number of elements 324 325 @return An error code: 0 - success, otherwise - failure 326 327 @ref Advanced 328 **/ 329 330 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 331 if (op->composite) 332 // LCOV_EXCL_START 333 return CeedError(op->ceed, 1, "Not defined for composite operator"); 334 // LCOV_EXCL_STOP 335 336 *numelem = op->numelements; 337 return 0; 338 } 339 340 /** 341 @brief Get the number of quadrature points associated with a CeedOperator 342 343 @param op CeedOperator 344 @param[out] numqpts Variable to store vector number of quadrature points 345 346 @return An error code: 0 - success, otherwise - failure 347 348 @ref Advanced 349 **/ 350 351 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 352 if (op->composite) 353 // LCOV_EXCL_START 354 return CeedError(op->ceed, 1, "Not defined for composite operator"); 355 // LCOV_EXCL_STOP 356 357 *numqpts = op->numqpoints; 358 return 0; 359 } 360 361 /** 362 @brief Get the number of arguments associated with a CeedOperator 363 364 @param op CeedOperator 365 @param[out] numargs Variable to store vector number of arguments 366 367 @return An error code: 0 - success, otherwise - failure 368 369 @ref Advanced 370 **/ 371 372 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 373 if (op->composite) 374 // LCOV_EXCL_START 375 return CeedError(op->ceed, 1, "Not defined for composite operators"); 376 // LCOV_EXCL_STOP 377 378 *numargs = op->nfields; 379 return 0; 380 } 381 382 /** 383 @brief Get the setup status of a CeedOperator 384 385 @param op CeedOperator 386 @param[out] setupdone Variable to store setup status 387 388 @return An error code: 0 - success, otherwise - failure 389 390 @ref Advanced 391 **/ 392 393 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 394 *setupdone = op->setupdone; 395 return 0; 396 } 397 398 /** 399 @brief Get the QFunction associated with a CeedOperator 400 401 @param op CeedOperator 402 @param[out] qf Variable to store QFunction 403 404 @return An error code: 0 - success, otherwise - failure 405 406 @ref Advanced 407 **/ 408 409 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 410 if (op->composite) 411 // LCOV_EXCL_START 412 return CeedError(op->ceed, 1, "Not defined for composite operator"); 413 // LCOV_EXCL_STOP 414 415 *qf = op->qf; 416 return 0; 417 } 418 419 /** 420 @brief Get the number of suboperators associated with a CeedOperator 421 422 @param op CeedOperator 423 @param[out] numsub Variable to store number of suboperators 424 425 @return An error code: 0 - success, otherwise - failure 426 427 @ref Advanced 428 **/ 429 430 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 431 if (!op->composite) 432 // LCOV_EXCL_START 433 return CeedError(op->ceed, 1, "Not a composite operator"); 434 // LCOV_EXCL_STOP 435 436 *numsub = op->numsub; 437 return 0; 438 } 439 440 /** 441 @brief Get the list of suboperators associated with a CeedOperator 442 443 @param op CeedOperator 444 @param[out] suboperators Variable to store list of suboperators 445 446 @return An error code: 0 - success, otherwise - failure 447 448 @ref Advanced 449 **/ 450 451 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) { 452 if (!op->composite) 453 // LCOV_EXCL_START 454 return CeedError(op->ceed, 1, "Not a composite operator"); 455 // LCOV_EXCL_STOP 456 457 *suboperators = op->suboperators; 458 return 0; 459 } 460 461 /** 462 @brief Set the backend data of a CeedOperator 463 464 @param[out] op CeedOperator 465 @param data Data to set 466 467 @return An error code: 0 - success, otherwise - failure 468 469 @ref Advanced 470 **/ 471 472 int CeedOperatorSetData(CeedOperator op, void* *data) { 473 op->data = *data; 474 return 0; 475 } 476 477 /** 478 @brief Get the backend data of a CeedOperator 479 480 @param op CeedOperator 481 @param[out] data Variable to store data 482 483 @return An error code: 0 - success, otherwise - failure 484 485 @ref Advanced 486 **/ 487 488 int CeedOperatorGetData(CeedOperator op, void* *data) { 489 *data = op->data; 490 return 0; 491 } 492 493 /** 494 @brief Set the setup flag of a CeedOperator to True 495 496 @param op CeedOperator 497 498 @return An error code: 0 - success, otherwise - failure 499 500 @ref Advanced 501 **/ 502 503 int CeedOperatorSetSetupDone(CeedOperator op) { 504 op->setupdone = 1; 505 return 0; 506 } 507 508 /** 509 @brief Get the CeedOperatorFields of a CeedOperator 510 511 @param op CeedOperator 512 @param[out] inputfields Variable to store inputfields 513 @param[out] outputfields Variable to store outputfields 514 515 @return An error code: 0 - success, otherwise - failure 516 517 @ref Advanced 518 **/ 519 520 int CeedOperatorGetFields(CeedOperator op, 521 CeedOperatorField* *inputfields, 522 CeedOperatorField* *outputfields) { 523 if (op->composite) 524 // LCOV_EXCL_START 525 return CeedError(op->ceed, 1, "Not defined for composite operator"); 526 // LCOV_EXCL_STOP 527 528 if (inputfields) *inputfields = op->inputfields; 529 if (outputfields) *outputfields = op->outputfields; 530 return 0; 531 } 532 533 /** 534 @brief Get the L vector CeedTransposeMode of a CeedOperatorField 535 536 @param opfield CeedOperatorField 537 @param[out] lmode Variable to store CeedTransposeMode 538 539 @return An error code: 0 - success, otherwise - failure 540 541 @ref Advanced 542 **/ 543 544 int CeedOperatorFieldGetLMode(CeedOperatorField opfield, 545 CeedTransposeMode *lmode) { 546 *lmode = opfield->lmode; 547 return 0; 548 } 549 550 /** 551 @brief Get the CeedElemRestriction of a CeedOperatorField 552 553 @param opfield CeedOperatorField 554 @param[out] rstr Variable to store CeedElemRestriction 555 556 @return An error code: 0 - success, otherwise - failure 557 558 @ref Advanced 559 **/ 560 561 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 562 CeedElemRestriction *rstr) { 563 *rstr = opfield->Erestrict; 564 return 0; 565 } 566 567 /** 568 @brief Get the CeedBasis of a CeedOperatorField 569 570 @param opfield CeedOperatorField 571 @param[out] basis Variable to store CeedBasis 572 573 @return An error code: 0 - success, otherwise - failure 574 575 @ref Advanced 576 **/ 577 578 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, 579 CeedBasis *basis) { 580 *basis = opfield->basis; 581 return 0; 582 } 583 584 /** 585 @brief Get the CeedVector of a CeedOperatorField 586 587 @param opfield CeedOperatorField 588 @param[out] vec Variable to store CeedVector 589 590 @return An error code: 0 - success, otherwise - failure 591 592 @ref Advanced 593 **/ 594 595 int CeedOperatorFieldGetVector(CeedOperatorField opfield, 596 CeedVector *vec) { 597 *vec = opfield->vec; 598 return 0; 599 } 600 601 /** 602 @brief Destroy a CeedOperator 603 604 @param op CeedOperator to destroy 605 606 @return An error code: 0 - success, otherwise - failure 607 608 @ref Basic 609 **/ 610 int CeedOperatorDestroy(CeedOperator *op) { 611 int ierr; 612 613 if (!*op || --(*op)->refcount > 0) return 0; 614 if ((*op)->Destroy) { 615 ierr = (*op)->Destroy(*op); CeedChk(ierr); 616 } 617 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 618 // Free fields 619 for (int i=0; i<(*op)->nfields; i++) { 620 if ((*op)->inputfields[i]) { 621 ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict); 622 CeedChk(ierr); 623 if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) { 624 ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr); 625 } 626 if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE && 627 (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) { 628 ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr); 629 } 630 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 631 } 632 } 633 for (int i=0; i<(*op)->nfields; i++) { 634 if ((*op)->outputfields[i]) { 635 ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict); 636 CeedChk(ierr); 637 if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) { 638 ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr); 639 } 640 if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE && 641 (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) { 642 ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr); 643 } 644 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 645 } 646 } 647 // Destroy suboperators 648 for (int i=0; i<(*op)->numsub; i++) { 649 if ((*op)->suboperators[i]) { 650 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 651 } 652 } 653 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 654 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 655 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 656 657 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 658 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 659 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 660 ierr = CeedFree(op); CeedChk(ierr); 661 return 0; 662 } 663 664 /// @} 665