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/ceed.h> 18 #include <ceed/backend.h> 19 #include <ceed-impl.h> 20 #include <stdbool.h> 21 #include <stdio.h> 22 23 /// @file 24 /// Implementation of CeedElemRestriction interfaces 25 26 /// ---------------------------------------------------------------------------- 27 /// CeedElemRestriction Library Internal Functions 28 /// ---------------------------------------------------------------------------- 29 /// @addtogroup CeedElemRestrictionDeveloper 30 /// @{ 31 32 /** 33 @brief Permute and pad offsets for a blocked restriction 34 35 @param offsets Array of shape [@a num_elem, @a elem_size]. Row i holds the 36 ordered list of the offsets (into the input CeedVector) 37 for the unknowns corresponding to element i, where 38 0 <= i < @a num_elem. All offsets must be in the range 39 [0, @a l_size - 1]. 40 @param blk_offsets Array of permuted and padded offsets of 41 shape [@a num_blk, @a elem_size, @a blk_size]. 42 @param num_blk Number of blocks 43 @param num_elem Number of elements 44 @param blk_size Number of elements in a block 45 @param elem_size Size of each element 46 47 @return An error code: 0 - success, otherwise - failure 48 49 @ref Utility 50 **/ 51 int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *blk_offsets, 52 CeedInt num_blk, CeedInt num_elem, CeedInt blk_size, 53 CeedInt elem_size) { 54 for (CeedInt e=0; e<num_blk*blk_size; e+=blk_size) 55 for (int j=0; j<blk_size; j++) 56 for (int k=0; k<elem_size; k++) 57 blk_offsets[e*elem_size + k*blk_size + j] 58 = offsets[CeedIntMin(e+j,num_elem-1)*elem_size + k]; 59 return CEED_ERROR_SUCCESS; 60 } 61 62 /// @} 63 64 /// ---------------------------------------------------------------------------- 65 /// CeedElemRestriction Backend API 66 /// ---------------------------------------------------------------------------- 67 /// @addtogroup CeedElemRestrictionBackend 68 /// @{ 69 70 /** 71 72 @brief Get the strides of a strided CeedElemRestriction 73 74 @param rstr CeedElemRestriction 75 @param[out] strides Variable to store strides array 76 77 @return An error code: 0 - success, otherwise - failure 78 79 @ref Backend 80 **/ 81 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr, 82 CeedInt (*strides)[3]) { 83 if (!rstr->strides) 84 // LCOV_EXCL_START 85 return CeedError(rstr->ceed, CEED_ERROR_MINOR, 86 "ElemRestriction has no stride data"); 87 // LCOV_EXCL_STOP 88 89 for (int i=0; i<3; i++) 90 (*strides)[i] = rstr->strides[i]; 91 return CEED_ERROR_SUCCESS; 92 } 93 94 /** 95 @brief Get read-only access to a CeedElemRestriction offsets array by memtype 96 97 @param rstr CeedElemRestriction to retrieve offsets 98 @param mem_type Memory type on which to access the array. If the backend 99 uses a different memory type, this will perform a copy 100 (possibly cached). 101 @param[out] offsets Array on memory type mem_type 102 103 @return An error code: 0 - success, otherwise - failure 104 105 @ref User 106 **/ 107 int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr, 108 CeedMemType mem_type, 109 const CeedInt **offsets) { 110 int ierr; 111 112 if (!rstr->GetOffsets) 113 // LCOV_EXCL_START 114 return CeedError(rstr->ceed, CEED_ERROR_UNSUPPORTED, 115 "Backend does not support GetOffsets"); 116 // LCOV_EXCL_STOP 117 118 ierr = rstr->GetOffsets(rstr, mem_type, offsets); CeedChk(ierr); 119 rstr->num_readers++; 120 return CEED_ERROR_SUCCESS; 121 } 122 123 /** 124 @brief Restore an offsets array obtained using CeedElemRestrictionGetOffsets() 125 126 @param rstr CeedElemRestriction to restore 127 @param offsets Array of offset data 128 129 @return An error code: 0 - success, otherwise - failure 130 131 @ref User 132 **/ 133 int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr, 134 const CeedInt **offsets) { 135 *offsets = NULL; 136 rstr->num_readers--; 137 return CEED_ERROR_SUCCESS; 138 } 139 140 /** 141 @brief Get the strided status of a CeedElemRestriction 142 143 @param rstr CeedElemRestriction 144 @param[out] is_strided Variable to store strided status, 1 if strided else 0 145 146 @return An error code: 0 - success, otherwise - failure 147 148 @ref Backend 149 **/ 150 int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) { 151 *is_strided = rstr->strides ? true : false; 152 return CEED_ERROR_SUCCESS; 153 } 154 155 /** 156 @brief Get the backend stride status of a CeedElemRestriction 157 158 @param rstr CeedElemRestriction 159 @param[out] has_backend_strides Variable to store stride status 160 161 @return An error code: 0 - success, otherwise - failure 162 163 @ref Backend 164 **/ 165 int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr, 166 bool *has_backend_strides) { 167 if (!rstr->strides) 168 // LCOV_EXCL_START 169 return CeedError(rstr->ceed, CEED_ERROR_MINOR, 170 "ElemRestriction has no stride data"); 171 // LCOV_EXCL_STOP 172 173 *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) && 174 (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) && 175 (rstr->strides[2] == CEED_STRIDES_BACKEND[2])); 176 return CEED_ERROR_SUCCESS; 177 } 178 179 /** 180 181 @brief Get the E-vector layout of a CeedElemRestriction 182 183 @param rstr CeedElemRestriction 184 @param[out] layout Variable to store layout array, 185 stored as [nodes, components, elements]. 186 The data for node i, component j, element k in the 187 E-vector is given by 188 i*layout[0] + j*layout[1] + k*layout[2] 189 190 @return An error code: 0 - success, otherwise - failure 191 192 @ref Backend 193 **/ 194 int CeedElemRestrictionGetELayout(CeedElemRestriction rstr, 195 CeedInt (*layout)[3]) { 196 if (!rstr->layout[0]) 197 // LCOV_EXCL_START 198 return CeedError(rstr->ceed, CEED_ERROR_MINOR, 199 "ElemRestriction has no layout data"); 200 // LCOV_EXCL_STOP 201 202 for (int i=0; i<3; i++) 203 (*layout)[i] = rstr->layout[i]; 204 return CEED_ERROR_SUCCESS; 205 } 206 207 /** 208 209 @brief Set the E-vector layout of a CeedElemRestriction 210 211 @param rstr CeedElemRestriction 212 @param layout Variable to containing layout array, 213 stored as [nodes, components, elements]. 214 The data for node i, component j, element k in the 215 E-vector is given by 216 i*layout[0] + j*layout[1] + k*layout[2] 217 218 @return An error code: 0 - success, otherwise - failure 219 220 @ref Backend 221 **/ 222 int CeedElemRestrictionSetELayout(CeedElemRestriction rstr, 223 CeedInt layout[3]) { 224 for (int i = 0; i<3; i++) 225 rstr->layout[i] = layout[i]; 226 return CEED_ERROR_SUCCESS; 227 } 228 229 /** 230 @brief Get the backend data of a CeedElemRestriction 231 232 @param rstr CeedElemRestriction 233 @param[out] data Variable to store data 234 235 @return An error code: 0 - success, otherwise - failure 236 237 @ref Backend 238 **/ 239 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) { 240 *(void **)data = rstr->data; 241 return CEED_ERROR_SUCCESS; 242 } 243 244 /** 245 @brief Set the backend data of a CeedElemRestriction 246 247 @param[out] rstr CeedElemRestriction 248 @param data Data to set 249 250 @return An error code: 0 - success, otherwise - failure 251 252 @ref Backend 253 **/ 254 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) { 255 rstr->data = data; 256 return CEED_ERROR_SUCCESS; 257 } 258 259 /** 260 @brief Increment the reference counter for a CeedElemRestriction 261 262 @param rstr ElemRestriction to increment the reference counter 263 264 @return An error code: 0 - success, otherwise - failure 265 266 @ref Backend 267 **/ 268 int CeedElemRestrictionReference(CeedElemRestriction rstr) { 269 rstr->ref_count++; 270 return CEED_ERROR_SUCCESS; 271 } 272 273 /// @} 274 275 /// @cond DOXYGEN_SKIP 276 static struct CeedElemRestriction_private ceed_elemrestriction_none; 277 /// @endcond 278 279 /// ---------------------------------------------------------------------------- 280 /// CeedElemRestriction Public API 281 /// ---------------------------------------------------------------------------- 282 /// @addtogroup CeedElemRestrictionUser 283 /// @{ 284 285 /// Indicate that the stride is determined by the backend 286 const CeedInt CEED_STRIDES_BACKEND[3] = {0}; 287 288 /// Indicate that no CeedElemRestriction is provided by the user 289 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = 290 &ceed_elemrestriction_none; 291 292 /** 293 @brief Create a CeedElemRestriction 294 295 @param ceed A Ceed object where the CeedElemRestriction will be created 296 @param num_elem Number of elements described in the @a offsets array 297 @param elem_size Size (number of "nodes") per element 298 @param num_comp Number of field components per interpolation node 299 (1 for scalar fields) 300 @param comp_stride Stride between components for the same L-vector "node". 301 Data for node i, component j, element k can be found in 302 the L-vector at index 303 offsets[i + k*elem_size] + j*comp_stride. 304 @param l_size The size of the L-vector. This vector may be larger than 305 the elements and fields given by this restriction. 306 @param mem_type Memory type of the @a offsets array, see CeedMemType 307 @param copy_mode Copy mode for the @a offsets array, see CeedCopyMode 308 @param offsets Array of shape [@a num_elem, @a elem_size]. Row i holds the 309 ordered list of the offsets (into the input CeedVector) 310 for the unknowns corresponding to element i, where 311 0 <= i < @a num_elem. All offsets must be in the range 312 [0, @a l_size - 1]. 313 @param[out] rstr Address of the variable where the newly created 314 CeedElemRestriction will be stored 315 316 @return An error code: 0 - success, otherwise - failure 317 318 @ref User 319 **/ 320 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, 321 CeedInt num_comp, CeedInt comp_stride, 322 CeedInt l_size, CeedMemType mem_type, 323 CeedCopyMode copy_mode, const CeedInt *offsets, 324 CeedElemRestriction *rstr) { 325 int ierr; 326 327 if (!ceed->ElemRestrictionCreate) { 328 Ceed delegate; 329 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 330 CeedChk(ierr); 331 332 if (!delegate) 333 // LCOV_EXCL_START 334 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 335 "Backend does not support ElemRestrictionCreate"); 336 // LCOV_EXCL_STOP 337 338 ierr = CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, 339 comp_stride, l_size, mem_type, copy_mode, 340 offsets, rstr); CeedChk(ierr); 341 return CEED_ERROR_SUCCESS; 342 } 343 344 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 345 (*rstr)->ceed = ceed; 346 ierr = CeedReference(ceed); CeedChk(ierr); 347 (*rstr)->ref_count = 1; 348 (*rstr)->num_elem = num_elem; 349 (*rstr)->elem_size = elem_size; 350 (*rstr)->num_comp = num_comp; 351 (*rstr)->comp_stride = comp_stride; 352 (*rstr)->l_size = l_size; 353 (*rstr)->num_blk = num_elem; 354 (*rstr)->blk_size = 1; 355 ierr = ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, *rstr); 356 CeedChk(ierr); 357 return CEED_ERROR_SUCCESS; 358 } 359 360 /** 361 @brief Create a CeedElemRestriction with orientation sign 362 363 @param ceed A Ceed object where the CeedElemRestriction will be created 364 @param num_elem Number of elements described in the @a offsets array 365 @param elem_size Size (number of "nodes") per element 366 @param num_comp Number of field components per interpolation node 367 (1 for scalar fields) 368 @param comp_stride Stride between components for the same L-vector "node". 369 Data for node i, component j, element k can be found in 370 the L-vector at index 371 offsets[i + k*elem_size] + j*comp_stride. 372 @param l_size The size of the L-vector. This vector may be larger than 373 the elements and fields given by this restriction. 374 @param mem_type Memory type of the @a offsets array, see CeedMemType 375 @param copy_mode Copy mode for the @a offsets array, see CeedCopyMode 376 @param offsets Array of shape [@a num_elem, @a elem_size]. Row i holds the 377 ordered list of the offsets (into the input CeedVector) 378 for the unknowns corresponding to element i, where 379 0 <= i < @a num_elem. All offsets must be in the range 380 [0, @a l_size - 1]. 381 @param orient Array of shape [@a num_elem, @a elem_size] with bool false 382 for positively oriented and true to flip the orientation. 383 @param scale An scalar value that scales the dofs in assembly. 384 @param[out] rstr Address of the variable where the newly created 385 CeedElemRestriction will be stored 386 387 @return An error code: 0 - success, otherwise - failure 388 389 @ref User 390 **/ 391 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, 392 CeedInt elem_size, CeedInt num_comp, 393 CeedInt comp_stride, CeedInt l_size, 394 CeedMemType mem_type, CeedCopyMode copy_mode, 395 const CeedInt *offsets, const bool *orient, 396 CeedElemRestriction *rstr) { 397 int ierr; 398 399 if (!ceed->ElemRestrictionCreate) { 400 Ceed delegate; 401 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 402 CeedChk(ierr); 403 404 if (!delegate) 405 // LCOV_EXCL_START 406 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 407 "Backend does not support ElemRestrictionCreateOriented"); 408 // LCOV_EXCL_STOP 409 410 ierr = CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, 411 num_comp, 412 comp_stride, l_size, mem_type, copy_mode, 413 offsets, orient, rstr); CeedChk(ierr); 414 return CEED_ERROR_SUCCESS; 415 } 416 417 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 418 (*rstr)->ceed = ceed; 419 ierr = CeedReference(ceed); CeedChk(ierr); 420 (*rstr)->ref_count = 1; 421 (*rstr)->num_elem = num_elem; 422 (*rstr)->elem_size = elem_size; 423 (*rstr)->num_comp = num_comp; 424 (*rstr)->comp_stride = comp_stride; 425 (*rstr)->l_size = l_size; 426 (*rstr)->num_blk = num_elem; 427 (*rstr)->blk_size = 1; 428 ierr = ceed->ElemRestrictionCreateOriented(mem_type, copy_mode, offsets, orient, 429 *rstr); 430 CeedChk(ierr); 431 return CEED_ERROR_SUCCESS; 432 } 433 434 /** 435 @brief Create a strided CeedElemRestriction 436 437 @param ceed A Ceed object where the CeedElemRestriction will be created 438 @param num_elem Number of elements described by the restriction 439 @param elem_size Size (number of "nodes") per element 440 @param num_comp Number of field components per interpolation "node" 441 (1 for scalar fields) 442 @param l_size The size of the L-vector. This vector may be larger than 443 the elements and fields given by this restriction. 444 @param strides Array for strides between [nodes, components, elements]. 445 Data for node i, component j, element k can be found in 446 the L-vector at index 447 i*strides[0] + j*strides[1] + k*strides[2]. 448 @a CEED_STRIDES_BACKEND may be used with vectors created 449 by a Ceed backend. 450 @param rstr Address of the variable where the newly created 451 CeedElemRestriction will be stored 452 453 @return An error code: 0 - success, otherwise - failure 454 455 @ref User 456 **/ 457 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, 458 CeedInt elem_size, 459 CeedInt num_comp, CeedInt l_size, 460 const CeedInt strides[3], 461 CeedElemRestriction *rstr) { 462 int ierr; 463 464 if (!ceed->ElemRestrictionCreate) { 465 Ceed delegate; 466 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 467 CeedChk(ierr); 468 469 if (!delegate) 470 // LCOV_EXCL_START 471 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 472 "Backend does not support ElemRestrictionCreate"); 473 // LCOV_EXCL_STOP 474 475 ierr = CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, 476 l_size, strides, rstr); 477 CeedChk(ierr); 478 return CEED_ERROR_SUCCESS; 479 } 480 481 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 482 (*rstr)->ceed = ceed; 483 ierr = CeedReference(ceed); CeedChk(ierr); 484 (*rstr)->ref_count = 1; 485 (*rstr)->num_elem = num_elem; 486 (*rstr)->elem_size = elem_size; 487 (*rstr)->num_comp = num_comp; 488 (*rstr)->l_size = l_size; 489 (*rstr)->num_blk = num_elem; 490 (*rstr)->blk_size = 1; 491 ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr); 492 for (int i=0; i<3; i++) 493 (*rstr)->strides[i] = strides[i]; 494 ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, 495 *rstr); 496 CeedChk(ierr); 497 return CEED_ERROR_SUCCESS; 498 } 499 500 /** 501 @brief Create a blocked CeedElemRestriction, typically only called by backends 502 503 @param ceed A Ceed object where the CeedElemRestriction will be created. 504 @param num_elem Number of elements described in the @a offsets array. 505 @param elem_size Size (number of unknowns) per element 506 @param blk_size Number of elements in a block 507 @param num_comp Number of field components per interpolation node 508 (1 for scalar fields) 509 @param comp_stride Stride between components for the same L-vector "node". 510 Data for node i, component j, element k can be found in 511 the L-vector at index 512 offsets[i + k*elem_size] + j*comp_stride. 513 @param l_size The size of the L-vector. This vector may be larger than 514 the elements and fields given by this restriction. 515 @param mem_type Memory type of the @a offsets array, see CeedMemType 516 @param copy_mode Copy mode for the @a offsets array, see CeedCopyMode 517 @param offsets Array of shape [@a num_elem, @a elem_size]. Row i holds the 518 ordered list of the offsets (into the input CeedVector) 519 for the unknowns corresponding to element i, where 520 0 <= i < @a num_elem. All offsets must be in the range 521 [0, @a l_size - 1]. The backend will permute and pad this 522 array to the desired ordering for the blocksize, which is 523 typically given by the backend. The default reordering is 524 to interlace elements. 525 @param rstr Address of the variable where the newly created 526 CeedElemRestriction will be stored 527 528 @return An error code: 0 - success, otherwise - failure 529 530 @ref Backend 531 **/ 532 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, 533 CeedInt elem_size, 534 CeedInt blk_size, CeedInt num_comp, 535 CeedInt comp_stride, CeedInt l_size, 536 CeedMemType mem_type, CeedCopyMode copy_mode, 537 const CeedInt *offsets, 538 CeedElemRestriction *rstr) { 539 int ierr; 540 CeedInt *blk_offsets; 541 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 542 543 if (!ceed->ElemRestrictionCreateBlocked) { 544 Ceed delegate; 545 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 546 CeedChk(ierr); 547 548 if (!delegate) 549 // LCOV_EXCL_START 550 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support " 551 "ElemRestrictionCreateBlocked"); 552 // LCOV_EXCL_STOP 553 554 ierr = CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size, 555 num_comp, comp_stride, l_size, mem_type, 556 copy_mode, offsets, rstr); 557 CeedChk(ierr); 558 return CEED_ERROR_SUCCESS; 559 } 560 561 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 562 563 ierr = CeedCalloc(num_blk*blk_size*elem_size, &blk_offsets); CeedChk(ierr); 564 ierr = CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, 565 elem_size); CeedChk(ierr); 566 567 (*rstr)->ceed = ceed; 568 ierr = CeedReference(ceed); CeedChk(ierr); 569 (*rstr)->ref_count = 1; 570 (*rstr)->num_elem = num_elem; 571 (*rstr)->elem_size = elem_size; 572 (*rstr)->num_comp = num_comp; 573 (*rstr)->comp_stride = comp_stride; 574 (*rstr)->l_size = l_size; 575 (*rstr)->num_blk = num_blk; 576 (*rstr)->blk_size = blk_size; 577 ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, 578 (const CeedInt *) blk_offsets, *rstr); CeedChk(ierr); 579 if (copy_mode == CEED_OWN_POINTER) { 580 ierr = CeedFree(&offsets); CeedChk(ierr); 581 } 582 return CEED_ERROR_SUCCESS; 583 } 584 585 /** 586 @brief Create a blocked strided CeedElemRestriction 587 588 @param ceed A Ceed object where the CeedElemRestriction will be created 589 @param num_elem Number of elements described by the restriction 590 @param elem_size Size (number of "nodes") per element 591 @param blk_size Number of elements in a block 592 @param num_comp Number of field components per interpolation node 593 (1 for scalar fields) 594 @param l_size The size of the L-vector. This vector may be larger than 595 the elements and fields given by this restriction. 596 @param strides Array for strides between [nodes, components, elements]. 597 Data for node i, component j, element k can be found in 598 the L-vector at index 599 i*strides[0] + j*strides[1] + k*strides[2]. 600 @a CEED_STRIDES_BACKEND may be used with vectors created 601 by a Ceed backend. 602 @param rstr Address of the variable where the newly created 603 CeedElemRestriction will be stored 604 605 @return An error code: 0 - success, otherwise - failure 606 607 @ref User 608 **/ 609 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, 610 CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt l_size, 611 const CeedInt strides[3], CeedElemRestriction *rstr) { 612 int ierr; 613 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 614 615 if (!ceed->ElemRestrictionCreateBlocked) { 616 Ceed delegate; 617 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 618 CeedChk(ierr); 619 620 if (!delegate) 621 // LCOV_EXCL_START 622 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support " 623 "ElemRestrictionCreateBlocked"); 624 // LCOV_EXCL_STOP 625 626 ierr = CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, 627 blk_size, num_comp, l_size, strides, rstr); CeedChk(ierr); 628 return CEED_ERROR_SUCCESS; 629 } 630 631 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 632 633 (*rstr)->ceed = ceed; 634 ierr = CeedReference(ceed); CeedChk(ierr); 635 (*rstr)->ref_count = 1; 636 (*rstr)->num_elem = num_elem; 637 (*rstr)->elem_size = elem_size; 638 (*rstr)->num_comp = num_comp; 639 (*rstr)->l_size = l_size; 640 (*rstr)->num_blk = num_blk; 641 (*rstr)->blk_size = blk_size; 642 ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr); 643 for (int i=0; i<3; i++) 644 (*rstr)->strides[i] = strides[i]; 645 ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, 646 NULL, *rstr); CeedChk(ierr); 647 return CEED_ERROR_SUCCESS; 648 } 649 650 /** 651 @brief Copy the pointer to a CeedElemRestriction. Both pointers should 652 be destroyed with `CeedElemRestrictionDestroy()`; 653 Note: If `*rstr_copy` is non-NULL, then it is assumed that 654 `*rstr_copy` is a pointer to a CeedElemRestriction. This 655 CeedElemRestriction will be destroyed if `*rstr_copy` is the 656 only reference to this CeedElemRestriction. 657 658 @param rstr CeedElemRestriction to copy reference to 659 @param[out] rstr_copy Variable to store copied reference 660 661 @return An error code: 0 - success, otherwise - failure 662 663 @ref User 664 **/ 665 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, 666 CeedElemRestriction *rstr_copy) { 667 int ierr; 668 669 ierr = CeedElemRestrictionReference(rstr); CeedChk(ierr); 670 ierr = CeedElemRestrictionDestroy(rstr_copy); CeedChk(ierr); 671 *rstr_copy = rstr; 672 return CEED_ERROR_SUCCESS; 673 } 674 675 /** 676 @brief Create CeedVectors associated with a CeedElemRestriction 677 678 @param rstr CeedElemRestriction 679 @param l_vec The address of the L-vector to be created, or NULL 680 @param e_vec The address of the E-vector to be created, or NULL 681 682 @return An error code: 0 - success, otherwise - failure 683 684 @ref User 685 **/ 686 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, 687 CeedVector *e_vec) { 688 int ierr; 689 CeedInt e_size, l_size; 690 l_size = rstr->l_size; 691 e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 692 if (l_vec) { 693 ierr = CeedVectorCreate(rstr->ceed, l_size, l_vec); CeedChk(ierr); 694 } 695 if (e_vec) { 696 ierr = CeedVectorCreate(rstr->ceed, e_size, e_vec); CeedChk(ierr); 697 } 698 return CEED_ERROR_SUCCESS; 699 } 700 701 /** 702 @brief Restrict an L-vector to an E-vector or apply its transpose 703 704 @param rstr CeedElemRestriction 705 @param t_mode Apply restriction or transpose 706 @param u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 707 @param ru Output vector (of shape [@a num_elem * @a elem_size] when 708 t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided 709 by the backend. 710 @param request Request or @ref CEED_REQUEST_IMMEDIATE 711 712 @return An error code: 0 - success, otherwise - failure 713 714 @ref User 715 **/ 716 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, 717 CeedVector u, CeedVector ru, 718 CeedRequest *request) { 719 CeedInt m, n; 720 int ierr; 721 722 if (t_mode == CEED_NOTRANSPOSE) { 723 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 724 n = rstr->l_size; 725 } else { 726 m = rstr->l_size; 727 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 728 } 729 if (n != u->length) 730 // LCOV_EXCL_START 731 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 732 "Input vector size %d not compatible with " 733 "element restriction (%d, %d)", u->length, m, n); 734 // LCOV_EXCL_STOP 735 if (m != ru->length) 736 // LCOV_EXCL_START 737 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 738 "Output vector size %d not compatible with " 739 "element restriction (%d, %d)", ru->length, m, n); 740 // LCOV_EXCL_STOP 741 ierr = rstr->Apply(rstr, t_mode, u, ru, request); CeedChk(ierr); 742 return CEED_ERROR_SUCCESS; 743 } 744 745 /** 746 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 747 748 @param rstr CeedElemRestriction 749 @param block Block number to restrict to/from, i.e. block=0 will handle 750 elements [0 : blk_size] and block=3 will handle elements 751 [3*blk_size : 4*blk_size] 752 @param t_mode Apply restriction or transpose 753 @param u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 754 @param ru Output vector (of shape [@a blk_size * @a elem_size] when 755 t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided 756 by the backend. 757 @param request Request or @ref CEED_REQUEST_IMMEDIATE 758 759 @return An error code: 0 - success, otherwise - failure 760 761 @ref Backend 762 **/ 763 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, 764 CeedTransposeMode t_mode, CeedVector u, 765 CeedVector ru, CeedRequest *request) { 766 CeedInt m, n; 767 int ierr; 768 769 if (t_mode == CEED_NOTRANSPOSE) { 770 m = rstr->blk_size * rstr->elem_size * rstr->num_comp; 771 n = rstr->l_size; 772 } else { 773 m = rstr->l_size; 774 n = rstr->blk_size * rstr->elem_size * rstr->num_comp; 775 } 776 if (n != u->length) 777 // LCOV_EXCL_START 778 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 779 "Input vector size %d not compatible with " 780 "element restriction (%d, %d)", u->length, m, n); 781 // LCOV_EXCL_STOP 782 if (m != ru->length) 783 // LCOV_EXCL_START 784 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 785 "Output vector size %d not compatible with " 786 "element restriction (%d, %d)", ru->length, m, n); 787 // LCOV_EXCL_STOP 788 if (rstr->blk_size*block > rstr->num_elem) 789 // LCOV_EXCL_START 790 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 791 "Cannot retrieve block %d, element %d > " 792 "total elements %d", block, rstr->blk_size*block, 793 rstr->num_elem); 794 // LCOV_EXCL_STOP 795 ierr = rstr->ApplyBlock(rstr, block, t_mode, u, ru, request); 796 CeedChk(ierr); 797 return CEED_ERROR_SUCCESS; 798 } 799 800 /** 801 @brief Get the Ceed associated with a CeedElemRestriction 802 803 @param rstr CeedElemRestriction 804 @param[out] ceed Variable to store Ceed 805 806 @return An error code: 0 - success, otherwise - failure 807 808 @ref Advanced 809 **/ 810 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 811 *ceed = rstr->ceed; 812 return CEED_ERROR_SUCCESS; 813 } 814 815 /** 816 @brief Get the L-vector component stride 817 818 @param rstr CeedElemRestriction 819 @param[out] comp_stride Variable to store component stride 820 821 @return An error code: 0 - success, otherwise - failure 822 823 @ref Advanced 824 **/ 825 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, 826 CeedInt *comp_stride) { 827 *comp_stride = rstr->comp_stride; 828 return CEED_ERROR_SUCCESS; 829 } 830 831 /** 832 @brief Get the total number of elements in the range of a CeedElemRestriction 833 834 @param rstr CeedElemRestriction 835 @param[out] num_elem Variable to store number of elements 836 837 @return An error code: 0 - success, otherwise - failure 838 839 @ref Advanced 840 **/ 841 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, 842 CeedInt *num_elem) { 843 *num_elem = rstr->num_elem; 844 return CEED_ERROR_SUCCESS; 845 } 846 847 /** 848 @brief Get the size of elements in the CeedElemRestriction 849 850 @param rstr CeedElemRestriction 851 @param[out] elem_size Variable to store size of elements 852 853 @return An error code: 0 - success, otherwise - failure 854 855 @ref Advanced 856 **/ 857 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, 858 CeedInt *elem_size) { 859 *elem_size = rstr->elem_size; 860 return CEED_ERROR_SUCCESS; 861 } 862 863 /** 864 @brief Get the size of the l-vector for a CeedElemRestriction 865 866 @param rstr CeedElemRestriction 867 @param[out] l_size Variable to store number of nodes 868 869 @return An error code: 0 - success, otherwise - failure 870 871 @ref Advanced 872 **/ 873 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, 874 CeedInt *l_size) { 875 *l_size = rstr->l_size; 876 return CEED_ERROR_SUCCESS; 877 } 878 879 /** 880 @brief Get the number of components in the elements of a 881 CeedElemRestriction 882 883 @param rstr CeedElemRestriction 884 @param[out] num_comp Variable to store number of components 885 886 @return An error code: 0 - success, otherwise - failure 887 888 @ref Advanced 889 **/ 890 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, 891 CeedInt *num_comp) { 892 *num_comp = rstr->num_comp; 893 return CEED_ERROR_SUCCESS; 894 } 895 896 /** 897 @brief Get the number of blocks in a CeedElemRestriction 898 899 @param rstr CeedElemRestriction 900 @param[out] num_block Variable to store number of blocks 901 902 @return An error code: 0 - success, otherwise - failure 903 904 @ref Advanced 905 **/ 906 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, 907 CeedInt *num_block) { 908 *num_block = rstr->num_blk; 909 return CEED_ERROR_SUCCESS; 910 } 911 912 /** 913 @brief Get the size of blocks in the CeedElemRestriction 914 915 @param rstr CeedElemRestriction 916 @param[out] blk_size Variable to store size of blocks 917 918 @return An error code: 0 - success, otherwise - failure 919 920 @ref Advanced 921 **/ 922 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, 923 CeedInt *blk_size) { 924 *blk_size = rstr->blk_size; 925 return CEED_ERROR_SUCCESS; 926 } 927 928 /** 929 @brief Get the multiplicity of nodes in a CeedElemRestriction 930 931 @param rstr CeedElemRestriction 932 @param[out] mult Vector to store multiplicity (of size l_size) 933 934 @return An error code: 0 - success, otherwise - failure 935 936 @ref User 937 **/ 938 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, 939 CeedVector mult) { 940 int ierr; 941 CeedVector e_vec; 942 943 // Create e_vec to hold intermediate computation in E^T (E 1) 944 ierr = CeedElemRestrictionCreateVector(rstr, NULL, &e_vec); CeedChk(ierr); 945 946 // Compute e_vec = E * 1 947 ierr = CeedVectorSetValue(mult, 1.0); CeedChk(ierr); 948 ierr = CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, 949 CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 950 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 951 ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr); 952 ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, 953 CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 954 // Cleanup 955 ierr = CeedVectorDestroy(&e_vec); CeedChk(ierr); 956 return CEED_ERROR_SUCCESS; 957 } 958 959 /** 960 @brief View a CeedElemRestriction 961 962 @param[in] rstr CeedElemRestriction to view 963 @param[in] stream Stream to write; typically stdout/stderr or a file 964 965 @return Error code: 0 - success, otherwise - failure 966 967 @ref User 968 **/ 969 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 970 char stridesstr[500]; 971 if (rstr->strides) 972 sprintf(stridesstr, "[%d, %d, %d]", rstr->strides[0], rstr->strides[1], 973 rstr->strides[2]); 974 else 975 sprintf(stridesstr, "%d", rstr->comp_stride); 976 977 fprintf(stream, "%sCeedElemRestriction from (%d, %d) to %d elements with %d " 978 "nodes each and %s %s\n", rstr->blk_size > 1 ? "Blocked " : "", 979 rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 980 rstr->strides ? "strides" : "component stride", stridesstr); 981 return CEED_ERROR_SUCCESS; 982 } 983 984 /** 985 @brief Destroy a CeedElemRestriction 986 987 @param rstr CeedElemRestriction to destroy 988 989 @return An error code: 0 - success, otherwise - failure 990 991 @ref User 992 **/ 993 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 994 int ierr; 995 996 if (!*rstr || --(*rstr)->ref_count > 0) return CEED_ERROR_SUCCESS; 997 if ((*rstr)->num_readers) 998 // LCOV_EXCL_START 999 return CeedError((*rstr)->ceed, CEED_ERROR_ACCESS, 1000 "Cannot destroy CeedElemRestriction, " 1001 "a process has read access to the offset data"); 1002 // LCOV_EXCL_STOP 1003 if ((*rstr)->Destroy) { 1004 ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr); 1005 } 1006 ierr = CeedFree(&(*rstr)->strides); CeedChk(ierr); 1007 ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr); 1008 ierr = CeedFree(rstr); CeedChk(ierr); 1009 return CEED_ERROR_SUCCESS; 1010 } 1011 1012 /// @} 1013