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[out] rstr Address of the variable where the newly created 384 CeedElemRestriction will be stored 385 386 @return An error code: 0 - success, otherwise - failure 387 388 @ref User 389 **/ 390 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, 391 CeedInt elem_size, CeedInt num_comp, 392 CeedInt comp_stride, CeedInt l_size, 393 CeedMemType mem_type, CeedCopyMode copy_mode, 394 const CeedInt *offsets, const bool *orient, 395 CeedElemRestriction *rstr) { 396 int ierr; 397 398 if (!ceed->ElemRestrictionCreate) { 399 Ceed delegate; 400 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 401 CeedChk(ierr); 402 403 if (!delegate) 404 // LCOV_EXCL_START 405 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 406 "Backend does not implement ElemRestrictionCreateOriented"); 407 // LCOV_EXCL_STOP 408 409 ierr = CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, 410 num_comp, comp_stride, l_size, 411 mem_type, copy_mode, offsets, 412 orient, rstr); CeedChk(ierr); 413 return CEED_ERROR_SUCCESS; 414 } 415 416 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 417 (*rstr)->ceed = ceed; 418 ierr = CeedReference(ceed); CeedChk(ierr); 419 (*rstr)->ref_count = 1; 420 (*rstr)->num_elem = num_elem; 421 (*rstr)->elem_size = elem_size; 422 (*rstr)->num_comp = num_comp; 423 (*rstr)->comp_stride = comp_stride; 424 (*rstr)->l_size = l_size; 425 (*rstr)->num_blk = num_elem; 426 (*rstr)->blk_size = 1; 427 ierr = ceed->ElemRestrictionCreateOriented(mem_type, copy_mode, 428 offsets, orient, *rstr); CeedChk(ierr); 429 return CEED_ERROR_SUCCESS; 430 } 431 432 /** 433 @brief Create a strided CeedElemRestriction 434 435 @param ceed A Ceed object where the CeedElemRestriction will be created 436 @param num_elem Number of elements described by the restriction 437 @param elem_size Size (number of "nodes") per element 438 @param num_comp Number of field components per interpolation "node" 439 (1 for scalar fields) 440 @param l_size The size of the L-vector. This vector may be larger than 441 the elements and fields given by this restriction. 442 @param strides Array for strides between [nodes, components, elements]. 443 Data for node i, component j, element k can be found in 444 the L-vector at index 445 i*strides[0] + j*strides[1] + k*strides[2]. 446 @a CEED_STRIDES_BACKEND may be used with vectors created 447 by a Ceed backend. 448 @param rstr Address of the variable where the newly created 449 CeedElemRestriction will be stored 450 451 @return An error code: 0 - success, otherwise - failure 452 453 @ref User 454 **/ 455 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, 456 CeedInt elem_size, 457 CeedInt num_comp, CeedInt l_size, 458 const CeedInt strides[3], 459 CeedElemRestriction *rstr) { 460 int ierr; 461 462 if (!ceed->ElemRestrictionCreate) { 463 Ceed delegate; 464 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 465 CeedChk(ierr); 466 467 if (!delegate) 468 // LCOV_EXCL_START 469 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 470 "Backend does not support ElemRestrictionCreate"); 471 // LCOV_EXCL_STOP 472 473 ierr = CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, 474 l_size, strides, rstr); 475 CeedChk(ierr); 476 return CEED_ERROR_SUCCESS; 477 } 478 479 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 480 (*rstr)->ceed = ceed; 481 ierr = CeedReference(ceed); CeedChk(ierr); 482 (*rstr)->ref_count = 1; 483 (*rstr)->num_elem = num_elem; 484 (*rstr)->elem_size = elem_size; 485 (*rstr)->num_comp = num_comp; 486 (*rstr)->l_size = l_size; 487 (*rstr)->num_blk = num_elem; 488 (*rstr)->blk_size = 1; 489 ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr); 490 for (int i=0; i<3; i++) 491 (*rstr)->strides[i] = strides[i]; 492 ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, 493 *rstr); 494 CeedChk(ierr); 495 return CEED_ERROR_SUCCESS; 496 } 497 498 /** 499 @brief Create a blocked CeedElemRestriction, typically only called by backends 500 501 @param ceed A Ceed object where the CeedElemRestriction will be created. 502 @param num_elem Number of elements described in the @a offsets array. 503 @param elem_size Size (number of unknowns) per element 504 @param blk_size Number of elements in a block 505 @param num_comp Number of field components per interpolation node 506 (1 for scalar fields) 507 @param comp_stride Stride between components for the same L-vector "node". 508 Data for node i, component j, element k can be found in 509 the L-vector at index 510 offsets[i + k*elem_size] + j*comp_stride. 511 @param l_size The size of the L-vector. This vector may be larger than 512 the elements and fields given by this restriction. 513 @param mem_type Memory type of the @a offsets array, see CeedMemType 514 @param copy_mode Copy mode for the @a offsets array, see CeedCopyMode 515 @param offsets Array of shape [@a num_elem, @a elem_size]. Row i holds the 516 ordered list of the offsets (into the input CeedVector) 517 for the unknowns corresponding to element i, where 518 0 <= i < @a num_elem. All offsets must be in the range 519 [0, @a l_size - 1]. The backend will permute and pad this 520 array to the desired ordering for the blocksize, which is 521 typically given by the backend. The default reordering is 522 to interlace elements. 523 @param rstr Address of the variable where the newly created 524 CeedElemRestriction will be stored 525 526 @return An error code: 0 - success, otherwise - failure 527 528 @ref Backend 529 **/ 530 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, 531 CeedInt elem_size, 532 CeedInt blk_size, CeedInt num_comp, 533 CeedInt comp_stride, CeedInt l_size, 534 CeedMemType mem_type, CeedCopyMode copy_mode, 535 const CeedInt *offsets, 536 CeedElemRestriction *rstr) { 537 int ierr; 538 CeedInt *blk_offsets; 539 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 540 541 if (!ceed->ElemRestrictionCreateBlocked) { 542 Ceed delegate; 543 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 544 CeedChk(ierr); 545 546 if (!delegate) 547 // LCOV_EXCL_START 548 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support " 549 "ElemRestrictionCreateBlocked"); 550 // LCOV_EXCL_STOP 551 552 ierr = CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size, 553 num_comp, comp_stride, l_size, mem_type, 554 copy_mode, offsets, rstr); 555 CeedChk(ierr); 556 return CEED_ERROR_SUCCESS; 557 } 558 559 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 560 561 ierr = CeedCalloc(num_blk*blk_size*elem_size, &blk_offsets); CeedChk(ierr); 562 ierr = CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, 563 elem_size); CeedChk(ierr); 564 565 (*rstr)->ceed = ceed; 566 ierr = CeedReference(ceed); CeedChk(ierr); 567 (*rstr)->ref_count = 1; 568 (*rstr)->num_elem = num_elem; 569 (*rstr)->elem_size = elem_size; 570 (*rstr)->num_comp = num_comp; 571 (*rstr)->comp_stride = comp_stride; 572 (*rstr)->l_size = l_size; 573 (*rstr)->num_blk = num_blk; 574 (*rstr)->blk_size = blk_size; 575 ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, 576 (const CeedInt *) blk_offsets, *rstr); CeedChk(ierr); 577 if (copy_mode == CEED_OWN_POINTER) { 578 ierr = CeedFree(&offsets); CeedChk(ierr); 579 } 580 return CEED_ERROR_SUCCESS; 581 } 582 583 /** 584 @brief Create a blocked strided CeedElemRestriction 585 586 @param ceed A Ceed object where the CeedElemRestriction will be created 587 @param num_elem Number of elements described by the restriction 588 @param elem_size Size (number of "nodes") per element 589 @param blk_size Number of elements in a block 590 @param num_comp Number of field components per interpolation node 591 (1 for scalar fields) 592 @param l_size The size of the L-vector. This vector may be larger than 593 the elements and fields given by this restriction. 594 @param strides Array for strides between [nodes, components, elements]. 595 Data for node i, component j, element k can be found in 596 the L-vector at index 597 i*strides[0] + j*strides[1] + k*strides[2]. 598 @a CEED_STRIDES_BACKEND may be used with vectors created 599 by a Ceed backend. 600 @param rstr Address of the variable where the newly created 601 CeedElemRestriction will be stored 602 603 @return An error code: 0 - success, otherwise - failure 604 605 @ref User 606 **/ 607 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, 608 CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt l_size, 609 const CeedInt strides[3], CeedElemRestriction *rstr) { 610 int ierr; 611 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 612 613 if (!ceed->ElemRestrictionCreateBlocked) { 614 Ceed delegate; 615 ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction"); 616 CeedChk(ierr); 617 618 if (!delegate) 619 // LCOV_EXCL_START 620 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support " 621 "ElemRestrictionCreateBlocked"); 622 // LCOV_EXCL_STOP 623 624 ierr = CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, 625 blk_size, num_comp, l_size, strides, rstr); CeedChk(ierr); 626 return CEED_ERROR_SUCCESS; 627 } 628 629 ierr = CeedCalloc(1, rstr); CeedChk(ierr); 630 631 (*rstr)->ceed = ceed; 632 ierr = CeedReference(ceed); CeedChk(ierr); 633 (*rstr)->ref_count = 1; 634 (*rstr)->num_elem = num_elem; 635 (*rstr)->elem_size = elem_size; 636 (*rstr)->num_comp = num_comp; 637 (*rstr)->l_size = l_size; 638 (*rstr)->num_blk = num_blk; 639 (*rstr)->blk_size = blk_size; 640 ierr = CeedMalloc(3, &(*rstr)->strides); CeedChk(ierr); 641 for (int i=0; i<3; i++) 642 (*rstr)->strides[i] = strides[i]; 643 ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, 644 NULL, *rstr); CeedChk(ierr); 645 return CEED_ERROR_SUCCESS; 646 } 647 648 /** 649 @brief Copy the pointer to a CeedElemRestriction. Both pointers should 650 be destroyed with `CeedElemRestrictionDestroy()`; 651 Note: If `*rstr_copy` is non-NULL, then it is assumed that 652 `*rstr_copy` is a pointer to a CeedElemRestriction. This 653 CeedElemRestriction will be destroyed if `*rstr_copy` is the 654 only reference to this CeedElemRestriction. 655 656 @param rstr CeedElemRestriction to copy reference to 657 @param[out] rstr_copy Variable to store copied reference 658 659 @return An error code: 0 - success, otherwise - failure 660 661 @ref User 662 **/ 663 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, 664 CeedElemRestriction *rstr_copy) { 665 int ierr; 666 667 ierr = CeedElemRestrictionReference(rstr); CeedChk(ierr); 668 ierr = CeedElemRestrictionDestroy(rstr_copy); CeedChk(ierr); 669 *rstr_copy = rstr; 670 return CEED_ERROR_SUCCESS; 671 } 672 673 /** 674 @brief Create CeedVectors associated with a CeedElemRestriction 675 676 @param rstr CeedElemRestriction 677 @param l_vec The address of the L-vector to be created, or NULL 678 @param e_vec The address of the E-vector to be created, or NULL 679 680 @return An error code: 0 - success, otherwise - failure 681 682 @ref User 683 **/ 684 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, 685 CeedVector *e_vec) { 686 int ierr; 687 CeedInt e_size, l_size; 688 l_size = rstr->l_size; 689 e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 690 if (l_vec) { 691 ierr = CeedVectorCreate(rstr->ceed, l_size, l_vec); CeedChk(ierr); 692 } 693 if (e_vec) { 694 ierr = CeedVectorCreate(rstr->ceed, e_size, e_vec); CeedChk(ierr); 695 } 696 return CEED_ERROR_SUCCESS; 697 } 698 699 /** 700 @brief Restrict an L-vector to an E-vector or apply its transpose 701 702 @param rstr CeedElemRestriction 703 @param t_mode Apply restriction or transpose 704 @param u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 705 @param ru Output vector (of shape [@a num_elem * @a elem_size] when 706 t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided 707 by the backend. 708 @param request Request or @ref CEED_REQUEST_IMMEDIATE 709 710 @return An error code: 0 - success, otherwise - failure 711 712 @ref User 713 **/ 714 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, 715 CeedVector u, CeedVector ru, 716 CeedRequest *request) { 717 CeedInt m, n; 718 int ierr; 719 720 if (t_mode == CEED_NOTRANSPOSE) { 721 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 722 n = rstr->l_size; 723 } else { 724 m = rstr->l_size; 725 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 726 } 727 if (n != u->length) 728 // LCOV_EXCL_START 729 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 730 "Input vector size %d not compatible with " 731 "element restriction (%d, %d)", u->length, m, n); 732 // LCOV_EXCL_STOP 733 if (m != ru->length) 734 // LCOV_EXCL_START 735 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 736 "Output vector size %d not compatible with " 737 "element restriction (%d, %d)", ru->length, m, n); 738 // LCOV_EXCL_STOP 739 ierr = rstr->Apply(rstr, t_mode, u, ru, request); CeedChk(ierr); 740 return CEED_ERROR_SUCCESS; 741 } 742 743 /** 744 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 745 746 @param rstr CeedElemRestriction 747 @param block Block number to restrict to/from, i.e. block=0 will handle 748 elements [0 : blk_size] and block=3 will handle elements 749 [3*blk_size : 4*blk_size] 750 @param t_mode Apply restriction or transpose 751 @param u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 752 @param ru Output vector (of shape [@a blk_size * @a elem_size] when 753 t_mode=@ref CEED_NOTRANSPOSE). Ordering of the e-vector is decided 754 by the backend. 755 @param request Request or @ref CEED_REQUEST_IMMEDIATE 756 757 @return An error code: 0 - success, otherwise - failure 758 759 @ref Backend 760 **/ 761 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, 762 CeedTransposeMode t_mode, CeedVector u, 763 CeedVector ru, CeedRequest *request) { 764 CeedInt m, n; 765 int ierr; 766 767 if (t_mode == CEED_NOTRANSPOSE) { 768 m = rstr->blk_size * rstr->elem_size * rstr->num_comp; 769 n = rstr->l_size; 770 } else { 771 m = rstr->l_size; 772 n = rstr->blk_size * rstr->elem_size * rstr->num_comp; 773 } 774 if (n != u->length) 775 // LCOV_EXCL_START 776 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 777 "Input vector size %d not compatible with " 778 "element restriction (%d, %d)", u->length, m, n); 779 // LCOV_EXCL_STOP 780 if (m != ru->length) 781 // LCOV_EXCL_START 782 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 783 "Output vector size %d not compatible with " 784 "element restriction (%d, %d)", ru->length, m, n); 785 // LCOV_EXCL_STOP 786 if (rstr->blk_size*block > rstr->num_elem) 787 // LCOV_EXCL_START 788 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 789 "Cannot retrieve block %d, element %d > " 790 "total elements %d", block, rstr->blk_size*block, 791 rstr->num_elem); 792 // LCOV_EXCL_STOP 793 ierr = rstr->ApplyBlock(rstr, block, t_mode, u, ru, request); 794 CeedChk(ierr); 795 return CEED_ERROR_SUCCESS; 796 } 797 798 /** 799 @brief Get the Ceed associated with a CeedElemRestriction 800 801 @param rstr CeedElemRestriction 802 @param[out] ceed Variable to store Ceed 803 804 @return An error code: 0 - success, otherwise - failure 805 806 @ref Advanced 807 **/ 808 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 809 *ceed = rstr->ceed; 810 return CEED_ERROR_SUCCESS; 811 } 812 813 /** 814 @brief Get the L-vector component stride 815 816 @param rstr CeedElemRestriction 817 @param[out] comp_stride Variable to store component stride 818 819 @return An error code: 0 - success, otherwise - failure 820 821 @ref Advanced 822 **/ 823 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, 824 CeedInt *comp_stride) { 825 *comp_stride = rstr->comp_stride; 826 return CEED_ERROR_SUCCESS; 827 } 828 829 /** 830 @brief Get the total number of elements in the range of a CeedElemRestriction 831 832 @param rstr CeedElemRestriction 833 @param[out] num_elem Variable to store number of elements 834 835 @return An error code: 0 - success, otherwise - failure 836 837 @ref Advanced 838 **/ 839 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, 840 CeedInt *num_elem) { 841 *num_elem = rstr->num_elem; 842 return CEED_ERROR_SUCCESS; 843 } 844 845 /** 846 @brief Get the size of elements in the CeedElemRestriction 847 848 @param rstr CeedElemRestriction 849 @param[out] elem_size Variable to store size of elements 850 851 @return An error code: 0 - success, otherwise - failure 852 853 @ref Advanced 854 **/ 855 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, 856 CeedInt *elem_size) { 857 *elem_size = rstr->elem_size; 858 return CEED_ERROR_SUCCESS; 859 } 860 861 /** 862 @brief Get the size of the l-vector for a CeedElemRestriction 863 864 @param rstr CeedElemRestriction 865 @param[out] l_size Variable to store number of nodes 866 867 @return An error code: 0 - success, otherwise - failure 868 869 @ref Advanced 870 **/ 871 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, 872 CeedInt *l_size) { 873 *l_size = rstr->l_size; 874 return CEED_ERROR_SUCCESS; 875 } 876 877 /** 878 @brief Get the number of components in the elements of a 879 CeedElemRestriction 880 881 @param rstr CeedElemRestriction 882 @param[out] num_comp Variable to store number of components 883 884 @return An error code: 0 - success, otherwise - failure 885 886 @ref Advanced 887 **/ 888 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, 889 CeedInt *num_comp) { 890 *num_comp = rstr->num_comp; 891 return CEED_ERROR_SUCCESS; 892 } 893 894 /** 895 @brief Get the number of blocks in a CeedElemRestriction 896 897 @param rstr CeedElemRestriction 898 @param[out] num_block Variable to store number of blocks 899 900 @return An error code: 0 - success, otherwise - failure 901 902 @ref Advanced 903 **/ 904 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, 905 CeedInt *num_block) { 906 *num_block = rstr->num_blk; 907 return CEED_ERROR_SUCCESS; 908 } 909 910 /** 911 @brief Get the size of blocks in the CeedElemRestriction 912 913 @param rstr CeedElemRestriction 914 @param[out] blk_size Variable to store size of blocks 915 916 @return An error code: 0 - success, otherwise - failure 917 918 @ref Advanced 919 **/ 920 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, 921 CeedInt *blk_size) { 922 *blk_size = rstr->blk_size; 923 return CEED_ERROR_SUCCESS; 924 } 925 926 /** 927 @brief Get the multiplicity of nodes in a CeedElemRestriction 928 929 @param rstr CeedElemRestriction 930 @param[out] mult Vector to store multiplicity (of size l_size) 931 932 @return An error code: 0 - success, otherwise - failure 933 934 @ref User 935 **/ 936 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, 937 CeedVector mult) { 938 int ierr; 939 CeedVector e_vec; 940 941 // Create e_vec to hold intermediate computation in E^T (E 1) 942 ierr = CeedElemRestrictionCreateVector(rstr, NULL, &e_vec); CeedChk(ierr); 943 944 // Compute e_vec = E * 1 945 ierr = CeedVectorSetValue(mult, 1.0); CeedChk(ierr); 946 ierr = CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, 947 CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 948 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 949 ierr = CeedVectorSetValue(mult, 0.0); CeedChk(ierr); 950 ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, 951 CEED_REQUEST_IMMEDIATE); CeedChk(ierr); 952 // Cleanup 953 ierr = CeedVectorDestroy(&e_vec); CeedChk(ierr); 954 return CEED_ERROR_SUCCESS; 955 } 956 957 /** 958 @brief View a CeedElemRestriction 959 960 @param[in] rstr CeedElemRestriction to view 961 @param[in] stream Stream to write; typically stdout/stderr or a file 962 963 @return Error code: 0 - success, otherwise - failure 964 965 @ref User 966 **/ 967 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 968 char stridesstr[500]; 969 if (rstr->strides) 970 sprintf(stridesstr, "[%d, %d, %d]", rstr->strides[0], rstr->strides[1], 971 rstr->strides[2]); 972 else 973 sprintf(stridesstr, "%d", rstr->comp_stride); 974 975 fprintf(stream, "%sCeedElemRestriction from (%d, %d) to %d elements with %d " 976 "nodes each and %s %s\n", rstr->blk_size > 1 ? "Blocked " : "", 977 rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 978 rstr->strides ? "strides" : "component stride", stridesstr); 979 return CEED_ERROR_SUCCESS; 980 } 981 982 /** 983 @brief Destroy a CeedElemRestriction 984 985 @param rstr CeedElemRestriction to destroy 986 987 @return An error code: 0 - success, otherwise - failure 988 989 @ref User 990 **/ 991 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 992 int ierr; 993 994 if (!*rstr || --(*rstr)->ref_count > 0) return CEED_ERROR_SUCCESS; 995 if ((*rstr)->num_readers) 996 // LCOV_EXCL_START 997 return CeedError((*rstr)->ceed, CEED_ERROR_ACCESS, 998 "Cannot destroy CeedElemRestriction, " 999 "a process has read access to the offset data"); 1000 // LCOV_EXCL_STOP 1001 if ((*rstr)->Destroy) { 1002 ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr); 1003 } 1004 ierr = CeedFree(&(*rstr)->strides); CeedChk(ierr); 1005 ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr); 1006 ierr = CeedFree(rstr); CeedChk(ierr); 1007 return CEED_ERROR_SUCCESS; 1008 } 1009 1010 /// @} 1011