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 20 /// @file 21 /// Implementation of public CeedElemRestriction interfaces 22 /// 23 /// @addtogroup CeedElemRestriction 24 /// @{ 25 26 /** 27 @brief Create a CeedElemRestriction 28 29 @param ceed A Ceed object where the CeedElemRestriction will be created 30 @param imode Ordering of the ncomp components, i.e. it specifies 31 the ordering of the components of the L-vector used 32 by this CeedElemRestriction. CEED_NONINTERLACED indicates 33 the component is the outermost index and CEED_INTERLACED 34 indicates the component is the innermost index in 35 ordering of the L-vector. 36 @param nelem Number of elements described in the @a indices array 37 @param elemsize Size (number of "nodes") per element 38 @param nnodes The number of nodes in the L-vector. The input CeedVector 39 to which the restriction will be applied is of size 40 @a nnodes * @a ncomp. This size may include data 41 used by other CeedElemRestriction objects describing 42 different types of elements. 43 @param ncomp Number of field components per interpolation node 44 (1 for scalar fields) 45 @param mtype Memory type of the @a indices array, see CeedMemType 46 @param cmode Copy mode for the @a indices array, see CeedCopyMode 47 @param indices Array of shape [@a nelem, @a elemsize]. Row i holds the 48 ordered list of the indices (into the input CeedVector) 49 for the unknowns corresponding to element i, where 50 0 <= i < @a nelem. All indices must be in the range 51 [0, @a nnodes - 1]. 52 @param[out] rstr Address of the variable where the newly created 53 CeedElemRestriction will be stored 54 55 @return An error code: 0 - success, otherwise - failure 56 57 @ref Basic 58 **/ 59 int CeedElemRestrictionCreate(Ceed ceed, CeedInterlaceMode imode, 60 CeedInt nelem, 61 CeedInt elemsize, CeedInt nnodes, CeedInt ncomp, 62 CeedMemType mtype, CeedCopyMode cmode, 63 const CeedInt *indices, 64 CeedElemRestriction *rstr) { 65 int ierr; 66 67 if (!ceed->ElemRestrictionCreate) { 68 Ceed delegate; 69 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 70 CeedChk(ierr); 71 72 if (!delegate) 73 // LCOV_EXCL_START 74 return CeedError(ceed, 1, "Backend does not support ElemRestrictionCreate"); 75 // LCOV_EXCL_STOP 76 77 ierr = CeedElemRestrictionCreate(delegate, imode, nelem, elemsize, 78 nnodes, ncomp, mtype, cmode, 79 indices, rstr); CeedChk(ierr); 80 return 0; 81 } 82 83 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 84 (*rstr)->ceed = ceed; 85 ceed->refcount++; 86 (*rstr)->refcount = 1; 87 (*rstr)->imode = imode; 88 (*rstr)->nelem = nelem; 89 (*rstr)->elemsize = elemsize; 90 (*rstr)->nnodes = nnodes; 91 (*rstr)->ncomp = ncomp; 92 (*rstr)->nblk = nelem; 93 (*rstr)->blksize = 1; 94 ierr = ceed->ElemRestrictionCreate(mtype, cmode, indices, *rstr); CeedChk(ierr); 95 return 0; 96 } 97 98 /** 99 @brief Create an identity CeedElemRestriction 100 101 @param ceed A Ceed object where the CeedElemRestriction will be created 102 @param imode Ordering of the ncomp components, i.e. it specifies 103 the ordering of the components of the L-vector used 104 by this CeedElemRestriction. CEED_NONINTERLACED indicates 105 the component is the outermost index and CEED_INTERLACED 106 indicates the component is the innermost index in 107 ordering of the L-vector. 108 @param nelem Number of elements described in the @a indices array 109 @param elemsize Size (number of "nodes") per element 110 @param nnodes The number of nodes in the L-vector. The input CeedVector 111 to which the restriction will be applied is of size 112 @a nnodes * @a ncomp. This size may include data 113 used by other CeedElemRestriction objects describing 114 different types of elements. 115 @param ncomp Number of field components per interpolation node 116 (1 for scalar fields) 117 @param rstr Address of the variable where the newly created 118 CeedElemRestriction will be stored 119 120 @return An error code: 0 - success, otherwise - failure 121 122 @ref Basic 123 **/ 124 int CeedElemRestrictionCreateIdentity(Ceed ceed, CeedInterlaceMode imode, 125 CeedInt nelem, CeedInt elemsize, 126 CeedInt nnodes, CeedInt ncomp, 127 CeedElemRestriction *rstr) { 128 int ierr; 129 130 if (!ceed->ElemRestrictionCreate) { 131 Ceed delegate; 132 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 133 CeedChk(ierr); 134 135 if (!delegate) 136 // LCOV_EXCL_START 137 return CeedError(ceed, 1, "Backend does not support ElemRestrictionCreate"); 138 // LCOV_EXCL_STOP 139 140 ierr = CeedElemRestrictionCreateIdentity(delegate, imode, nelem, elemsize, 141 nnodes, ncomp, rstr); CeedChk(ierr); 142 return 0; 143 } 144 145 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 146 (*rstr)->ceed = ceed; 147 ceed->refcount++; 148 (*rstr)->refcount = 1; 149 (*rstr)->imode = imode; 150 (*rstr)->nelem = nelem; 151 (*rstr)->elemsize = elemsize; 152 (*rstr)->nnodes = nnodes; 153 (*rstr)->ncomp = ncomp; 154 (*rstr)->nblk = nelem; 155 (*rstr)->blksize = 1; 156 ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, 157 *rstr); 158 CeedChk(ierr); 159 return 0; 160 } 161 162 /** 163 @brief Permute and pad indices for a blocked restriction 164 165 @param indices Array of shape [@a nelem, @a elemsize]. Row i holds the 166 ordered list of the indices (into the input CeedVector) 167 for the unknowns corresponding to element i, where 168 0 <= i < @a nelem. All indices must be in the range 169 [0, @a nnodes). 170 @param blkindices Array of permuted and padded indices of 171 shape [@a nblk, @a elemsize, @a blksize]. 172 @param nblk Number of blocks 173 @param nelem Number of elements 174 @param blksize Number of elements in a block 175 @param elemsize Size of each element 176 177 @return An error code: 0 - success, otherwise - failure 178 179 @ref Utility 180 **/ 181 int CeedPermutePadIndices(const CeedInt *indices, CeedInt *blkindices, 182 CeedInt nblk, CeedInt nelem, CeedInt blksize, 183 CeedInt elemsize) { 184 for (CeedInt e = 0; e < nblk*blksize; e+=blksize) 185 for (int j = 0; j < blksize; j++) 186 for (int k = 0; k < elemsize; k++) 187 blkindices[e*elemsize + k*blksize + j] 188 = indices[CeedIntMin(e+j,nelem-1)*elemsize + k]; 189 return 0; 190 } 191 192 /** 193 @brief Create a blocked CeedElemRestriction, typically only called by backends 194 195 @param ceed A Ceed object where the CeedElemRestriction will be created. 196 @param imode Ordering of the ncomp components, i.e. it specifies 197 the ordering of the components of the L-vector used 198 by this CeedElemRestriction. CEED_NONINTERLACED indicates 199 the component is the outermost index and CEED_INTERLACED 200 indicates the component is the innermost index in 201 ordering of the L-vector. 202 @param nelem Number of elements described in the @a indices array. 203 @param elemsize Size (number of unknowns) per element 204 @param blksize Number of elements in a block 205 @param nnodes The number of nodes in the L-vector. The input CeedVector 206 to which the restriction will be applied is of size 207 @a nnodes * @a ncomp. This size may include data 208 used by other CeedElemRestriction objects describing 209 different types of elements. 210 @param ncomp Number of field components per interpolation node 211 (1 for scalar fields) 212 @param mtype Memory type of the @a indices array, see CeedMemType 213 @param cmode Copy mode for the @a indices array, see CeedCopyMode 214 @param indices Array of shape [@a nelem, @a elemsize]. Row i holds the 215 ordered list of the indices (into the input CeedVector) 216 for the unknowns corresponding to element i, where 217 0 <= i < @a nelem. All indices must be in the range 218 [0, @a nnodes). The backend will permute and pad this 219 array to the desired ordering for the blocksize, which is 220 typically given by the backend. The default reordering is 221 to interlace elements. 222 @param rstr Address of the variable where the newly created 223 CeedElemRestriction will be stored 224 225 @return An error code: 0 - success, otherwise - failure 226 227 @ref Advanced 228 **/ 229 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInterlaceMode imode, 230 CeedInt nelem, CeedInt elemsize, 231 CeedInt blksize, CeedInt nnodes, 232 CeedInt ncomp, CeedMemType mtype, 233 CeedCopyMode cmode, const CeedInt *indices, 234 CeedElemRestriction *rstr) { 235 int ierr; 236 CeedInt *blkindices; 237 CeedInt nblk = (nelem / blksize) + !!(nelem % blksize); 238 239 if (!ceed->ElemRestrictionCreateBlocked) { 240 Ceed delegate; 241 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 242 CeedChk(ierr); 243 244 if (!delegate) 245 // LCOV_EXCL_START 246 return CeedError(ceed, 1, "Backend does not support " 247 "ElemRestrictionCreateBlocked"); 248 // LCOV_EXCL_STOP 249 250 ierr = CeedElemRestrictionCreateBlocked(delegate, imode, nelem, elemsize, 251 blksize, nnodes, ncomp, mtype, cmode, 252 indices, rstr); CeedChk(ierr); 253 return 0; 254 } 255 256 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 257 258 if (indices) { 259 ierr = CeedCalloc(nblk*blksize*elemsize, &blkindices); CeedChk(ierr); 260 ierr = CeedPermutePadIndices(indices, blkindices, nblk, nelem, blksize, 261 elemsize); 262 CeedChk(ierr); 263 } else { 264 blkindices = NULL; 265 } 266 267 (*rstr)->ceed = ceed; 268 ceed->refcount++; 269 (*rstr)->refcount = 1; 270 (*rstr)->imode = imode; 271 (*rstr)->nelem = nelem; 272 (*rstr)->elemsize = elemsize; 273 (*rstr)->nnodes = nnodes; 274 (*rstr)->ncomp = ncomp; 275 (*rstr)->nblk = nblk; 276 (*rstr)->blksize = blksize; 277 ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, 278 (const CeedInt *) blkindices, *rstr); CeedChk(ierr); 279 280 if (cmode == CEED_OWN_POINTER) { 281 ierr = CeedFree(&indices); CeedChk(ierr); 282 } 283 284 return 0; 285 } 286 287 /** 288 @brief Create CeedVectors associated with a CeedElemRestriction 289 290 @param rstr CeedElemRestriction 291 @param lvec The address of the L-vector to be created, or NULL 292 @param evec The address of the E-vector to be created, or NULL 293 294 @return An error code: 0 - success, otherwise - failure 295 296 @ref Advanced 297 **/ 298 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *lvec, 299 CeedVector *evec) { 300 int ierr; 301 CeedInt n, m; 302 m = rstr->nnodes * rstr->ncomp; 303 n = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp; 304 if (lvec) { 305 ierr = CeedVectorCreate(rstr->ceed, m, lvec); CeedChk(ierr); 306 } 307 if (evec) { 308 ierr = CeedVectorCreate(rstr->ceed, n, evec); CeedChk(ierr); 309 } 310 return 0; 311 } 312 313 /** 314 @brief Restrict an L-vector to an E-vector or apply its transpose 315 316 @param rstr CeedElemRestriction 317 @param tmode Apply restriction or transpose 318 @param u Input vector (of shape [@a nnodes, @a ncomp] when 319 tmode=CEED_NOTRANSPOSE, imode=CEED_INTERLACED) 320 @param ru Output vector (of shape [@a nelem * @a elemsize] when 321 tmode=CEED_NOTRANSPOSE). Ordering of the e-vector is decided 322 by the backend. 323 @param request Request or CEED_REQUEST_IMMEDIATE 324 325 @return An error code: 0 - success, otherwise - failure 326 327 @ref Advanced 328 **/ 329 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode tmode, 330 CeedVector u, CeedVector ru, 331 CeedRequest *request) { 332 CeedInt m,n; 333 int ierr; 334 335 if (tmode == CEED_NOTRANSPOSE) { 336 m = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp; 337 n = rstr->nnodes * rstr->ncomp; 338 } else { 339 m = rstr->nnodes * rstr->ncomp; 340 n = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp; 341 } 342 if (n != u->length) 343 // LCOV_EXCL_START 344 return CeedError(rstr->ceed, 2, "Input vector size %d not compatible with " 345 "element restriction (%d, %d)", u->length, m, n); 346 // LCOV_EXCL_STOP 347 if (m != ru->length) 348 // LCOV_EXCL_START 349 return CeedError(rstr->ceed, 2, "Output vector size %d not compatible with " 350 "element restriction (%d, %d)", ru->length, m, n); 351 // LCOV_EXCL_STOP 352 ierr = rstr->Apply(rstr, tmode, u, ru, request); CeedChk(ierr); 353 354 return 0; 355 } 356 357 /** 358 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 359 360 @param rstr CeedElemRestriction 361 @param block Block number to restrict to/from, i.e. block=0 will handle 362 elements [0 : blksize] and block=3 will handle elements 363 [3*blksize : 4*blksize] 364 @param tmode Apply restriction or transpose 365 @param u Input vector (of shape [@a nnodes, @a ncomp] when 366 tmode=CEED_NOTRANSPOSE, imode=CEED_INTERLACED) 367 @param ru Output vector (of shape [@a blksize * @a elemsize] when 368 tmode=CEED_NOTRANSPOSE). Ordering of the e-vector is decided 369 by the backend. 370 @param request Request or CEED_REQUEST_IMMEDIATE 371 372 @return An error code: 0 - success, otherwise - failure 373 374 @ref Advanced 375 **/ 376 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, 377 CeedTransposeMode tmode, CeedVector u, 378 CeedVector ru, CeedRequest *request) { 379 CeedInt m,n; 380 int ierr; 381 382 if (tmode == CEED_NOTRANSPOSE) { 383 m = rstr->blksize * rstr->elemsize * rstr->ncomp; 384 n = rstr->nnodes * rstr->ncomp; 385 } else { 386 m = rstr->nnodes * rstr->ncomp; 387 n = rstr->blksize * rstr->elemsize * rstr->ncomp; 388 } 389 if (n != u->length) 390 // LCOV_EXCL_START 391 return CeedError(rstr->ceed, 2, "Input vector size %d not compatible with " 392 "element restriction (%d, %d)", u->length, m, n); 393 // LCOV_EXCL_STOP 394 if (m != ru->length) 395 // LCOV_EXCL_START 396 return CeedError(rstr->ceed, 2, "Output vector size %d not compatible with " 397 "element restriction (%d, %d)", ru->length, m, n); 398 // LCOV_EXCL_STOP 399 if (rstr->blksize*block > rstr->nelem) 400 // LCOV_EXCL_START 401 return CeedError(rstr->ceed, 2, "Cannot retrieve block %d, element %d > " 402 "total elements %d", block, rstr->blksize*block, 403 rstr->nelem); 404 // LCOV_EXCL_STOP 405 ierr = rstr->ApplyBlock(rstr, block, tmode, u, ru, request); 406 CeedChk(ierr); 407 408 return 0; 409 } 410 411 /** 412 @brief Get the multiplicity of nodes in a CeedElemRestriction 413 414 @param rstr CeedElemRestriction 415 @param[out] mult Vector to store multiplicity (of size nnodes) 416 417 @return An error code: 0 - success, otherwise - failure 418 419 @ref Advanced 420 **/ 421 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, 422 CeedVector mult) { 423 int ierr; 424 CeedVector evec; 425 426 // Create and set evec 427 ierr = CeedElemRestrictionCreateVector(rstr, NULL, &evec); CeedChk(ierr); 428 ierr = CeedVectorSetValue(evec, 1.0); CeedChk(ierr); 429 430 // Apply to get multiplicity 431 ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, evec, mult, 432 CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 433 434 // Cleanup 435 ierr = CeedVectorDestroy(&evec); CeedChk(ierr); 436 437 return 0; 438 } 439 440 /** 441 @brief Get the Ceed associated with a CeedElemRestriction 442 443 @param rstr CeedElemRestriction 444 @param[out] ceed Variable to store Ceed 445 446 @return An error code: 0 - success, otherwise - failure 447 448 @ref Advanced 449 **/ 450 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 451 *ceed = rstr->ceed; 452 return 0; 453 } 454 455 /** 456 @brief Get the L-vector interlaced mode of a CeedElemRestriction 457 458 @param rstr CeedElemRestriction 459 @param[out] imode Variable to store imode 460 461 @return An error code: 0 - success, otherwise - failure 462 463 @ref Advanced 464 **/ 465 int CeedElemRestrictionGetIMode(CeedElemRestriction rstr, 466 CeedInterlaceMode *imode) { 467 *imode = rstr->imode; 468 return 0; 469 } 470 471 /** 472 @brief Get the total number of elements in the range of a CeedElemRestriction 473 474 @param rstr CeedElemRestriction 475 @param[out] numelem Variable to store number of elements 476 477 @return An error code: 0 - success, otherwise - failure 478 479 @ref Advanced 480 **/ 481 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, 482 CeedInt *numelem) { 483 *numelem = rstr->nelem; 484 return 0; 485 } 486 487 /** 488 @brief Get the size of elements in the CeedElemRestriction 489 490 @param rstr CeedElemRestriction 491 @param[out] elemsize Variable to store size of elements 492 493 @return An error code: 0 - success, otherwise - failure 494 495 @ref Advanced 496 **/ 497 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, 498 CeedInt *elemsize) { 499 *elemsize = rstr->elemsize; 500 return 0; 501 } 502 503 /** 504 @brief Get the number of degrees of freedom in the range of a 505 CeedElemRestriction 506 507 @param rstr CeedElemRestriction 508 @param[out] numnodes Variable to store number of nodes 509 510 @return An error code: 0 - success, otherwise - failure 511 512 @ref Advanced 513 **/ 514 int CeedElemRestrictionGetNumNodes(CeedElemRestriction rstr, 515 CeedInt *numnodes) { 516 *numnodes = rstr->nnodes; 517 return 0; 518 } 519 520 /** 521 @brief Get the number of components in the elements of a 522 CeedElemRestriction 523 524 @param rstr CeedElemRestriction 525 @param[out] numcomp Variable to store number of components 526 527 @return An error code: 0 - success, otherwise - failure 528 529 @ref Advanced 530 **/ 531 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, 532 CeedInt *numcomp) { 533 *numcomp = rstr->ncomp; 534 return 0; 535 } 536 537 /** 538 @brief Get the number of blocks in a CeedElemRestriction 539 540 @param rstr CeedElemRestriction 541 @param[out] numblock Variable to store number of blocks 542 543 @return An error code: 0 - success, otherwise - failure 544 545 @ref Advanced 546 **/ 547 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, 548 CeedInt *numblock) { 549 *numblock = rstr->nblk; 550 return 0; 551 } 552 553 /** 554 @brief Get the size of blocks in the CeedElemRestriction 555 556 @param rstr CeedElemRestriction 557 @param[out] blksize Variable to store size of blocks 558 559 @return An error code: 0 - success, otherwise - failure 560 561 @ref Advanced 562 **/ 563 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, 564 CeedInt *blksize) { 565 *blksize = rstr->blksize; 566 return 0; 567 } 568 569 /** 570 @brief Get the backend data of a CeedElemRestriction 571 572 @param rstr CeedElemRestriction 573 @param[out] data Variable to store data 574 575 @return An error code: 0 - success, otherwise - failure 576 577 @ref Advanced 578 **/ 579 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void **data) { 580 *data = rstr->data; 581 return 0; 582 } 583 584 /** 585 @brief Set the backend data of a CeedElemRestriction 586 587 @param[out] rstr CeedElemRestriction 588 @param data Data to set 589 590 @return An error code: 0 - success, otherwise - failure 591 592 @ref Advanced 593 **/ 594 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void **data) { 595 rstr->data = *data; 596 return 0; 597 } 598 599 /** 600 @brief View a CeedElemRestriction 601 602 @param[in] rstr CeedElemRestriction to view 603 @param[in] stream Stream to write; typically stdout/stderr or a file 604 605 @return Error code: 0 - success, otherwise - failure 606 607 @ref Utility 608 **/ 609 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 610 fprintf(stream, "CeedElemRestriction from (%d, %d) to %d elements with %d " 611 "nodes each and L-vector components %s\n", rstr->nnodes, rstr->ncomp, 612 rstr->nelem, rstr->elemsize, CeedInterlaceModes[rstr->imode]); 613 return 0; 614 } 615 616 /** 617 @brief Destroy a CeedElemRestriction 618 619 @param rstr CeedElemRestriction to destroy 620 621 @return An error code: 0 - success, otherwise - failure 622 623 @ref Basic 624 **/ 625 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 626 int ierr; 627 628 if (!*rstr || --(*rstr)->refcount > 0) 629 return 0; 630 if ((*rstr)->Destroy) { 631 ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr); 632 } 633 ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr); 634 ierr = CeedFree(rstr); CeedChk(ierr); 635 return 0; 636 } 637 638 /// @} 639