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 (*ofield)->lmode = lmode; 210 (*ofield)->basis = b; 211 (*ofield)->vec = v; 212 op->nfields += 1; 213 return 0; 214 } 215 216 /** 217 @brief Add a sub-operator to a composite CeedOperator 218 219 @param[out] compositeop Address of the composite CeedOperator 220 @param subop Address of the sub-operator CeedOperator 221 222 @return An error code: 0 - success, otherwise - failure 223 224 @ref Basic 225 */ 226 int CeedCompositeOperatorAddSub(CeedOperator compositeop, 227 CeedOperator subop) { 228 if (!compositeop->composite) 229 // LCOV_EXCL_START 230 return CeedError(compositeop->ceed, 1, 231 "CeedOperator is not a composite operator"); 232 // LCOV_EXCL_STOP 233 234 if (compositeop->numsub == CEED_COMPOSITE_MAX) 235 // LCOV_EXCL_START 236 return CeedError(compositeop->ceed, 1, 237 "Cannot add additional suboperators"); 238 // LCOV_EXCL_STOP 239 240 compositeop->suboperators[compositeop->numsub] = subop; 241 subop->refcount++; 242 compositeop->numsub++; 243 return 0; 244 } 245 246 /** 247 @brief Apply CeedOperator to a vector 248 249 This computes the action of the operator on the specified (active) input, 250 yielding its (active) output. All inputs and outputs must be specified using 251 CeedOperatorSetField(). 252 253 @param op CeedOperator to apply 254 @param[in] in CeedVector containing input state or NULL if there are no 255 active inputs 256 @param[out] out CeedVector to store result of applying operator (must be 257 distinct from @a in) or NULL if there are no active outputs 258 @param request Address of CeedRequest for non-blocking completion, else 259 CEED_REQUEST_IMMEDIATE 260 261 @return An error code: 0 - success, otherwise - failure 262 263 @ref Basic 264 **/ 265 int CeedOperatorApply(CeedOperator op, CeedVector in, 266 CeedVector out, CeedRequest *request) { 267 int ierr; 268 Ceed ceed = op->ceed; 269 CeedQFunction qf = op->qf; 270 271 if (op->composite) { 272 if (!op->numsub) 273 // LCOV_EXCL_START 274 return CeedError(ceed, 1, "No suboperators set"); 275 // LCOV_EXCL_STOP 276 } else { 277 if (op->nfields == 0) 278 // LCOV_EXCL_START 279 return CeedError(ceed, 1, "No operator fields set"); 280 // LCOV_EXCL_STOP 281 if (op->nfields < qf->numinputfields + qf->numoutputfields) 282 // LCOV_EXCL_START 283 return CeedError(ceed, 1, "Not all operator fields set"); 284 // LCOV_EXCL_STOP 285 if (op->numelements == 0) 286 // LCOV_EXCL_START 287 return CeedError(ceed, 1,"At least one restriction required"); 288 // LCOV_EXCL_STOP 289 if (op->numqpoints == 0) 290 // LCOV_EXCL_START 291 return CeedError(ceed, 1,"At least one non-collocated basis required"); 292 // LCOV_EXCL_STOP 293 } 294 ierr = op->Apply(op, in, out, request); CeedChk(ierr); 295 return 0; 296 } 297 298 /** 299 @brief Get the Ceed associated with a CeedOperator 300 301 @param op CeedOperator 302 @param[out] ceed Variable to store Ceed 303 304 @return An error code: 0 - success, otherwise - failure 305 306 @ref Advanced 307 **/ 308 309 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) { 310 *ceed = op->ceed; 311 return 0; 312 } 313 314 /** 315 @brief Get the number of elements associated with a CeedOperator 316 317 @param op CeedOperator 318 @param[out] numelem Variable to store number of elements 319 320 @return An error code: 0 - success, otherwise - failure 321 322 @ref Advanced 323 **/ 324 325 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) { 326 if (op->composite) 327 // LCOV_EXCL_START 328 return CeedError(op->ceed, 1, "Not defined for composite operator"); 329 // LCOV_EXCL_STOP 330 331 *numelem = op->numelements; 332 return 0; 333 } 334 335 /** 336 @brief Get the number of quadrature points associated with a CeedOperator 337 338 @param op CeedOperator 339 @param[out] numqpts Variable to store vector number of quadrature points 340 341 @return An error code: 0 - success, otherwise - failure 342 343 @ref Advanced 344 **/ 345 346 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) { 347 if (op->composite) 348 // LCOV_EXCL_START 349 return CeedError(op->ceed, 1, "Not defined for composite operator"); 350 // LCOV_EXCL_STOP 351 352 *numqpts = op->numqpoints; 353 return 0; 354 } 355 356 /** 357 @brief Get the number of arguments associated with a CeedOperator 358 359 @param op CeedOperator 360 @param[out] numargs Variable to store vector number of arguments 361 362 @return An error code: 0 - success, otherwise - failure 363 364 @ref Advanced 365 **/ 366 367 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) { 368 if (op->composite) 369 // LCOV_EXCL_START 370 return CeedError(op->ceed, 1, "Not defined for composite operators"); 371 // LCOV_EXCL_STOP 372 373 *numargs = op->nfields; 374 return 0; 375 } 376 377 /** 378 @brief Get the setup status of a CeedOperator 379 380 @param op CeedOperator 381 @param[out] setupdone Variable to store setup status 382 383 @return An error code: 0 - success, otherwise - failure 384 385 @ref Advanced 386 **/ 387 388 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) { 389 *setupdone = op->setupdone; 390 return 0; 391 } 392 393 /** 394 @brief Get the QFunction associated with a CeedOperator 395 396 @param op CeedOperator 397 @param[out] qf Variable to store QFunction 398 399 @return An error code: 0 - success, otherwise - failure 400 401 @ref Advanced 402 **/ 403 404 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) { 405 if (op->composite) 406 // LCOV_EXCL_START 407 return CeedError(op->ceed, 1, "Not defined for composite operator"); 408 // LCOV_EXCL_STOP 409 410 *qf = op->qf; 411 return 0; 412 } 413 414 /** 415 @brief Get the number of suboperators associated with a CeedOperator 416 417 @param op CeedOperator 418 @param[out] numsub Variable to store number of suboperators 419 420 @return An error code: 0 - success, otherwise - failure 421 422 @ref Advanced 423 **/ 424 425 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) { 426 if (!op->composite) 427 // LCOV_EXCL_START 428 return CeedError(op->ceed, 1, "Not a composite operator"); 429 // LCOV_EXCL_STOP 430 431 *numsub = op->numsub; 432 return 0; 433 } 434 435 /** 436 @brief Get the list of suboperators associated with a CeedOperator 437 438 @param op CeedOperator 439 @param[out] suboperators Variable to store list of suboperators 440 441 @return An error code: 0 - success, otherwise - failure 442 443 @ref Advanced 444 **/ 445 446 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) { 447 if (!op->composite) 448 // LCOV_EXCL_START 449 return CeedError(op->ceed, 1, "Not a composite operator"); 450 // LCOV_EXCL_STOP 451 452 *suboperators = op->suboperators; 453 return 0; 454 } 455 456 /** 457 @brief Set the backend data of a CeedOperator 458 459 @param[out] op CeedOperator 460 @param data Data to set 461 462 @return An error code: 0 - success, otherwise - failure 463 464 @ref Advanced 465 **/ 466 467 int CeedOperatorSetData(CeedOperator op, void* *data) { 468 op->data = *data; 469 return 0; 470 } 471 472 /** 473 @brief Get the backend data of a CeedOperator 474 475 @param op CeedOperator 476 @param[out] data Variable to store data 477 478 @return An error code: 0 - success, otherwise - failure 479 480 @ref Advanced 481 **/ 482 483 int CeedOperatorGetData(CeedOperator op, void* *data) { 484 *data = op->data; 485 return 0; 486 } 487 488 /** 489 @brief Set the setup flag of a CeedOperator to True 490 491 @param op CeedOperator 492 493 @return An error code: 0 - success, otherwise - failure 494 495 @ref Advanced 496 **/ 497 498 int CeedOperatorSetSetupDone(CeedOperator op) { 499 op->setupdone = 1; 500 return 0; 501 } 502 503 /** 504 @brief Get the CeedOperatorFields of a CeedOperator 505 506 @param op CeedOperator 507 @param[out] inputfields Variable to store inputfields 508 @param[out] outputfields Variable to store outputfields 509 510 @return An error code: 0 - success, otherwise - failure 511 512 @ref Advanced 513 **/ 514 515 int CeedOperatorGetFields(CeedOperator op, 516 CeedOperatorField* *inputfields, 517 CeedOperatorField* *outputfields) { 518 if (op->composite) 519 // LCOV_EXCL_START 520 return CeedError(op->ceed, 1, "Not defined for composite operator"); 521 // LCOV_EXCL_STOP 522 523 if (inputfields) *inputfields = op->inputfields; 524 if (outputfields) *outputfields = op->outputfields; 525 return 0; 526 } 527 528 /** 529 @brief Get the L vector CeedTransposeMode of a CeedOperatorField 530 531 @param opfield CeedOperatorField 532 @param[out] lmode Variable to store CeedTransposeMode 533 534 @return An error code: 0 - success, otherwise - failure 535 536 @ref Advanced 537 **/ 538 539 int CeedOperatorFieldGetLMode(CeedOperatorField opfield, 540 CeedTransposeMode *lmode) { 541 *lmode = opfield->lmode; 542 return 0; 543 }/** 544 @brief Get the CeedElemRestriction of a CeedOperatorField 545 546 @param opfield CeedOperatorField 547 @param[out] rstr Variable to store CeedElemRestriction 548 549 @return An error code: 0 - success, otherwise - failure 550 551 @ref Advanced 552 **/ 553 554 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield, 555 CeedElemRestriction *rstr) { 556 *rstr = opfield->Erestrict; 557 return 0; 558 } 559 560 /** 561 @brief Get the CeedBasis of a CeedOperatorField 562 563 @param opfield CeedOperatorField 564 @param[out] basis Variable to store CeedBasis 565 566 @return An error code: 0 - success, otherwise - failure 567 568 @ref Advanced 569 **/ 570 571 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, 572 CeedBasis *basis) { 573 *basis = opfield->basis; 574 return 0; 575 } 576 577 /** 578 @brief Get the CeedVector of a CeedOperatorField 579 580 @param opfield CeedOperatorField 581 @param[out] vec Variable to store CeedVector 582 583 @return An error code: 0 - success, otherwise - failure 584 585 @ref Advanced 586 **/ 587 588 int CeedOperatorFieldGetVector(CeedOperatorField opfield, 589 CeedVector *vec) { 590 *vec = opfield->vec; 591 return 0; 592 } 593 594 /** 595 @brief Destroy a CeedOperator 596 597 @param op CeedOperator to destroy 598 599 @return An error code: 0 - success, otherwise - failure 600 601 @ref Basic 602 **/ 603 int CeedOperatorDestroy(CeedOperator *op) { 604 int ierr; 605 606 if (!*op || --(*op)->refcount > 0) return 0; 607 if ((*op)->Destroy) { 608 ierr = (*op)->Destroy(*op); CeedChk(ierr); 609 } 610 ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr); 611 // Free fields 612 for (int i=0; i<(*op)->nfields; i++) { 613 if ((*op)->inputfields[i]) { 614 ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr); 615 } 616 } 617 for (int i=0; i<(*op)->nfields; i++) { 618 if ((*op)->outputfields[i]) { 619 ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr); 620 } 621 } 622 // Destroy suboperators 623 for (int i=0; i<(*op)->numsub; i++) { 624 if ((*op)->suboperators[i]) { 625 ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr); 626 } 627 } 628 ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr); 629 ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr); 630 ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr); 631 632 ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr); 633 ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr); 634 ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr); 635 ierr = CeedFree(op); CeedChk(ierr); 636 return 0; 637 } 638 639 /// @} 640