1 // Copyright (c) 2017-2024, 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.h> 10 #include <ceed/backend.h> 11 #include <stdbool.h> 12 #include <stdio.h> 13 #include <string.h> 14 15 /// @file 16 /// Implementation of CeedElemRestriction interfaces 17 18 /// ---------------------------------------------------------------------------- 19 /// CeedElemRestriction Library Internal Functions 20 /// ---------------------------------------------------------------------------- 21 /// @addtogroup CeedElemRestrictionDeveloper 22 /// @{ 23 24 /** 25 @brief Permute and pad offsets for a blocked `CeedElemRestriction` 26 27 @param[in] offsets Array of shape `[num_elem, elem_size]` 28 @param[out] block_offsets Array of permuted and padded array values of shape `[num_block, elem_size, block_size]` 29 @param[in] num_block Number of blocks 30 @param[in] num_elem Number of elements 31 @param[in] block_size Number of elements in a block 32 @param[in] elem_size Size of each element 33 34 @return An error code: 0 - success, otherwise - failure 35 36 @ref Utility 37 **/ 38 int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *block_offsets, CeedInt num_block, CeedInt num_elem, CeedInt block_size, 39 CeedInt elem_size) { 40 for (CeedInt e = 0; e < num_block * block_size; e += block_size) { 41 for (CeedInt j = 0; j < block_size; j++) { 42 for (CeedInt k = 0; k < elem_size; k++) { 43 block_offsets[e * elem_size + k * block_size + j] = offsets[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 44 } 45 } 46 } 47 return CEED_ERROR_SUCCESS; 48 } 49 50 /** 51 @brief Permute and pad orientations for a blocked `CeedElemRestriction` 52 53 @param[in] orients Array of shape `[num_elem, elem_size]` 54 @param[out] block_orients Array of permuted and padded array values of shape `[num_block, elem_size, block_size]` 55 @param[in] num_block Number of blocks 56 @param[in] num_elem Number of elements 57 @param[in] block_size Number of elements in a block 58 @param[in] elem_size Size of each element 59 60 @return An error code: 0 - success, otherwise - failure 61 62 @ref Utility 63 **/ 64 int CeedPermutePadOrients(const bool *orients, bool *block_orients, CeedInt num_block, CeedInt num_elem, CeedInt block_size, CeedInt elem_size) { 65 for (CeedInt e = 0; e < num_block * block_size; e += block_size) { 66 for (CeedInt j = 0; j < block_size; j++) { 67 for (CeedInt k = 0; k < elem_size; k++) { 68 block_orients[e * elem_size + k * block_size + j] = orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 69 } 70 } 71 } 72 return CEED_ERROR_SUCCESS; 73 } 74 75 /** 76 @brief Permute and pad curl-conforming orientations for a blocked `CeedElemRestriction` 77 78 @param[in] curl_orients Array of shape `[num_elem, elem_size]` 79 @param[out] block_curl_orients Array of permuted and padded array values of shape `[num_block, elem_size, block_size]` 80 @param[in] num_block Number of blocks 81 @param[in] num_elem Number of elements 82 @param[in] block_size Number of elements in a block 83 @param[in] elem_size Size of each element 84 85 @return An error code: 0 - success, otherwise - failure 86 87 @ref Utility 88 **/ 89 int CeedPermutePadCurlOrients(const CeedInt8 *curl_orients, CeedInt8 *block_curl_orients, CeedInt num_block, CeedInt num_elem, CeedInt block_size, 90 CeedInt elem_size) { 91 for (CeedInt e = 0; e < num_block * block_size; e += block_size) { 92 for (CeedInt j = 0; j < block_size; j++) { 93 for (CeedInt k = 0; k < elem_size; k++) { 94 block_curl_orients[e * elem_size + k * block_size + j] = curl_orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 95 } 96 } 97 } 98 return CEED_ERROR_SUCCESS; 99 } 100 101 /// @} 102 103 /// ---------------------------------------------------------------------------- 104 /// CeedElemRestriction Backend API 105 /// ---------------------------------------------------------------------------- 106 /// @addtogroup CeedElemRestrictionBackend 107 /// @{ 108 109 /** 110 @brief Get the type of a `CeedElemRestriction` 111 112 @param[in] rstr `CeedElemRestriction` 113 @param[out] rstr_type Variable to store restriction type 114 115 @return An error code: 0 - success, otherwise - failure 116 117 @ref Backend 118 **/ 119 int CeedElemRestrictionGetType(CeedElemRestriction rstr, CeedRestrictionType *rstr_type) { 120 *rstr_type = rstr->rstr_type; 121 return CEED_ERROR_SUCCESS; 122 } 123 124 /** 125 @brief Get the strided status of a `CeedElemRestriction` 126 127 @param[in] rstr `CeedElemRestriction` 128 @param[out] is_strided Variable to store strided status 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->rstr_type == CEED_RESTRICTION_STRIDED); 136 return CEED_ERROR_SUCCESS; 137 } 138 139 /** 140 @brief Get the points status of a `CeedElemRestriction` 141 142 @param[in] rstr `CeedElemRestriction` 143 @param[out] is_points Variable to store points status 144 145 @return An error code: 0 - success, otherwise - failure 146 147 @ref Backend 148 **/ 149 int CeedElemRestrictionIsPoints(CeedElemRestriction rstr, bool *is_points) { 150 *is_points = (rstr->rstr_type == CEED_RESTRICTION_POINTS); 151 return CEED_ERROR_SUCCESS; 152 } 153 154 /** 155 @brief Check if two `CeedElemRestriction` created with @ref CeedElemRestrictionCreateAtPoints() and use the same points per element 156 157 @param[in] rstr_a First `CeedElemRestriction` 158 @param[in] rstr_b Second `CeedElemRestriction` 159 @param[out] are_compatible Variable to store compatibility status 160 161 @return An error code: 0 - success, otherwise - failure 162 163 @ref Backend 164 **/ 165 int CeedElemRestrictionAtPointsAreCompatible(CeedElemRestriction rstr_a, CeedElemRestriction rstr_b, bool *are_compatible) { 166 CeedInt num_elem_a, num_elem_b, num_points_a, num_points_b; 167 Ceed ceed; 168 169 CeedCall(CeedElemRestrictionGetCeed(rstr_a, &ceed)); 170 171 // Cannot compare non-points restrictions 172 CeedCheck(rstr_a->rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_UNSUPPORTED, "First CeedElemRestriction must be AtPoints"); 173 CeedCheck(rstr_b->rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_UNSUPPORTED, "Second CeedElemRestriction must be AtPoints"); 174 175 CeedCall(CeedElemRestrictionGetNumElements(rstr_a, &num_elem_a)); 176 CeedCall(CeedElemRestrictionGetNumElements(rstr_b, &num_elem_b)); 177 CeedCall(CeedElemRestrictionGetNumPoints(rstr_a, &num_points_a)); 178 CeedCall(CeedElemRestrictionGetNumPoints(rstr_b, &num_points_b)); 179 180 // Check size and contents of offsets arrays 181 *are_compatible = true; 182 if (num_elem_a != num_elem_b) *are_compatible = false; 183 if (num_points_a != num_points_b) *are_compatible = false; 184 if (*are_compatible) { 185 const CeedInt *offsets_a, *offsets_b; 186 187 CeedCall(CeedElemRestrictionGetOffsets(rstr_a, CEED_MEM_HOST, &offsets_a)); 188 CeedCall(CeedElemRestrictionGetOffsets(rstr_b, CEED_MEM_HOST, &offsets_b)); 189 for (CeedInt i = 0; i < num_elem_a + 1 + num_points_a; i++) *are_compatible &= offsets_a[i] == offsets_b[i]; 190 CeedCall(CeedElemRestrictionRestoreOffsets(rstr_a, &offsets_a)); 191 CeedCall(CeedElemRestrictionRestoreOffsets(rstr_b, &offsets_b)); 192 } 193 return CEED_ERROR_SUCCESS; 194 } 195 196 /** 197 @brief Get the strides of a strided `CeedElemRestriction` 198 199 @param[in] rstr `CeedElemRestriction` 200 @param[out] strides Variable to store strides array 201 202 @return An error code: 0 - success, otherwise - failure 203 204 @ref Backend 205 **/ 206 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr, CeedInt strides[3]) { 207 CeedCheck(rstr->strides, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_MINOR, "CeedElemRestriction has no stride data"); 208 for (CeedInt i = 0; i < 3; i++) strides[i] = rstr->strides[i]; 209 return CEED_ERROR_SUCCESS; 210 } 211 212 /** 213 @brief Get the backend stride status of a `CeedElemRestriction` 214 215 @param[in] rstr `CeedElemRestriction` 216 @param[out] has_backend_strides Variable to store stride status 217 218 @return An error code: 0 - success, otherwise - failure 219 220 @ref Backend 221 **/ 222 int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr, bool *has_backend_strides) { 223 CeedCheck(rstr->strides, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_MINOR, "CeedElemRestriction has no stride data"); 224 *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) && (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) && 225 (rstr->strides[2] == CEED_STRIDES_BACKEND[2])); 226 return CEED_ERROR_SUCCESS; 227 } 228 229 /** 230 @brief Get read-only access to a `CeedElemRestriction` offsets array by @ref CeedMemType 231 232 @param[in] rstr `CeedElemRestriction` to retrieve offsets 233 @param[in] mem_type Memory type on which to access the array. 234 If the backend uses a different memory type, this will perform a copy (possibly cached). 235 @param[out] offsets Array on memory type `mem_type` 236 237 @return An error code: 0 - success, otherwise - failure 238 239 @ref User 240 **/ 241 int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **offsets) { 242 if (rstr->rstr_base) { 243 CeedCall(CeedElemRestrictionGetOffsets(rstr->rstr_base, mem_type, offsets)); 244 } else { 245 CeedCheck(rstr->GetOffsets, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_UNSUPPORTED, 246 "Backend does not support CeedElemRestrictionGetOffsets"); 247 CeedCall(rstr->GetOffsets(rstr, mem_type, offsets)); 248 rstr->num_readers++; 249 } 250 return CEED_ERROR_SUCCESS; 251 } 252 253 /** 254 @brief Restore an offsets array obtained using @ref CeedElemRestrictionGetOffsets() 255 256 @param[in] rstr `CeedElemRestriction` to restore 257 @param[in] offsets Array of offset data 258 259 @return An error code: 0 - success, otherwise - failure 260 261 @ref User 262 **/ 263 int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr, const CeedInt **offsets) { 264 if (rstr->rstr_base) { 265 CeedCall(CeedElemRestrictionRestoreOffsets(rstr->rstr_base, offsets)); 266 } else { 267 *offsets = NULL; 268 rstr->num_readers--; 269 } 270 return CEED_ERROR_SUCCESS; 271 } 272 273 /** 274 @brief Get read-only access to a `CeedElemRestriction` orientations array by @ref CeedMemType 275 276 @param[in] rstr `CeedElemRestriction` to retrieve orientations 277 @param[in] mem_type Memory type on which to access the array. 278 If the backend uses a different memory type, this will perform a copy (possibly cached). 279 @param[out] orients Array on memory type `mem_type` 280 281 @return An error code: 0 - success, otherwise - failure 282 283 @ref User 284 **/ 285 int CeedElemRestrictionGetOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const bool **orients) { 286 CeedCheck(rstr->GetOrientations, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_UNSUPPORTED, 287 "Backend does not support CeedElemRestrictionGetOrientations"); 288 CeedCall(rstr->GetOrientations(rstr, mem_type, orients)); 289 rstr->num_readers++; 290 return CEED_ERROR_SUCCESS; 291 } 292 293 /** 294 @brief Restore an orientations array obtained using @ref CeedElemRestrictionGetOrientations() 295 296 @param[in] rstr `CeedElemRestriction` to restore 297 @param[in] orients Array of orientation data 298 299 @return An error code: 0 - success, otherwise - failure 300 301 @ref User 302 **/ 303 int CeedElemRestrictionRestoreOrientations(CeedElemRestriction rstr, const bool **orients) { 304 *orients = NULL; 305 rstr->num_readers--; 306 return CEED_ERROR_SUCCESS; 307 } 308 309 /** 310 @brief Get read-only access to a `CeedElemRestriction` curl-conforming orientations array by @ref CeedMemType 311 312 @param[in] rstr `CeedElemRestriction` to retrieve curl-conforming orientations 313 @param[in] mem_type Memory type on which to access the array. 314 If the backend uses a different memory type, this will perform a copy (possibly cached). 315 @param[out] curl_orients Array on memory type `mem_type` 316 317 @return An error code: 0 - success, otherwise - failure 318 319 @ref User 320 **/ 321 int CeedElemRestrictionGetCurlOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt8 **curl_orients) { 322 CeedCheck(rstr->GetCurlOrientations, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_UNSUPPORTED, 323 "Backend does not support CeedElemRestrictionGetCurlOrientations"); 324 CeedCall(rstr->GetCurlOrientations(rstr, mem_type, curl_orients)); 325 rstr->num_readers++; 326 return CEED_ERROR_SUCCESS; 327 } 328 329 /** 330 @brief Restore an orientations array obtained using @ref CeedElemRestrictionGetCurlOrientations() 331 332 @param[in] rstr `CeedElemRestriction` to restore 333 @param[in] curl_orients Array of orientation data 334 335 @return An error code: 0 - success, otherwise - failure 336 337 @ref User 338 **/ 339 int CeedElemRestrictionRestoreCurlOrientations(CeedElemRestriction rstr, const CeedInt8 **curl_orients) { 340 *curl_orients = NULL; 341 rstr->num_readers--; 342 return CEED_ERROR_SUCCESS; 343 } 344 345 /** 346 347 @brief Get the L-vector layout of a strided `CeedElemRestriction` 348 349 @param[in] rstr `CeedElemRestriction` 350 @param[out] layout Variable to store layout array, stored as `[nodes, components, elements]`. 351 The data for node `i`, component `j`, element `k` in the E-vector is given by `i*layout[0] + j*layout[1] + k*layout[2]`. 352 353 @return An error code: 0 - success, otherwise - failure 354 355 @ref Backend 356 **/ 357 int CeedElemRestrictionGetLLayout(CeedElemRestriction rstr, CeedInt layout[3]) { 358 bool has_backend_strides; 359 CeedRestrictionType rstr_type; 360 Ceed ceed; 361 362 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 363 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 364 CeedCheck(rstr_type == CEED_RESTRICTION_STRIDED, ceed, CEED_ERROR_MINOR, "Only strided CeedElemRestriction have strided L-vector layout"); 365 CeedCall(CeedElemRestrictionHasBackendStrides(rstr, &has_backend_strides)); 366 if (has_backend_strides) { 367 CeedCheck(rstr->l_layout[0], ceed, CEED_ERROR_MINOR, "CeedElemRestriction has no L-vector layout data"); 368 for (CeedInt i = 0; i < 3; i++) layout[i] = rstr->l_layout[i]; 369 } else { 370 CeedCall(CeedElemRestrictionGetStrides(rstr, layout)); 371 } 372 return CEED_ERROR_SUCCESS; 373 } 374 375 /** 376 377 @brief Set the L-vector layout of a strided `CeedElemRestriction` 378 379 @param[in] rstr `CeedElemRestriction` 380 @param[in] layout Variable to containing layout array, stored as `[nodes, components, elements]`. 381 The data for node `i`, component `j`, element `k` in the E-vector is given by `i*layout[0] + j*layout[1] + k*layout[2]`. 382 383 @return An error code: 0 - success, otherwise - failure 384 385 @ref Backend 386 **/ 387 int CeedElemRestrictionSetLLayout(CeedElemRestriction rstr, CeedInt layout[3]) { 388 CeedRestrictionType rstr_type; 389 390 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 391 CeedCheck(rstr_type == CEED_RESTRICTION_STRIDED, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_MINOR, 392 "Only strided CeedElemRestriction have strided L-vector layout"); 393 for (CeedInt i = 0; i < 3; i++) rstr->l_layout[i] = layout[i]; 394 return CEED_ERROR_SUCCESS; 395 } 396 397 /** 398 399 @brief Get the E-vector layout of a `CeedElemRestriction` 400 401 @param[in] rstr `CeedElemRestriction` 402 @param[out] layout Variable to store layout array, stored as `[nodes, components, elements]`. 403 The data for node `i`, component `j`, element `k` in the E-vector is given by `i*layout[0] + j*layout[1] + k*layout[2]`. 404 405 @return An error code: 0 - success, otherwise - failure 406 407 @ref Backend 408 **/ 409 int CeedElemRestrictionGetELayout(CeedElemRestriction rstr, CeedInt layout[3]) { 410 CeedCheck(rstr->e_layout[0], CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_MINOR, "CeedElemRestriction has no E-vector layout data"); 411 for (CeedInt i = 0; i < 3; i++) layout[i] = rstr->e_layout[i]; 412 return CEED_ERROR_SUCCESS; 413 } 414 415 /** 416 417 @brief Set the E-vector layout of a `CeedElemRestriction` 418 419 @param[in] rstr `CeedElemRestriction` 420 @param[in] layout Variable to containing layout array, stored as `[nodes, components, elements]`. 421 The data for node `i`, component `j`, element `k` in the E-vector is given by `i*layout[0] + j*layout[1] + k*layout[2]`. 422 423 @return An error code: 0 - success, otherwise - failure 424 425 @ref Backend 426 **/ 427 int CeedElemRestrictionSetELayout(CeedElemRestriction rstr, CeedInt layout[3]) { 428 for (CeedInt i = 0; i < 3; i++) rstr->e_layout[i] = layout[i]; 429 return CEED_ERROR_SUCCESS; 430 } 431 432 /** 433 434 @brief Get the E-vector element offset of a `CeedElemRestriction` at points 435 436 @param[in] rstr `CeedElemRestriction` 437 @param[in] elem Element number index into E-vector for 438 @param[out] elem_offset Offset for element `elem` in the E-vector. 439 The data for point `i`, component `j`, element `elem` in the E-vector is given by `i*e_layout[0] + j*e_layout[1] + elem_offset`. 440 441 @return An error code: 0 - success, otherwise - failure 442 443 @ref Backend 444 **/ 445 int CeedElemRestrictionGetAtPointsElementOffset(CeedElemRestriction rstr, CeedInt elem, CeedSize *elem_offset) { 446 CeedInt num_comp; 447 CeedRestrictionType rstr_type; 448 449 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 450 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 451 "Can only compute offset for a points CeedElemRestriction"); 452 453 // Backend method 454 if (rstr->GetAtPointsElementOffset) { 455 CeedCall(rstr->GetAtPointsElementOffset(rstr, elem, elem_offset)); 456 return CEED_ERROR_SUCCESS; 457 } 458 459 // Default layout (CPU) 460 *elem_offset = 0; 461 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 462 for (CeedInt i = 0; i < elem; i++) { 463 CeedInt num_points; 464 465 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, i, &num_points)); 466 *elem_offset += num_points * num_comp; 467 } 468 return CEED_ERROR_SUCCESS; 469 } 470 471 /** 472 @brief Get the backend data of a `CeedElemRestriction` 473 474 @param[in] rstr `CeedElemRestriction` 475 @param[out] data Variable to store data 476 477 @return An error code: 0 - success, otherwise - failure 478 479 @ref Backend 480 **/ 481 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) { 482 *(void **)data = rstr->data; 483 return CEED_ERROR_SUCCESS; 484 } 485 486 /** 487 @brief Set the backend data of a `CeedElemRestriction` 488 489 @param[in,out] rstr `CeedElemRestriction` 490 @param[in] data Data to set 491 492 @return An error code: 0 - success, otherwise - failure 493 494 @ref Backend 495 **/ 496 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) { 497 rstr->data = data; 498 return CEED_ERROR_SUCCESS; 499 } 500 501 /** 502 @brief Increment the reference counter for a `CeedElemRestriction` 503 504 @param[in,out] rstr `CeedElemRestriction` to increment the reference counter 505 506 @return An error code: 0 - success, otherwise - failure 507 508 @ref Backend 509 **/ 510 int CeedElemRestrictionReference(CeedElemRestriction rstr) { 511 rstr->ref_count++; 512 return CEED_ERROR_SUCCESS; 513 } 514 515 /** 516 @brief Estimate number of FLOPs required to apply `CeedElemRestriction` in `t_mode` 517 518 @param[in] rstr `CeedElemRestriction` to estimate FLOPs for 519 @param[in] t_mode Apply restriction or transpose 520 @param[out] flops Address of variable to hold FLOPs estimate 521 522 @ref Backend 523 **/ 524 int CeedElemRestrictionGetFlopsEstimate(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedSize *flops) { 525 CeedSize e_size, scale = 0; 526 CeedRestrictionType rstr_type; 527 528 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &e_size)); 529 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 530 if (t_mode == CEED_TRANSPOSE) { 531 switch (rstr_type) { 532 case CEED_RESTRICTION_POINTS: 533 scale = 0; 534 break; 535 case CEED_RESTRICTION_STRIDED: 536 case CEED_RESTRICTION_STANDARD: 537 scale = 1; 538 break; 539 case CEED_RESTRICTION_ORIENTED: 540 scale = 2; 541 break; 542 case CEED_RESTRICTION_CURL_ORIENTED: 543 scale = 6; 544 break; 545 } 546 } else { 547 switch (rstr_type) { 548 case CEED_RESTRICTION_STRIDED: 549 case CEED_RESTRICTION_STANDARD: 550 case CEED_RESTRICTION_POINTS: 551 scale = 0; 552 break; 553 case CEED_RESTRICTION_ORIENTED: 554 scale = 1; 555 break; 556 case CEED_RESTRICTION_CURL_ORIENTED: 557 scale = 5; 558 break; 559 } 560 } 561 *flops = e_size * scale; 562 return CEED_ERROR_SUCCESS; 563 } 564 565 /// @} 566 567 /// @cond DOXYGEN_SKIP 568 static struct CeedElemRestriction_private ceed_elemrestriction_none; 569 /// @endcond 570 571 /// ---------------------------------------------------------------------------- 572 /// CeedElemRestriction Public API 573 /// ---------------------------------------------------------------------------- 574 /// @addtogroup CeedElemRestrictionUser 575 /// @{ 576 577 /// Indicate that the stride is determined by the backend 578 const CeedInt CEED_STRIDES_BACKEND[3] = {0}; 579 580 /// Argument for @ref CeedOperatorSetField() indicating that the field does not require a `CeedElemRestriction` 581 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none; 582 583 /** 584 @brief Create a `CeedElemRestriction` 585 586 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 587 @param[in] num_elem Number of elements described in the `offsets` array 588 @param[in] elem_size Size (number of "nodes") per element 589 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 590 @param[in] comp_stride Stride between components for the same L-vector "node". 591 Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`. 592 @param[in] l_size The size of the L-vector. 593 This vector may be larger than the elements and fields given by this restriction. 594 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 595 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 596 @param[in] offsets Array of shape `[num_elem, elem_size]`. 597 Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where 0 <= i < @a num_elem. 598 All offsets must be in the range `[0, l_size - 1]`. 599 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 600 601 @return An error code: 0 - success, otherwise - failure 602 603 @ref User 604 **/ 605 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 606 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 607 if (!ceed->ElemRestrictionCreate) { 608 Ceed delegate; 609 610 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 611 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreate"); 612 CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 613 return CEED_ERROR_SUCCESS; 614 } 615 616 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 617 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 618 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 619 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 620 621 CeedCall(CeedCalloc(1, rstr)); 622 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->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)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 630 (*rstr)->num_block = num_elem; 631 (*rstr)->block_size = 1; 632 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 633 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 634 return CEED_ERROR_SUCCESS; 635 } 636 637 /** 638 @brief Create a `CeedElemRestriction` with orientation signs 639 640 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 641 @param[in] num_elem Number of elements described in the `offsets` array 642 @param[in] elem_size Size (number of "nodes") per element 643 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 644 @param[in] comp_stride Stride between components for the same L-vector "node". 645 Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`. 646 @param[in] l_size The size of the L-vector. 647 This vector may be larger than the elements and fields given by this restriction. 648 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 649 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 650 @param[in] offsets Array of shape `[num_elem, elem_size]`. 651 Row i holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`. 652 All offsets must be in the range `[0, l_size - 1]`. 653 @param[in] orients Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation 654 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 655 656 @return An error code: 0 - success, otherwise - failure 657 658 @ref User 659 **/ 660 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 661 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orients, 662 CeedElemRestriction *rstr) { 663 if (!ceed->ElemRestrictionCreate) { 664 Ceed delegate; 665 666 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 667 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateOriented"); 668 CeedCall( 669 CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orients, rstr)); 670 return CEED_ERROR_SUCCESS; 671 } 672 673 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 674 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 675 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 676 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 677 678 CeedCall(CeedCalloc(1, rstr)); 679 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 680 (*rstr)->ref_count = 1; 681 (*rstr)->num_elem = num_elem; 682 (*rstr)->elem_size = elem_size; 683 (*rstr)->num_comp = num_comp; 684 (*rstr)->comp_stride = comp_stride; 685 (*rstr)->l_size = l_size; 686 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 687 (*rstr)->num_block = num_elem; 688 (*rstr)->block_size = 1; 689 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 690 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, orients, NULL, *rstr)); 691 return CEED_ERROR_SUCCESS; 692 } 693 694 /** 695 @brief Create a `CeedElemRestriction` with a general tridiagonal transformation matrix for curl-conforming elements 696 697 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 698 @param[in] num_elem Number of elements described in the `offsets` array 699 @param[in] elem_size Size (number of "nodes") per element 700 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 701 @param[in] comp_stride Stride between components for the same L-vector "node". 702 Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`. 703 @param[in] l_size The size of the L-vector. 704 This vector may be larger than the elements and fields given by this restriction. 705 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 706 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 707 @param[in] offsets Array of shape `[num_elem, elem_size]`. 708 Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`. 709 All offsets must be in the range `[0, l_size - 1]`. 710 @param[in] curl_orients Array of shape `[num_elem, 3 * elem_size]` representing a row-major tridiagonal matrix (`curl_orients[i * 3 * elem_size] = curl_orients[(i + 1) * 3 * elem_size - 1] = 0`, where `0 <= i < num_elem`) which is applied to the element unknowns upon restriction. 711 This orientation matrix allows for pairs of face degrees of freedom on elements for \f$H(\mathrm{curl})\f$ spaces to be coupled in the element restriction operation, which is a way to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456). 712 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 713 714 @return An error code: 0 - success, otherwise - failure 715 716 @ref User 717 **/ 718 int CeedElemRestrictionCreateCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 719 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const CeedInt8 *curl_orients, 720 CeedElemRestriction *rstr) { 721 if (!ceed->ElemRestrictionCreate) { 722 Ceed delegate; 723 724 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 725 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateCurlOriented"); 726 CeedCall(CeedElemRestrictionCreateCurlOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 727 curl_orients, rstr)); 728 return CEED_ERROR_SUCCESS; 729 } 730 731 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 732 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 733 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 734 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 735 736 CeedCall(CeedCalloc(1, rstr)); 737 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 738 (*rstr)->ref_count = 1; 739 (*rstr)->num_elem = num_elem; 740 (*rstr)->elem_size = elem_size; 741 (*rstr)->num_comp = num_comp; 742 (*rstr)->comp_stride = comp_stride; 743 (*rstr)->l_size = l_size; 744 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 745 (*rstr)->num_block = num_elem; 746 (*rstr)->block_size = 1; 747 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 748 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, curl_orients, *rstr)); 749 return CEED_ERROR_SUCCESS; 750 } 751 752 /** 753 @brief Create a strided `CeedElemRestriction` 754 755 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 756 @param[in] num_elem Number of elements described by the restriction 757 @param[in] elem_size Size (number of "nodes") per element 758 @param[in] num_comp Number of field components per interpolation "node" (1 for scalar fields) 759 @param[in] l_size The size of the L-vector. 760 This vector may be larger than the elements and fields given by this restriction. 761 @param[in] strides Array for strides between `[nodes, components, elements]`. 762 Data for node `i`, component `j`, element `k` can be found in the L-vector at index `i*strides[0] + j*strides[1] + k*strides[2]`. 763 @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend. 764 `CEED_STRIDES_BACKEND` should only be used pass data between `CeedOperator` created with the same `Ceed` backend. 765 The L-vector layout will, in general, be different between `Ceed` backends. 766 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 767 768 @return An error code: 0 - success, otherwise - failure 769 770 @ref User 771 **/ 772 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3], 773 CeedElemRestriction *rstr) { 774 if (!ceed->ElemRestrictionCreate) { 775 Ceed delegate; 776 777 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 778 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateStrided"); 779 CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr)); 780 return CEED_ERROR_SUCCESS; 781 } 782 783 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 784 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 785 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 786 CeedCheck(l_size >= (CeedSize)num_elem * elem_size * num_comp, ceed, CEED_ERROR_DIMENSION, 787 "L-vector size must be at least num_elem * elem_size * num_comp"); 788 789 CeedCall(CeedCalloc(1, rstr)); 790 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 791 (*rstr)->ref_count = 1; 792 (*rstr)->num_elem = num_elem; 793 (*rstr)->elem_size = elem_size; 794 (*rstr)->num_comp = num_comp; 795 (*rstr)->l_size = l_size; 796 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 797 (*rstr)->num_block = num_elem; 798 (*rstr)->block_size = 1; 799 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 800 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 801 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 802 CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 803 return CEED_ERROR_SUCCESS; 804 } 805 806 /** 807 @brief Create a points `CeedElemRestriction`, for restricting for restricting from a all local points to the current element in which they are located. 808 809 The offsets array is arranged as 810 811 element_0_start_index 812 element_1_start_index 813 ... 814 element_n_start_index 815 element_n_stop_index 816 element_0_point_0 817 element_0_point_1 818 ... 819 820 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 821 @param[in] num_elem Number of elements described in the `offsets` array 822 @param[in] num_points Number of points described in the `offsets` array 823 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields). 824 Components are assumed to be contiguous by point. 825 @param[in] l_size The size of the L-vector. 826 This vector may be larger than the elements and fields given by this restriction. 827 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 828 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 829 @param[in] offsets Array of size `num_elem + 1 + num_points`. 830 The first portion of the offsets array holds the ranges of indices corresponding to each element. 831 The second portion holds the indices for each element. 832 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 833 834 @return An error code: 0 - success, otherwise - failure 835 836 @ref Backend 837 **/ 838 int CeedElemRestrictionCreateAtPoints(Ceed ceed, CeedInt num_elem, CeedInt num_points, CeedInt num_comp, CeedSize l_size, CeedMemType mem_type, 839 CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 840 if (!ceed->ElemRestrictionCreateAtPoints) { 841 Ceed delegate; 842 843 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 844 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateAtPoints"); 845 CeedCall(CeedElemRestrictionCreateAtPoints(delegate, num_elem, num_points, num_comp, l_size, mem_type, copy_mode, offsets, rstr)); 846 return CEED_ERROR_SUCCESS; 847 } 848 849 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 850 CeedCheck(num_points >= 0, ceed, CEED_ERROR_DIMENSION, "Number of points must be non-negative"); 851 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 852 CeedCheck(l_size >= (CeedSize)num_points * num_comp, ceed, CEED_ERROR_DIMENSION, "L-vector must be at least num_points * num_comp"); 853 854 CeedCall(CeedCalloc(1, rstr)); 855 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 856 (*rstr)->ref_count = 1; 857 (*rstr)->num_elem = num_elem; 858 (*rstr)->num_points = num_points; 859 (*rstr)->num_comp = num_comp; 860 (*rstr)->l_size = l_size; 861 (*rstr)->e_size = (CeedSize)num_points * (CeedSize)num_comp; 862 (*rstr)->num_block = num_elem; 863 (*rstr)->block_size = 1; 864 (*rstr)->rstr_type = CEED_RESTRICTION_POINTS; 865 CeedCall(ceed->ElemRestrictionCreateAtPoints(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 866 return CEED_ERROR_SUCCESS; 867 } 868 869 /** 870 @brief Create a blocked `CeedElemRestriction`, typically only used by backends 871 872 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 873 @param[in] num_elem Number of elements described in the `offsets` array 874 @param[in] elem_size Size (number of unknowns) per element 875 @param[in] block_size Number of elements in a block 876 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 877 @param[in] comp_stride Stride between components for the same L-vector "node". 878 Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`. 879 @param[in] l_size The size of the L-vector. 880 This vector may be larger than the elements and fields given by this restriction. 881 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 882 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 883 @param[in] offsets Array of shape `[num_elem, elem_size]`. 884 Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`. 885 All offsets must be in the range `[0, l_size - 1]`. 886 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 887 The default reordering is to interlace elements. 888 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 889 890 @return An error code: 0 - success, otherwise - failure 891 892 @ref Backend 893 **/ 894 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedInt comp_stride, 895 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 896 CeedElemRestriction *rstr) { 897 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 898 899 if (!ceed->ElemRestrictionCreateBlocked) { 900 Ceed delegate; 901 902 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 903 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlocked"); 904 CeedCall(CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 905 rstr)); 906 return CEED_ERROR_SUCCESS; 907 } 908 909 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 910 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 911 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 912 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 913 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 914 915 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 916 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 917 918 CeedCall(CeedCalloc(1, rstr)); 919 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 920 (*rstr)->ref_count = 1; 921 (*rstr)->num_elem = num_elem; 922 (*rstr)->elem_size = elem_size; 923 (*rstr)->num_comp = num_comp; 924 (*rstr)->comp_stride = comp_stride; 925 (*rstr)->l_size = l_size; 926 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 927 (*rstr)->num_block = num_block; 928 (*rstr)->block_size = block_size; 929 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 930 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, NULL, *rstr)); 931 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 932 return CEED_ERROR_SUCCESS; 933 } 934 935 /** 936 @brief Create a blocked oriented `CeedElemRestriction`, typically only used by backends 937 938 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 939 @param[in] num_elem Number of elements described in the `offsets` array. 940 @param[in] elem_size Size (number of unknowns) per element 941 @param[in] block_size Number of elements in a block 942 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 943 @param[in] comp_stride Stride between components for the same L-vector "node". 944 Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`. 945 @param[in] l_size The size of the L-vector. 946 This vector may be larger than the elements and fields given by this restriction. 947 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 948 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 949 @param[in] offsets Array of shape `[num_elem, elem_size]`. 950 Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`. 951 All offsets must be in the range `[0, l_size - 1]`. 952 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 953 The default reordering is to interlace elements. 954 @param[in] orients Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation. 955 Will also be permuted and padded similarly to `offsets`. 956 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 957 958 @return An error code: 0 - success, otherwise - failure 959 960 @ref Backend 961 **/ 962 int CeedElemRestrictionCreateBlockedOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, 963 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 964 const CeedInt *offsets, const bool *orients, CeedElemRestriction *rstr) { 965 bool *block_orients; 966 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 967 968 if (!ceed->ElemRestrictionCreateBlocked) { 969 Ceed delegate; 970 971 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 972 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedOriented"); 973 CeedCall(CeedElemRestrictionCreateBlockedOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, 974 offsets, orients, rstr)); 975 return CEED_ERROR_SUCCESS; 976 } 977 978 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 979 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 980 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 981 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 982 983 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 984 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_orients)); 985 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 986 CeedCall(CeedPermutePadOrients(orients, block_orients, num_block, num_elem, block_size, elem_size)); 987 988 CeedCall(CeedCalloc(1, rstr)); 989 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 990 (*rstr)->ref_count = 1; 991 (*rstr)->num_elem = num_elem; 992 (*rstr)->elem_size = elem_size; 993 (*rstr)->num_comp = num_comp; 994 (*rstr)->comp_stride = comp_stride; 995 (*rstr)->l_size = l_size; 996 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 997 (*rstr)->num_block = num_block; 998 (*rstr)->block_size = block_size; 999 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 1000 CeedCall( 1001 ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, (const bool *)block_orients, NULL, *rstr)); 1002 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 1003 return CEED_ERROR_SUCCESS; 1004 } 1005 1006 /** 1007 @brief Create a blocked curl-oriented `CeedElemRestriction`, typically only used by backends 1008 1009 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 1010 @param[in] num_elem Number of elements described in the `offsets` array. 1011 @param[in] elem_size Size (number of unknowns) per element 1012 @param[in] block_size Number of elements in a block 1013 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 1014 @param[in] comp_stride Stride between components for the same L-vector "node". 1015 Data for node `i`, component `j`, element `k` can be found in the L-vector at index `offsets[i + k*elem_size] + j*comp_stride`. 1016 @param[in] l_size The size of the L-vector. 1017 This vector may be larger than the elements and fields given by this restriction. 1018 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 1019 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 1020 @param[in] offsets Array of shape `[num_elem, elem_size]`. 1021 Row `i` holds the ordered list of the offsets (into the input `CeedVector`) for the unknowns corresponding to element `i`, where `0 <= i < num_elem`. 1022 All offsets must be in the range `[0, l_size - 1]`. 1023 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 1024 The default reordering is to interlace elements. 1025 @param[in] curl_orients Array of shape `[num_elem, 3 * elem_size]` representing a row-major tridiagonal matrix (`curl_orients[i * 3 * elem_size] = curl_orients[(i + 1) * 3 * elem_size - 1] = 0`, where `0 <= i < num_elem`) which is applied to the element unknowns upon restriction. 1026 This orientation matrix allows for pairs of face degrees of freedom on elements for \f$H(\mathrm{curl})\f$ spaces to be coupled in the element restriction operation, which is a way to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456). 1027 Will also be permuted and padded similarly to offsets. 1028 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 1029 1030 @return An error code: 0 - success, otherwise - failure 1031 1032 @ref Backend 1033 **/ 1034 int CeedElemRestrictionCreateBlockedCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, 1035 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 1036 const CeedInt *offsets, const CeedInt8 *curl_orients, CeedElemRestriction *rstr) { 1037 CeedInt8 *block_curl_orients; 1038 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 1039 1040 if (!ceed->ElemRestrictionCreateBlocked) { 1041 Ceed delegate; 1042 1043 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 1044 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedCurlOriented"); 1045 CeedCall(CeedElemRestrictionCreateBlockedCurlOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, 1046 copy_mode, offsets, curl_orients, rstr)); 1047 return CEED_ERROR_SUCCESS; 1048 } 1049 1050 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 1051 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1052 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1053 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1054 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 1055 1056 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 1057 CeedCall(CeedCalloc(num_block * block_size * 3 * elem_size, &block_curl_orients)); 1058 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 1059 CeedCall(CeedPermutePadCurlOrients(curl_orients, block_curl_orients, num_block, num_elem, block_size, 3 * elem_size)); 1060 1061 CeedCall(CeedCalloc(1, rstr)); 1062 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1063 (*rstr)->ref_count = 1; 1064 (*rstr)->num_elem = num_elem; 1065 (*rstr)->elem_size = elem_size; 1066 (*rstr)->num_comp = num_comp; 1067 (*rstr)->comp_stride = comp_stride; 1068 (*rstr)->l_size = l_size; 1069 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1070 (*rstr)->num_block = num_block; 1071 (*rstr)->block_size = block_size; 1072 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 1073 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, 1074 (const CeedInt8 *)block_curl_orients, *rstr)); 1075 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 1076 return CEED_ERROR_SUCCESS; 1077 } 1078 1079 /** 1080 @brief Create a blocked strided `CeedElemRestriction`, typically only used by backends 1081 1082 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 1083 @param[in] num_elem Number of elements described by the restriction 1084 @param[in] elem_size Size (number of "nodes") per element 1085 @param[in] block_size Number of elements in a block 1086 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 1087 @param[in] l_size The size of the L-vector. 1088 This vector may be larger than the elements and fields given by this restriction. 1089 @param[in] strides Array for strides between `[nodes, components, elements]`. 1090 Data for node `i`, component `j`, element `k` can be found in the L-vector at index `i*strides[0] + j*strides[1] +k*strides[2]`. 1091 @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend. 1092 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 1093 1094 @return An error code: 0 - success, otherwise - failure 1095 1096 @ref User 1097 **/ 1098 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedSize l_size, 1099 const CeedInt strides[3], CeedElemRestriction *rstr) { 1100 CeedInt num_block = (num_elem / block_size) + !!(num_elem % block_size); 1101 1102 if (!ceed->ElemRestrictionCreateBlocked) { 1103 Ceed delegate; 1104 1105 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 1106 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedStrided"); 1107 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, block_size, num_comp, l_size, strides, rstr)); 1108 return CEED_ERROR_SUCCESS; 1109 } 1110 1111 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 1112 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1113 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1114 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1115 CeedCheck(l_size >= (CeedSize)num_elem * elem_size * num_comp, ceed, CEED_ERROR_DIMENSION, 1116 "L-vector size must be at least num_elem * elem_size * num_comp"); 1117 1118 CeedCall(CeedCalloc(1, rstr)); 1119 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1120 (*rstr)->ref_count = 1; 1121 (*rstr)->num_elem = num_elem; 1122 (*rstr)->elem_size = elem_size; 1123 (*rstr)->num_comp = num_comp; 1124 (*rstr)->l_size = l_size; 1125 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1126 (*rstr)->num_block = num_block; 1127 (*rstr)->block_size = block_size; 1128 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 1129 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 1130 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 1131 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 1132 return CEED_ERROR_SUCCESS; 1133 } 1134 1135 /** 1136 @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unsigned version. 1137 1138 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1139 1140 @param[in] rstr `CeedElemRestriction` to create unsigned reference to 1141 @param[in,out] rstr_unsigned Variable to store unsigned `CeedElemRestriction` 1142 1143 @return An error code: 0 - success, otherwise - failure 1144 1145 @ref User 1146 **/ 1147 int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) { 1148 CeedCall(CeedCalloc(1, rstr_unsigned)); 1149 1150 // Copy old rstr 1151 memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private)); 1152 (*rstr_unsigned)->ceed = NULL; 1153 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed)); 1154 (*rstr_unsigned)->ref_count = 1; 1155 (*rstr_unsigned)->strides = NULL; 1156 if (rstr->strides) { 1157 CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides)); 1158 for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i]; 1159 } 1160 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_base)); 1161 1162 // Override Apply 1163 (*rstr_unsigned)->Apply = rstr->ApplyUnsigned; 1164 return CEED_ERROR_SUCCESS; 1165 } 1166 1167 /** 1168 @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unoriented version. 1169 1170 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1171 1172 @param[in] rstr `CeedElemRestriction` to create unoriented reference to 1173 @param[in,out] rstr_unoriented Variable to store unoriented `CeedElemRestriction` 1174 1175 @return An error code: 0 - success, otherwise - failure 1176 1177 @ref User 1178 **/ 1179 int CeedElemRestrictionCreateUnorientedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unoriented) { 1180 CeedCall(CeedCalloc(1, rstr_unoriented)); 1181 1182 // Copy old rstr 1183 memcpy(*rstr_unoriented, rstr, sizeof(struct CeedElemRestriction_private)); 1184 (*rstr_unoriented)->ceed = NULL; 1185 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unoriented)->ceed)); 1186 (*rstr_unoriented)->ref_count = 1; 1187 (*rstr_unoriented)->strides = NULL; 1188 if (rstr->strides) { 1189 CeedCall(CeedMalloc(3, &(*rstr_unoriented)->strides)); 1190 for (CeedInt i = 0; i < 3; i++) (*rstr_unoriented)->strides[i] = rstr->strides[i]; 1191 } 1192 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unoriented)->rstr_base)); 1193 1194 // Override Apply 1195 (*rstr_unoriented)->Apply = rstr->ApplyUnoriented; 1196 return CEED_ERROR_SUCCESS; 1197 } 1198 1199 /** 1200 @brief Copy the pointer to a `CeedElemRestriction`. 1201 1202 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1203 1204 Note: If the value of `*rstr_copy` passed into this function is non-`NULL`, then it is assumed that `*rstr_copy` is a pointer to a `CeedElemRestriction`. 1205 This `CeedElemRestriction` will be destroyed if `*rstr_copy` is the only reference to this `CeedElemRestriction`. 1206 1207 @param[in] rstr `CeedElemRestriction` to copy reference to 1208 @param[in,out] rstr_copy Variable to store copied reference 1209 1210 @return An error code: 0 - success, otherwise - failure 1211 1212 @ref User 1213 **/ 1214 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 1215 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 1216 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 1217 *rstr_copy = rstr; 1218 return CEED_ERROR_SUCCESS; 1219 } 1220 1221 /** 1222 @brief Create `CeedVector` associated with a `CeedElemRestriction` 1223 1224 @param[in] rstr `CeedElemRestriction` 1225 @param[out] l_vec The address of the L-vector to be created, or `NULL` 1226 @param[out] e_vec The address of the E-vector to be created, or `NULL` 1227 1228 @return An error code: 0 - success, otherwise - failure 1229 1230 @ref User 1231 **/ 1232 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 1233 CeedSize e_size, l_size; 1234 Ceed ceed; 1235 1236 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1237 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 1238 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &e_size)); 1239 if (l_vec) CeedCall(CeedVectorCreate(ceed, l_size, l_vec)); 1240 if (e_vec) CeedCall(CeedVectorCreate(ceed, e_size, e_vec)); 1241 return CEED_ERROR_SUCCESS; 1242 } 1243 1244 /** 1245 @brief Restrict an L-vector to an E-vector or apply its transpose 1246 1247 @param[in] rstr `CeedElemRestriction` 1248 @param[in] t_mode Apply restriction or transpose 1249 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1250 @param[out] ru Output vector (of shape `[num_elem * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1251 Ordering of the e-vector is decided by the backend. 1252 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1253 1254 @return An error code: 0 - success, otherwise - failure 1255 1256 @ref User 1257 **/ 1258 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 1259 CeedSize min_u_len, min_ru_len, len; 1260 CeedInt num_elem; 1261 Ceed ceed; 1262 1263 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1264 if (t_mode == CEED_NOTRANSPOSE) { 1265 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &min_ru_len)); 1266 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1267 } else { 1268 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &min_u_len)); 1269 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1270 } 1271 CeedCall(CeedVectorGetLength(u, &len)); 1272 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1273 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1274 min_u_len); 1275 CeedCall(CeedVectorGetLength(ru, &len)); 1276 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1277 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1278 min_ru_len); 1279 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1280 if (num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 1281 return CEED_ERROR_SUCCESS; 1282 } 1283 1284 /** 1285 @brief Restrict an L-vector of points to a single element or apply its transpose 1286 1287 @param[in] rstr `CeedElemRestriction` 1288 @param[in] elem Element number in range `[0, num_elem)` 1289 @param[in] t_mode Apply restriction or transpose 1290 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1291 @param[out] ru Output vector (of shape [`num_points * num_comp]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1292 Ordering of the e-vector is decided by the backend. 1293 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1294 1295 @return An error code: 0 - success, otherwise - failure 1296 1297 @ref User 1298 **/ 1299 int CeedElemRestrictionApplyAtPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1300 CeedRequest *request) { 1301 CeedSize min_u_len, min_ru_len, len; 1302 CeedInt num_elem; 1303 Ceed ceed; 1304 1305 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1306 if (t_mode == CEED_NOTRANSPOSE) { 1307 CeedInt num_points, num_comp; 1308 1309 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1310 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1311 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1312 min_ru_len = (CeedSize)num_points * (CeedSize)num_comp; 1313 } else { 1314 CeedInt num_points, num_comp; 1315 1316 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1317 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1318 min_u_len = (CeedSize)num_points * (CeedSize)num_comp; 1319 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1320 } 1321 CeedCall(CeedVectorGetLength(u, &len)); 1322 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1323 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1324 ") for element %" CeedInt_FMT, 1325 len, min_ru_len, min_u_len, elem); 1326 CeedCall(CeedVectorGetLength(ru, &len)); 1327 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1328 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1329 ") for element %" CeedInt_FMT, 1330 len, min_ru_len, min_u_len, elem); 1331 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1332 CeedCheck(elem < num_elem, ceed, CEED_ERROR_DIMENSION, 1333 "Cannot retrieve element %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", elem, elem, num_elem); 1334 if (num_elem > 0) CeedCall(rstr->ApplyAtPointsInElement(rstr, elem, t_mode, u, ru, request)); 1335 return CEED_ERROR_SUCCESS; 1336 } 1337 1338 /** 1339 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 1340 1341 @param[in] rstr `CeedElemRestriction` 1342 @param[in] block Block number to restrict to/from, i.e. `block = 0` will handle elements `[0 : block_size]` and `block = 3` will handle elements `[3*block_size : 4*block_size]` 1343 @param[in] t_mode Apply restriction or transpose 1344 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1345 @param[out] ru Output vector (of shape `[block_size * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1346 Ordering of the e-vector is decided by the backend. 1347 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1348 1349 @return An error code: 0 - success, otherwise - failure 1350 1351 @ref Backend 1352 **/ 1353 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1354 CeedRequest *request) { 1355 CeedSize min_u_len, min_ru_len, len; 1356 CeedInt block_size, num_elem; 1357 Ceed ceed; 1358 1359 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1360 CeedCheck(rstr->ApplyBlock, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionApplyBlock"); 1361 1362 CeedCall(CeedElemRestrictionGetBlockSize(rstr, &block_size)); 1363 if (t_mode == CEED_NOTRANSPOSE) { 1364 CeedInt elem_size, num_comp; 1365 1366 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1367 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1368 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1369 min_ru_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1370 } else { 1371 CeedInt elem_size, num_comp; 1372 1373 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1374 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1375 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1376 min_u_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1377 } 1378 CeedCall(CeedVectorGetLength(u, &len)); 1379 CeedCheck(min_u_len == len, ceed, CEED_ERROR_DIMENSION, 1380 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1381 min_ru_len); 1382 CeedCall(CeedVectorGetLength(ru, &len)); 1383 CeedCheck(min_ru_len == len, ceed, CEED_ERROR_DIMENSION, 1384 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1385 min_u_len); 1386 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1387 CeedCheck(block_size * block <= num_elem, ceed, CEED_ERROR_DIMENSION, 1388 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, block_size * block, 1389 num_elem); 1390 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 1391 return CEED_ERROR_SUCCESS; 1392 } 1393 1394 /** 1395 @brief Get the `Ceed` associated with a `CeedElemRestriction` 1396 1397 @param[in] rstr `CeedElemRestriction` 1398 @param[out] ceed Variable to store `Ceed` 1399 1400 @return An error code: 0 - success, otherwise - failure 1401 1402 @ref Advanced 1403 **/ 1404 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 1405 *ceed = CeedElemRestrictionReturnCeed(rstr); 1406 return CEED_ERROR_SUCCESS; 1407 } 1408 1409 /** 1410 @brief Return the `Ceed` associated with a `CeedElemRestriction` 1411 1412 @param[in] rstr `CeedElemRestriction` 1413 1414 @return `Ceed` associated with the `rstr` 1415 1416 @ref Advanced 1417 **/ 1418 Ceed CeedElemRestrictionReturnCeed(CeedElemRestriction rstr) { return rstr->ceed; } 1419 1420 /** 1421 @brief Get the L-vector component stride 1422 1423 @param[in] rstr `CeedElemRestriction` 1424 @param[out] comp_stride Variable to store component stride 1425 1426 @return An error code: 0 - success, otherwise - failure 1427 1428 @ref Advanced 1429 **/ 1430 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 1431 *comp_stride = rstr->comp_stride; 1432 return CEED_ERROR_SUCCESS; 1433 } 1434 1435 /** 1436 @brief Get the total number of elements in the range of a `CeedElemRestriction` 1437 1438 @param[in] rstr `CeedElemRestriction` 1439 @param[out] num_elem Variable to store number of elements 1440 1441 @return An error code: 0 - success, otherwise - failure 1442 1443 @ref Advanced 1444 **/ 1445 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 1446 *num_elem = rstr->num_elem; 1447 return CEED_ERROR_SUCCESS; 1448 } 1449 1450 /** 1451 @brief Get the size of elements in the `CeedElemRestriction` 1452 1453 @param[in] rstr `CeedElemRestriction` 1454 @param[out] elem_size Variable to store size of elements 1455 1456 @return An error code: 0 - success, otherwise - failure 1457 1458 @ref Advanced 1459 **/ 1460 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 1461 *elem_size = rstr->elem_size; 1462 return CEED_ERROR_SUCCESS; 1463 } 1464 1465 /** 1466 1467 @brief Get the number of points in the l-vector for a points `CeedElemRestriction` 1468 1469 @param[in] rstr `CeedElemRestriction` 1470 @param[out] num_points The number of points in the l-vector 1471 1472 @return An error code: 0 - success, otherwise - failure 1473 1474 @ref User 1475 **/ 1476 int CeedElemRestrictionGetNumPoints(CeedElemRestriction rstr, CeedInt *num_points) { 1477 CeedRestrictionType rstr_type; 1478 1479 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1480 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1481 "Can only retrieve the number of points for a points CeedElemRestriction"); 1482 1483 *num_points = rstr->num_points; 1484 return CEED_ERROR_SUCCESS; 1485 } 1486 1487 /** 1488 1489 @brief Get the number of points in an element of a `CeedElemRestriction` at points 1490 1491 @param[in] rstr `CeedElemRestriction` 1492 @param[in] elem Index number of element to retrieve the number of points for 1493 @param[out] num_points The number of points in the element at index elem 1494 1495 @return An error code: 0 - success, otherwise - failure 1496 1497 @ref User 1498 **/ 1499 int CeedElemRestrictionGetNumPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedInt *num_points) { 1500 CeedRestrictionType rstr_type; 1501 const CeedInt *offsets; 1502 1503 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1504 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1505 "Can only retrieve the number of points for a points CeedElemRestriction"); 1506 1507 CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets)); 1508 *num_points = offsets[elem + 1] - offsets[elem]; 1509 CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets)); 1510 return CEED_ERROR_SUCCESS; 1511 } 1512 1513 /** 1514 @brief Get the maximum number of points in an element for a `CeedElemRestriction` at points 1515 1516 @param[in] rstr `CeedElemRestriction` 1517 @param[out] max_points Variable to store size of elements 1518 1519 @return An error code: 0 - success, otherwise - failure 1520 1521 @ref Advanced 1522 **/ 1523 int CeedElemRestrictionGetMaxPointsInElement(CeedElemRestriction rstr, CeedInt *max_points) { 1524 CeedInt num_elem; 1525 CeedRestrictionType rstr_type; 1526 1527 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1528 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1529 "Cannot compute max points for a CeedElemRestriction that does not use points"); 1530 1531 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1532 *max_points = 0; 1533 for (CeedInt e = 0; e < num_elem; e++) { 1534 CeedInt num_points; 1535 1536 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, e, &num_points)); 1537 *max_points = CeedIntMax(num_points, *max_points); 1538 } 1539 return CEED_ERROR_SUCCESS; 1540 } 1541 1542 /** 1543 @brief Get the size of the l-vector for a `CeedElemRestriction` 1544 1545 @param[in] rstr `CeedElemRestriction` 1546 @param[out] l_size Variable to store l-vector size 1547 1548 @return An error code: 0 - success, otherwise - failure 1549 1550 @ref Advanced 1551 **/ 1552 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 1553 *l_size = rstr->l_size; 1554 return CEED_ERROR_SUCCESS; 1555 } 1556 1557 /** 1558 @brief Get the size of the e-vector for a `CeedElemRestriction` 1559 1560 @param[in] rstr `CeedElemRestriction` 1561 @param[out] e_size Variable to store e-vector size 1562 1563 @return An error code: 0 - success, otherwise - failure 1564 1565 @ref Advanced 1566 **/ 1567 int CeedElemRestrictionGetEVectorSize(CeedElemRestriction rstr, CeedSize *e_size) { 1568 *e_size = rstr->e_size; 1569 return CEED_ERROR_SUCCESS; 1570 } 1571 1572 /** 1573 @brief Get the number of components in the elements of a `CeedElemRestriction` 1574 1575 @param[in] rstr `CeedElemRestriction` 1576 @param[out] num_comp Variable to store number of components 1577 1578 @return An error code: 0 - success, otherwise - failure 1579 1580 @ref Advanced 1581 **/ 1582 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 1583 *num_comp = rstr->num_comp; 1584 return CEED_ERROR_SUCCESS; 1585 } 1586 1587 /** 1588 @brief Get the number of blocks in a `CeedElemRestriction` 1589 1590 @param[in] rstr `CeedElemRestriction` 1591 @param[out] num_block Variable to store number of blocks 1592 1593 @return An error code: 0 - success, otherwise - failure 1594 1595 @ref Advanced 1596 **/ 1597 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 1598 *num_block = rstr->num_block; 1599 return CEED_ERROR_SUCCESS; 1600 } 1601 1602 /** 1603 @brief Get the size of blocks in the `CeedElemRestriction` 1604 1605 @param[in] rstr `CeedElemRestriction` 1606 @param[out] block_size Variable to store size of blocks 1607 1608 @return An error code: 0 - success, otherwise - failure 1609 1610 @ref Advanced 1611 **/ 1612 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *block_size) { 1613 *block_size = rstr->block_size; 1614 return CEED_ERROR_SUCCESS; 1615 } 1616 1617 /** 1618 @brief Get the multiplicity of nodes in a `CeedElemRestriction` 1619 1620 @param[in] rstr `CeedElemRestriction` 1621 @param[out] mult Vector to store multiplicity (of size `l_size`) 1622 1623 @return An error code: 0 - success, otherwise - failure 1624 1625 @ref User 1626 **/ 1627 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 1628 CeedVector e_vec; 1629 1630 // Create e_vec to hold intermediate computation in E^T (E 1) 1631 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 1632 1633 // Compute e_vec = E * 1 1634 CeedCall(CeedVectorSetValue(mult, 1.0)); 1635 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 1636 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 1637 CeedCall(CeedVectorSetValue(mult, 0.0)); 1638 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 1639 // Cleanup 1640 CeedCall(CeedVectorDestroy(&e_vec)); 1641 return CEED_ERROR_SUCCESS; 1642 } 1643 1644 /** 1645 @brief View a `CeedElemRestriction` 1646 1647 @param[in] rstr `CeedElemRestriction` to view 1648 @param[in] stream Stream to write; typically `stdout` or a file 1649 1650 @return Error code: 0 - success, otherwise - failure 1651 1652 @ref User 1653 **/ 1654 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 1655 CeedRestrictionType rstr_type; 1656 1657 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1658 if (rstr_type == CEED_RESTRICTION_POINTS) { 1659 CeedInt max_points; 1660 1661 CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr, &max_points)); 1662 fprintf(stream, 1663 "CeedElemRestriction at points from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with a maximum of %" CeedInt_FMT 1664 " points on an element\n", 1665 rstr->l_size, rstr->num_comp, rstr->num_elem, max_points); 1666 } else { 1667 char strides_str[500]; 1668 1669 if (rstr->strides) { 1670 sprintf(strides_str, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 1671 } else { 1672 sprintf(strides_str, "%" CeedInt_FMT, rstr->comp_stride); 1673 } 1674 fprintf(stream, 1675 "%sCeedElemRestriction from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT 1676 " nodes each and %s %s\n", 1677 rstr->block_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 1678 rstr->strides ? "strides" : "component stride", strides_str); 1679 } 1680 return CEED_ERROR_SUCCESS; 1681 } 1682 1683 /** 1684 @brief Destroy a `CeedElemRestriction` 1685 1686 @param[in,out] rstr `CeedElemRestriction` to destroy 1687 1688 @return An error code: 0 - success, otherwise - failure 1689 1690 @ref User 1691 **/ 1692 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 1693 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 1694 *rstr = NULL; 1695 return CEED_ERROR_SUCCESS; 1696 } 1697 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 1698 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 1699 1700 // Only destroy backend data once between rstr and unsigned copy 1701 if ((*rstr)->rstr_base) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_base)); 1702 else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 1703 1704 CeedCall(CeedFree(&(*rstr)->strides)); 1705 CeedCall(CeedDestroy(&(*rstr)->ceed)); 1706 CeedCall(CeedFree(rstr)); 1707 return CEED_ERROR_SUCCESS; 1708 } 1709 1710 /// @} 1711