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