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