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 implement 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 implement 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 implement 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)->comp_stride = 1; 861 (*rstr)->l_size = l_size; 862 (*rstr)->e_size = (CeedSize)num_points * (CeedSize)num_comp; 863 (*rstr)->num_block = num_elem; 864 (*rstr)->block_size = 1; 865 (*rstr)->rstr_type = CEED_RESTRICTION_POINTS; 866 CeedCall(ceed->ElemRestrictionCreateAtPoints(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 867 return CEED_ERROR_SUCCESS; 868 } 869 870 /** 871 @brief Create a blocked `CeedElemRestriction`, typically only used by backends 872 873 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 874 @param[in] num_elem Number of elements described in the `offsets` array 875 @param[in] elem_size Size (number of unknowns) per element 876 @param[in] block_size Number of elements in a block 877 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 878 @param[in] comp_stride Stride between components for the same L-vector "node". 879 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`. 880 @param[in] l_size The size of the L-vector. 881 This vector may be larger than the elements and fields given by this restriction. 882 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 883 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 884 @param[in] offsets Array of shape `[num_elem, elem_size]`. 885 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`. 886 All offsets must be in the range `[0, l_size - 1]`. 887 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 888 The default reordering is to interlace elements. 889 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 890 891 @return An error code: 0 - success, otherwise - failure 892 893 @ref Backend 894 **/ 895 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedInt comp_stride, 896 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 897 CeedElemRestriction *rstr) { 898 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 899 900 if (!ceed->ElemRestrictionCreateBlocked) { 901 Ceed delegate; 902 903 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 904 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlocked"); 905 CeedCall(CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 906 rstr)); 907 return CEED_ERROR_SUCCESS; 908 } 909 910 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 911 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 912 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 913 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 914 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 915 916 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 917 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 918 919 CeedCall(CeedCalloc(1, rstr)); 920 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 921 (*rstr)->ref_count = 1; 922 (*rstr)->num_elem = num_elem; 923 (*rstr)->elem_size = elem_size; 924 (*rstr)->num_comp = num_comp; 925 (*rstr)->comp_stride = comp_stride; 926 (*rstr)->l_size = l_size; 927 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 928 (*rstr)->num_block = num_block; 929 (*rstr)->block_size = block_size; 930 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 931 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, NULL, *rstr)); 932 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 933 return CEED_ERROR_SUCCESS; 934 } 935 936 /** 937 @brief Create a blocked oriented `CeedElemRestriction`, typically only used by backends 938 939 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 940 @param[in] num_elem Number of elements described in the `offsets` array. 941 @param[in] elem_size Size (number of unknowns) per element 942 @param[in] block_size Number of elements in a block 943 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 944 @param[in] comp_stride Stride between components for the same L-vector "node". 945 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`. 946 @param[in] l_size The size of the L-vector. 947 This vector may be larger than the elements and fields given by this restriction. 948 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 949 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 950 @param[in] offsets Array of shape `[num_elem, elem_size]`. 951 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`. 952 All offsets must be in the range `[0, l_size - 1]`. 953 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 954 The default reordering is to interlace elements. 955 @param[in] orients Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation. 956 Will also be permuted and padded similarly to `offsets`. 957 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 958 959 @return An error code: 0 - success, otherwise - failure 960 961 @ref Backend 962 **/ 963 int CeedElemRestrictionCreateBlockedOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, 964 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 965 const CeedInt *offsets, const bool *orients, CeedElemRestriction *rstr) { 966 bool *block_orients; 967 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 968 969 if (!ceed->ElemRestrictionCreateBlocked) { 970 Ceed delegate; 971 972 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 973 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedOriented"); 974 CeedCall(CeedElemRestrictionCreateBlockedOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, 975 offsets, orients, rstr)); 976 return CEED_ERROR_SUCCESS; 977 } 978 979 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 980 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 981 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 982 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 983 984 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 985 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_orients)); 986 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 987 CeedCall(CeedPermutePadOrients(orients, block_orients, num_block, num_elem, block_size, elem_size)); 988 989 CeedCall(CeedCalloc(1, rstr)); 990 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 991 (*rstr)->ref_count = 1; 992 (*rstr)->num_elem = num_elem; 993 (*rstr)->elem_size = elem_size; 994 (*rstr)->num_comp = num_comp; 995 (*rstr)->comp_stride = comp_stride; 996 (*rstr)->l_size = l_size; 997 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 998 (*rstr)->num_block = num_block; 999 (*rstr)->block_size = block_size; 1000 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 1001 CeedCall( 1002 ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, (const bool *)block_orients, NULL, *rstr)); 1003 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 1004 return CEED_ERROR_SUCCESS; 1005 } 1006 1007 /** 1008 @brief Create a blocked curl-oriented `CeedElemRestriction`, typically only used by backends 1009 1010 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 1011 @param[in] num_elem Number of elements described in the `offsets` array. 1012 @param[in] elem_size Size (number of unknowns) per element 1013 @param[in] block_size Number of elements in a block 1014 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 1015 @param[in] comp_stride Stride between components for the same L-vector "node". 1016 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`. 1017 @param[in] l_size The size of the L-vector. 1018 This vector may be larger than the elements and fields given by this restriction. 1019 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 1020 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 1021 @param[in] offsets Array of shape `[num_elem, elem_size]`. 1022 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`. 1023 All offsets must be in the range `[0, l_size - 1]`. 1024 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 1025 The default reordering is to interlace elements. 1026 @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. 1027 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). 1028 Will also be permuted and padded similarly to offsets. 1029 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 1030 1031 @return An error code: 0 - success, otherwise - failure 1032 1033 @ref Backend 1034 **/ 1035 int CeedElemRestrictionCreateBlockedCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, 1036 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 1037 const CeedInt *offsets, const CeedInt8 *curl_orients, CeedElemRestriction *rstr) { 1038 CeedInt8 *block_curl_orients; 1039 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 1040 1041 if (!ceed->ElemRestrictionCreateBlocked) { 1042 Ceed delegate; 1043 1044 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 1045 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedCurlOriented"); 1046 CeedCall(CeedElemRestrictionCreateBlockedCurlOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, 1047 copy_mode, offsets, curl_orients, rstr)); 1048 return CEED_ERROR_SUCCESS; 1049 } 1050 1051 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 1052 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1053 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1054 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1055 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 1056 1057 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 1058 CeedCall(CeedCalloc(num_block * block_size * 3 * elem_size, &block_curl_orients)); 1059 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 1060 CeedCall(CeedPermutePadCurlOrients(curl_orients, block_curl_orients, num_block, num_elem, block_size, 3 * elem_size)); 1061 1062 CeedCall(CeedCalloc(1, rstr)); 1063 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1064 (*rstr)->ref_count = 1; 1065 (*rstr)->num_elem = num_elem; 1066 (*rstr)->elem_size = elem_size; 1067 (*rstr)->num_comp = num_comp; 1068 (*rstr)->comp_stride = comp_stride; 1069 (*rstr)->l_size = l_size; 1070 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1071 (*rstr)->num_block = num_block; 1072 (*rstr)->block_size = block_size; 1073 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 1074 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, 1075 (const CeedInt8 *)block_curl_orients, *rstr)); 1076 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 1077 return CEED_ERROR_SUCCESS; 1078 } 1079 1080 /** 1081 @brief Create a blocked strided `CeedElemRestriction`, typically only used by backends 1082 1083 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 1084 @param[in] num_elem Number of elements described by the restriction 1085 @param[in] elem_size Size (number of "nodes") per element 1086 @param[in] block_size Number of elements in a block 1087 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 1088 @param[in] l_size The size of the L-vector. 1089 This vector may be larger than the elements and fields given by this restriction. 1090 @param[in] strides Array for strides between `[nodes, components, elements]`. 1091 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]`. 1092 @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend. 1093 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 1094 1095 @return An error code: 0 - success, otherwise - failure 1096 1097 @ref User 1098 **/ 1099 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedSize l_size, 1100 const CeedInt strides[3], CeedElemRestriction *rstr) { 1101 CeedInt num_block = (num_elem / block_size) + !!(num_elem % block_size); 1102 1103 if (!ceed->ElemRestrictionCreateBlocked) { 1104 Ceed delegate; 1105 1106 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 1107 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedStrided"); 1108 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, block_size, num_comp, l_size, strides, rstr)); 1109 return CEED_ERROR_SUCCESS; 1110 } 1111 1112 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 1113 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1114 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1115 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1116 CeedCheck(l_size >= (CeedSize)num_elem * elem_size * num_comp, ceed, CEED_ERROR_DIMENSION, 1117 "L-vector size must be at least num_elem * elem_size * num_comp"); 1118 1119 CeedCall(CeedCalloc(1, rstr)); 1120 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1121 (*rstr)->ref_count = 1; 1122 (*rstr)->num_elem = num_elem; 1123 (*rstr)->elem_size = elem_size; 1124 (*rstr)->num_comp = num_comp; 1125 (*rstr)->l_size = l_size; 1126 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1127 (*rstr)->num_block = num_block; 1128 (*rstr)->block_size = block_size; 1129 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 1130 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 1131 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 1132 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 1133 return CEED_ERROR_SUCCESS; 1134 } 1135 1136 /** 1137 @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unsigned version. 1138 1139 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1140 1141 @param[in] rstr `CeedElemRestriction` to create unsigned reference to 1142 @param[in,out] rstr_unsigned Variable to store unsigned `CeedElemRestriction` 1143 1144 @return An error code: 0 - success, otherwise - failure 1145 1146 @ref User 1147 **/ 1148 int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) { 1149 CeedCall(CeedCalloc(1, rstr_unsigned)); 1150 1151 // Copy old rstr 1152 memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private)); 1153 (*rstr_unsigned)->ceed = NULL; 1154 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed)); 1155 (*rstr_unsigned)->ref_count = 1; 1156 (*rstr_unsigned)->strides = NULL; 1157 if (rstr->strides) { 1158 CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides)); 1159 for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i]; 1160 } 1161 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_base)); 1162 1163 // Override Apply 1164 (*rstr_unsigned)->Apply = rstr->ApplyUnsigned; 1165 return CEED_ERROR_SUCCESS; 1166 } 1167 1168 /** 1169 @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unoriented version. 1170 1171 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1172 1173 @param[in] rstr `CeedElemRestriction` to create unoriented reference to 1174 @param[in,out] rstr_unoriented Variable to store unoriented `CeedElemRestriction` 1175 1176 @return An error code: 0 - success, otherwise - failure 1177 1178 @ref User 1179 **/ 1180 int CeedElemRestrictionCreateUnorientedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unoriented) { 1181 CeedCall(CeedCalloc(1, rstr_unoriented)); 1182 1183 // Copy old rstr 1184 memcpy(*rstr_unoriented, rstr, sizeof(struct CeedElemRestriction_private)); 1185 (*rstr_unoriented)->ceed = NULL; 1186 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unoriented)->ceed)); 1187 (*rstr_unoriented)->ref_count = 1; 1188 (*rstr_unoriented)->strides = NULL; 1189 if (rstr->strides) { 1190 CeedCall(CeedMalloc(3, &(*rstr_unoriented)->strides)); 1191 for (CeedInt i = 0; i < 3; i++) (*rstr_unoriented)->strides[i] = rstr->strides[i]; 1192 } 1193 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unoriented)->rstr_base)); 1194 1195 // Override Apply 1196 (*rstr_unoriented)->Apply = rstr->ApplyUnoriented; 1197 return CEED_ERROR_SUCCESS; 1198 } 1199 1200 /** 1201 @brief Copy the pointer to a `CeedElemRestriction`. 1202 1203 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1204 1205 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`. 1206 This `CeedElemRestriction` will be destroyed if `*rstr_copy` is the only reference to this `CeedElemRestriction`. 1207 1208 @param[in] rstr `CeedElemRestriction` to copy reference to 1209 @param[in,out] rstr_copy Variable to store copied reference 1210 1211 @return An error code: 0 - success, otherwise - failure 1212 1213 @ref User 1214 **/ 1215 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 1216 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 1217 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 1218 *rstr_copy = rstr; 1219 return CEED_ERROR_SUCCESS; 1220 } 1221 1222 /** 1223 @brief Create `CeedVector` associated with a `CeedElemRestriction` 1224 1225 @param[in] rstr `CeedElemRestriction` 1226 @param[out] l_vec The address of the L-vector to be created, or `NULL` 1227 @param[out] e_vec The address of the E-vector to be created, or `NULL` 1228 1229 @return An error code: 0 - success, otherwise - failure 1230 1231 @ref User 1232 **/ 1233 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 1234 CeedSize e_size, l_size; 1235 Ceed ceed; 1236 1237 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1238 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 1239 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &e_size)); 1240 if (l_vec) CeedCall(CeedVectorCreate(ceed, l_size, l_vec)); 1241 if (e_vec) CeedCall(CeedVectorCreate(ceed, e_size, e_vec)); 1242 return CEED_ERROR_SUCCESS; 1243 } 1244 1245 /** 1246 @brief Restrict an L-vector to an E-vector or apply its transpose 1247 1248 @param[in] rstr `CeedElemRestriction` 1249 @param[in] t_mode Apply restriction or transpose 1250 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1251 @param[out] ru Output vector (of shape `[num_elem * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1252 Ordering of the e-vector is decided by the backend. 1253 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1254 1255 @return An error code: 0 - success, otherwise - failure 1256 1257 @ref User 1258 **/ 1259 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 1260 CeedSize min_u_len, min_ru_len, len; 1261 CeedInt num_elem; 1262 Ceed ceed; 1263 1264 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1265 if (t_mode == CEED_NOTRANSPOSE) { 1266 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &min_ru_len)); 1267 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1268 } else { 1269 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &min_u_len)); 1270 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1271 } 1272 CeedCall(CeedVectorGetLength(u, &len)); 1273 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1274 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1275 min_u_len); 1276 CeedCall(CeedVectorGetLength(ru, &len)); 1277 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1278 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1279 min_ru_len); 1280 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1281 if (num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 1282 return CEED_ERROR_SUCCESS; 1283 } 1284 1285 /** 1286 @brief Restrict an L-vector of points to a single element or apply its transpose 1287 1288 @param[in] rstr `CeedElemRestriction` 1289 @param[in] elem Element number in range `[0, num_elem)` 1290 @param[in] t_mode Apply restriction or transpose 1291 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1292 @param[out] ru Output vector (of shape [`num_points * num_comp]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1293 Ordering of the e-vector is decided by the backend. 1294 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1295 1296 @return An error code: 0 - success, otherwise - failure 1297 1298 @ref User 1299 **/ 1300 int CeedElemRestrictionApplyAtPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1301 CeedRequest *request) { 1302 CeedSize min_u_len, min_ru_len, len; 1303 CeedInt num_elem; 1304 Ceed ceed; 1305 1306 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1307 CeedCheck(rstr->ApplyAtPointsInElement, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionApplyAtPointsInElement"); 1308 1309 if (t_mode == CEED_NOTRANSPOSE) { 1310 CeedInt num_points, num_comp; 1311 1312 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1313 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1314 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1315 min_ru_len = (CeedSize)num_points * (CeedSize)num_comp; 1316 } else { 1317 CeedInt num_points, num_comp; 1318 1319 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1320 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1321 min_u_len = (CeedSize)num_points * (CeedSize)num_comp; 1322 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1323 } 1324 CeedCall(CeedVectorGetLength(u, &len)); 1325 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1326 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1327 ") for element %" CeedInt_FMT, 1328 len, min_ru_len, min_u_len, elem); 1329 CeedCall(CeedVectorGetLength(ru, &len)); 1330 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1331 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1332 ") for element %" CeedInt_FMT, 1333 len, min_ru_len, min_u_len, elem); 1334 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1335 CeedCheck(elem < num_elem, ceed, CEED_ERROR_DIMENSION, 1336 "Cannot retrieve element %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", elem, elem, num_elem); 1337 if (num_elem > 0) CeedCall(rstr->ApplyAtPointsInElement(rstr, elem, t_mode, u, ru, request)); 1338 return CEED_ERROR_SUCCESS; 1339 } 1340 1341 /** 1342 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 1343 1344 @param[in] rstr `CeedElemRestriction` 1345 @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]` 1346 @param[in] t_mode Apply restriction or transpose 1347 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1348 @param[out] ru Output vector (of shape `[block_size * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1349 Ordering of the e-vector is decided by the backend. 1350 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1351 1352 @return An error code: 0 - success, otherwise - failure 1353 1354 @ref Backend 1355 **/ 1356 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1357 CeedRequest *request) { 1358 CeedSize min_u_len, min_ru_len, len; 1359 CeedInt block_size, num_elem; 1360 Ceed ceed; 1361 1362 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1363 CeedCheck(rstr->ApplyBlock, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionApplyBlock"); 1364 1365 CeedCall(CeedElemRestrictionGetBlockSize(rstr, &block_size)); 1366 if (t_mode == CEED_NOTRANSPOSE) { 1367 CeedInt elem_size, num_comp; 1368 1369 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1370 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1371 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1372 min_ru_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1373 } else { 1374 CeedInt elem_size, num_comp; 1375 1376 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1377 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1378 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1379 min_u_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1380 } 1381 CeedCall(CeedVectorGetLength(u, &len)); 1382 CeedCheck(min_u_len == len, ceed, CEED_ERROR_DIMENSION, 1383 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1384 min_ru_len); 1385 CeedCall(CeedVectorGetLength(ru, &len)); 1386 CeedCheck(min_ru_len == len, ceed, CEED_ERROR_DIMENSION, 1387 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1388 min_u_len); 1389 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1390 CeedCheck(block_size * block <= num_elem, ceed, CEED_ERROR_DIMENSION, 1391 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, block_size * block, 1392 num_elem); 1393 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 1394 return CEED_ERROR_SUCCESS; 1395 } 1396 1397 /** 1398 @brief Get the `Ceed` associated with a `CeedElemRestriction` 1399 1400 @param[in] rstr `CeedElemRestriction` 1401 @param[out] ceed Variable to store `Ceed` 1402 1403 @return An error code: 0 - success, otherwise - failure 1404 1405 @ref Advanced 1406 **/ 1407 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 1408 *ceed = CeedElemRestrictionReturnCeed(rstr); 1409 return CEED_ERROR_SUCCESS; 1410 } 1411 1412 /** 1413 @brief Return the `Ceed` associated with a `CeedElemRestriction` 1414 1415 @param[in] rstr `CeedElemRestriction` 1416 1417 @return `Ceed` associated with the `rstr` 1418 1419 @ref Advanced 1420 **/ 1421 Ceed CeedElemRestrictionReturnCeed(CeedElemRestriction rstr) { return rstr->ceed; } 1422 1423 /** 1424 @brief Get the L-vector component stride 1425 1426 @param[in] rstr `CeedElemRestriction` 1427 @param[out] comp_stride Variable to store component stride 1428 1429 @return An error code: 0 - success, otherwise - failure 1430 1431 @ref Advanced 1432 **/ 1433 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 1434 *comp_stride = rstr->comp_stride; 1435 return CEED_ERROR_SUCCESS; 1436 } 1437 1438 /** 1439 @brief Get the total number of elements in the range of a `CeedElemRestriction` 1440 1441 @param[in] rstr `CeedElemRestriction` 1442 @param[out] num_elem Variable to store number of elements 1443 1444 @return An error code: 0 - success, otherwise - failure 1445 1446 @ref Advanced 1447 **/ 1448 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 1449 *num_elem = rstr->num_elem; 1450 return CEED_ERROR_SUCCESS; 1451 } 1452 1453 /** 1454 @brief Get the size of elements in the `CeedElemRestriction` 1455 1456 @param[in] rstr `CeedElemRestriction` 1457 @param[out] elem_size Variable to store size of elements 1458 1459 @return An error code: 0 - success, otherwise - failure 1460 1461 @ref Advanced 1462 **/ 1463 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 1464 *elem_size = rstr->elem_size; 1465 return CEED_ERROR_SUCCESS; 1466 } 1467 1468 /** 1469 1470 @brief Get the number of points in the l-vector for a points `CeedElemRestriction` 1471 1472 @param[in] rstr `CeedElemRestriction` 1473 @param[out] num_points The number of points in the l-vector 1474 1475 @return An error code: 0 - success, otherwise - failure 1476 1477 @ref User 1478 **/ 1479 int CeedElemRestrictionGetNumPoints(CeedElemRestriction rstr, CeedInt *num_points) { 1480 CeedRestrictionType rstr_type; 1481 1482 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1483 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1484 "Can only retrieve the number of points for a points CeedElemRestriction"); 1485 1486 *num_points = rstr->num_points; 1487 return CEED_ERROR_SUCCESS; 1488 } 1489 1490 /** 1491 1492 @brief Get the number of points in an element of a `CeedElemRestriction` at points 1493 1494 @param[in] rstr `CeedElemRestriction` 1495 @param[in] elem Index number of element to retrieve the number of points for 1496 @param[out] num_points The number of points in the element at index elem 1497 1498 @return An error code: 0 - success, otherwise - failure 1499 1500 @ref User 1501 **/ 1502 int CeedElemRestrictionGetNumPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedInt *num_points) { 1503 CeedRestrictionType rstr_type; 1504 const CeedInt *offsets; 1505 1506 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1507 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1508 "Can only retrieve the number of points for a points CeedElemRestriction"); 1509 1510 CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets)); 1511 *num_points = offsets[elem + 1] - offsets[elem]; 1512 CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets)); 1513 return CEED_ERROR_SUCCESS; 1514 } 1515 1516 /** 1517 @brief Get the maximum number of points in an element for a `CeedElemRestriction` at points 1518 1519 @param[in] rstr `CeedElemRestriction` 1520 @param[out] max_points Variable to store size of elements 1521 1522 @return An error code: 0 - success, otherwise - failure 1523 1524 @ref Advanced 1525 **/ 1526 int CeedElemRestrictionGetMaxPointsInElement(CeedElemRestriction rstr, CeedInt *max_points) { 1527 CeedInt num_elem; 1528 CeedRestrictionType rstr_type; 1529 1530 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1531 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1532 "Cannot compute max points for a CeedElemRestriction that does not use points"); 1533 1534 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1535 *max_points = 0; 1536 for (CeedInt e = 0; e < num_elem; e++) { 1537 CeedInt num_points; 1538 1539 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, e, &num_points)); 1540 *max_points = CeedIntMax(num_points, *max_points); 1541 } 1542 return CEED_ERROR_SUCCESS; 1543 } 1544 1545 /** 1546 @brief Get the size of the l-vector for a `CeedElemRestriction` 1547 1548 @param[in] rstr `CeedElemRestriction` 1549 @param[out] l_size Variable to store l-vector size 1550 1551 @return An error code: 0 - success, otherwise - failure 1552 1553 @ref Advanced 1554 **/ 1555 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 1556 *l_size = rstr->l_size; 1557 return CEED_ERROR_SUCCESS; 1558 } 1559 1560 /** 1561 @brief Get the size of the e-vector for a `CeedElemRestriction` 1562 1563 @param[in] rstr `CeedElemRestriction` 1564 @param[out] e_size Variable to store e-vector size 1565 1566 @return An error code: 0 - success, otherwise - failure 1567 1568 @ref Advanced 1569 **/ 1570 int CeedElemRestrictionGetEVectorSize(CeedElemRestriction rstr, CeedSize *e_size) { 1571 *e_size = rstr->e_size; 1572 return CEED_ERROR_SUCCESS; 1573 } 1574 1575 /** 1576 @brief Get the number of components in the elements of a `CeedElemRestriction` 1577 1578 @param[in] rstr `CeedElemRestriction` 1579 @param[out] num_comp Variable to store number of components 1580 1581 @return An error code: 0 - success, otherwise - failure 1582 1583 @ref Advanced 1584 **/ 1585 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 1586 *num_comp = rstr->num_comp; 1587 return CEED_ERROR_SUCCESS; 1588 } 1589 1590 /** 1591 @brief Get the number of blocks in a `CeedElemRestriction` 1592 1593 @param[in] rstr `CeedElemRestriction` 1594 @param[out] num_block Variable to store number of blocks 1595 1596 @return An error code: 0 - success, otherwise - failure 1597 1598 @ref Advanced 1599 **/ 1600 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 1601 *num_block = rstr->num_block; 1602 return CEED_ERROR_SUCCESS; 1603 } 1604 1605 /** 1606 @brief Get the size of blocks in the `CeedElemRestriction` 1607 1608 @param[in] rstr `CeedElemRestriction` 1609 @param[out] block_size Variable to store size of blocks 1610 1611 @return An error code: 0 - success, otherwise - failure 1612 1613 @ref Advanced 1614 **/ 1615 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *block_size) { 1616 *block_size = rstr->block_size; 1617 return CEED_ERROR_SUCCESS; 1618 } 1619 1620 /** 1621 @brief Get the multiplicity of nodes in a `CeedElemRestriction` 1622 1623 @param[in] rstr `CeedElemRestriction` 1624 @param[out] mult Vector to store multiplicity (of size `l_size`) 1625 1626 @return An error code: 0 - success, otherwise - failure 1627 1628 @ref User 1629 **/ 1630 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 1631 CeedVector e_vec; 1632 1633 // Create e_vec to hold intermediate computation in E^T (E 1) 1634 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 1635 1636 // Compute e_vec = E * 1 1637 CeedCall(CeedVectorSetValue(mult, 1.0)); 1638 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 1639 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 1640 CeedCall(CeedVectorSetValue(mult, 0.0)); 1641 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 1642 // Cleanup 1643 CeedCall(CeedVectorDestroy(&e_vec)); 1644 return CEED_ERROR_SUCCESS; 1645 } 1646 1647 /** 1648 @brief View a `CeedElemRestriction` 1649 1650 @param[in] rstr `CeedElemRestriction` to view 1651 @param[in] stream Stream to write; typically `stdout` or a file 1652 1653 @return Error code: 0 - success, otherwise - failure 1654 1655 @ref User 1656 **/ 1657 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 1658 CeedRestrictionType rstr_type; 1659 1660 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1661 if (rstr_type == CEED_RESTRICTION_POINTS) { 1662 CeedInt max_points; 1663 1664 CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr, &max_points)); 1665 fprintf(stream, 1666 "CeedElemRestriction at points from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with a maximum of %" CeedInt_FMT 1667 " points on an element\n", 1668 rstr->l_size, rstr->num_comp, rstr->num_elem, max_points); 1669 } else { 1670 char strides_str[500]; 1671 1672 if (rstr->strides) { 1673 sprintf(strides_str, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 1674 } else { 1675 sprintf(strides_str, "%" CeedInt_FMT, rstr->comp_stride); 1676 } 1677 fprintf(stream, 1678 "%sCeedElemRestriction from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT 1679 " nodes each and %s %s\n", 1680 rstr->block_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 1681 rstr->strides ? "strides" : "component stride", strides_str); 1682 } 1683 return CEED_ERROR_SUCCESS; 1684 } 1685 1686 /** 1687 @brief Destroy a `CeedElemRestriction` 1688 1689 @param[in,out] rstr `CeedElemRestriction` to destroy 1690 1691 @return An error code: 0 - success, otherwise - failure 1692 1693 @ref User 1694 **/ 1695 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 1696 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 1697 *rstr = NULL; 1698 return CEED_ERROR_SUCCESS; 1699 } 1700 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 1701 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 1702 1703 // Only destroy backend data once between rstr and unsigned copy 1704 if ((*rstr)->rstr_base) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_base)); 1705 else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 1706 1707 CeedCall(CeedFree(&(*rstr)->strides)); 1708 CeedCall(CeedDestroy(&(*rstr)->ceed)); 1709 CeedCall(CeedFree(rstr)); 1710 return CEED_ERROR_SUCCESS; 1711 } 1712 1713 /// @} 1714