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