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)->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 if (t_mode == CEED_NOTRANSPOSE) { 1308 CeedInt num_points, num_comp; 1309 1310 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1311 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1312 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1313 min_ru_len = (CeedSize)num_points * (CeedSize)num_comp; 1314 } else { 1315 CeedInt num_points, num_comp; 1316 1317 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1318 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1319 min_u_len = (CeedSize)num_points * (CeedSize)num_comp; 1320 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1321 } 1322 CeedCall(CeedVectorGetLength(u, &len)); 1323 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1324 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1325 ") for element %" CeedInt_FMT, 1326 len, min_ru_len, min_u_len, elem); 1327 CeedCall(CeedVectorGetLength(ru, &len)); 1328 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1329 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1330 ") for element %" CeedInt_FMT, 1331 len, min_ru_len, min_u_len, elem); 1332 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1333 CeedCheck(elem < num_elem, ceed, CEED_ERROR_DIMENSION, 1334 "Cannot retrieve element %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", elem, elem, num_elem); 1335 if (num_elem > 0) CeedCall(rstr->ApplyAtPointsInElement(rstr, elem, t_mode, u, ru, request)); 1336 return CEED_ERROR_SUCCESS; 1337 } 1338 1339 /** 1340 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 1341 1342 @param[in] rstr `CeedElemRestriction` 1343 @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]` 1344 @param[in] t_mode Apply restriction or transpose 1345 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1346 @param[out] ru Output vector (of shape `[block_size * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1347 Ordering of the e-vector is decided by the backend. 1348 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1349 1350 @return An error code: 0 - success, otherwise - failure 1351 1352 @ref Backend 1353 **/ 1354 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1355 CeedRequest *request) { 1356 CeedSize min_u_len, min_ru_len, len; 1357 CeedInt block_size, num_elem; 1358 Ceed ceed; 1359 1360 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1361 CeedCheck(rstr->ApplyBlock, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionApplyBlock"); 1362 1363 CeedCall(CeedElemRestrictionGetBlockSize(rstr, &block_size)); 1364 if (t_mode == CEED_NOTRANSPOSE) { 1365 CeedInt elem_size, num_comp; 1366 1367 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1368 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1369 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1370 min_ru_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1371 } else { 1372 CeedInt elem_size, num_comp; 1373 1374 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1375 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1376 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1377 min_u_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1378 } 1379 CeedCall(CeedVectorGetLength(u, &len)); 1380 CeedCheck(min_u_len == len, ceed, CEED_ERROR_DIMENSION, 1381 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1382 min_ru_len); 1383 CeedCall(CeedVectorGetLength(ru, &len)); 1384 CeedCheck(min_ru_len == len, ceed, CEED_ERROR_DIMENSION, 1385 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1386 min_u_len); 1387 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1388 CeedCheck(block_size * block <= num_elem, ceed, CEED_ERROR_DIMENSION, 1389 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, block_size * block, 1390 num_elem); 1391 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 1392 return CEED_ERROR_SUCCESS; 1393 } 1394 1395 /** 1396 @brief Get the `Ceed` associated with a `CeedElemRestriction` 1397 1398 @param[in] rstr `CeedElemRestriction` 1399 @param[out] ceed Variable to store `Ceed` 1400 1401 @return An error code: 0 - success, otherwise - failure 1402 1403 @ref Advanced 1404 **/ 1405 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 1406 *ceed = CeedElemRestrictionReturnCeed(rstr); 1407 return CEED_ERROR_SUCCESS; 1408 } 1409 1410 /** 1411 @brief Return the `Ceed` associated with a `CeedElemRestriction` 1412 1413 @param[in] rstr `CeedElemRestriction` 1414 1415 @return `Ceed` associated with the `rstr` 1416 1417 @ref Advanced 1418 **/ 1419 Ceed CeedElemRestrictionReturnCeed(CeedElemRestriction rstr) { return rstr->ceed; } 1420 1421 /** 1422 @brief Get the L-vector component stride 1423 1424 @param[in] rstr `CeedElemRestriction` 1425 @param[out] comp_stride Variable to store component stride 1426 1427 @return An error code: 0 - success, otherwise - failure 1428 1429 @ref Advanced 1430 **/ 1431 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 1432 *comp_stride = rstr->comp_stride; 1433 return CEED_ERROR_SUCCESS; 1434 } 1435 1436 /** 1437 @brief Get the total number of elements in the range of a `CeedElemRestriction` 1438 1439 @param[in] rstr `CeedElemRestriction` 1440 @param[out] num_elem Variable to store number of elements 1441 1442 @return An error code: 0 - success, otherwise - failure 1443 1444 @ref Advanced 1445 **/ 1446 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 1447 *num_elem = rstr->num_elem; 1448 return CEED_ERROR_SUCCESS; 1449 } 1450 1451 /** 1452 @brief Get the size of elements in the `CeedElemRestriction` 1453 1454 @param[in] rstr `CeedElemRestriction` 1455 @param[out] elem_size Variable to store size of elements 1456 1457 @return An error code: 0 - success, otherwise - failure 1458 1459 @ref Advanced 1460 **/ 1461 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 1462 *elem_size = rstr->elem_size; 1463 return CEED_ERROR_SUCCESS; 1464 } 1465 1466 /** 1467 1468 @brief Get the number of points in the l-vector for a points `CeedElemRestriction` 1469 1470 @param[in] rstr `CeedElemRestriction` 1471 @param[out] num_points The number of points in the l-vector 1472 1473 @return An error code: 0 - success, otherwise - failure 1474 1475 @ref User 1476 **/ 1477 int CeedElemRestrictionGetNumPoints(CeedElemRestriction rstr, CeedInt *num_points) { 1478 CeedRestrictionType rstr_type; 1479 1480 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1481 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1482 "Can only retrieve the number of points for a points CeedElemRestriction"); 1483 1484 *num_points = rstr->num_points; 1485 return CEED_ERROR_SUCCESS; 1486 } 1487 1488 /** 1489 1490 @brief Get the number of points in an element of a `CeedElemRestriction` at points 1491 1492 @param[in] rstr `CeedElemRestriction` 1493 @param[in] elem Index number of element to retrieve the number of points for 1494 @param[out] num_points The number of points in the element at index elem 1495 1496 @return An error code: 0 - success, otherwise - failure 1497 1498 @ref User 1499 **/ 1500 int CeedElemRestrictionGetNumPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedInt *num_points) { 1501 CeedRestrictionType rstr_type; 1502 const CeedInt *offsets; 1503 1504 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1505 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1506 "Can only retrieve the number of points for a points CeedElemRestriction"); 1507 1508 CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets)); 1509 *num_points = offsets[elem + 1] - offsets[elem]; 1510 CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets)); 1511 return CEED_ERROR_SUCCESS; 1512 } 1513 1514 /** 1515 @brief Get the maximum number of points in an element for a `CeedElemRestriction` at points 1516 1517 @param[in] rstr `CeedElemRestriction` 1518 @param[out] max_points Variable to store size of elements 1519 1520 @return An error code: 0 - success, otherwise - failure 1521 1522 @ref Advanced 1523 **/ 1524 int CeedElemRestrictionGetMaxPointsInElement(CeedElemRestriction rstr, CeedInt *max_points) { 1525 CeedInt num_elem; 1526 CeedRestrictionType rstr_type; 1527 1528 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1529 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1530 "Cannot compute max points for a CeedElemRestriction that does not use points"); 1531 1532 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1533 *max_points = 0; 1534 for (CeedInt e = 0; e < num_elem; e++) { 1535 CeedInt num_points; 1536 1537 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, e, &num_points)); 1538 *max_points = CeedIntMax(num_points, *max_points); 1539 } 1540 return CEED_ERROR_SUCCESS; 1541 } 1542 1543 /** 1544 @brief Get the size of the l-vector for a `CeedElemRestriction` 1545 1546 @param[in] rstr `CeedElemRestriction` 1547 @param[out] l_size Variable to store l-vector size 1548 1549 @return An error code: 0 - success, otherwise - failure 1550 1551 @ref Advanced 1552 **/ 1553 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 1554 *l_size = rstr->l_size; 1555 return CEED_ERROR_SUCCESS; 1556 } 1557 1558 /** 1559 @brief Get the size of the e-vector for a `CeedElemRestriction` 1560 1561 @param[in] rstr `CeedElemRestriction` 1562 @param[out] e_size Variable to store e-vector size 1563 1564 @return An error code: 0 - success, otherwise - failure 1565 1566 @ref Advanced 1567 **/ 1568 int CeedElemRestrictionGetEVectorSize(CeedElemRestriction rstr, CeedSize *e_size) { 1569 *e_size = rstr->e_size; 1570 return CEED_ERROR_SUCCESS; 1571 } 1572 1573 /** 1574 @brief Get the number of components in the elements of a `CeedElemRestriction` 1575 1576 @param[in] rstr `CeedElemRestriction` 1577 @param[out] num_comp Variable to store number of components 1578 1579 @return An error code: 0 - success, otherwise - failure 1580 1581 @ref Advanced 1582 **/ 1583 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 1584 *num_comp = rstr->num_comp; 1585 return CEED_ERROR_SUCCESS; 1586 } 1587 1588 /** 1589 @brief Get the number of blocks in a `CeedElemRestriction` 1590 1591 @param[in] rstr `CeedElemRestriction` 1592 @param[out] num_block Variable to store number of blocks 1593 1594 @return An error code: 0 - success, otherwise - failure 1595 1596 @ref Advanced 1597 **/ 1598 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 1599 *num_block = rstr->num_block; 1600 return CEED_ERROR_SUCCESS; 1601 } 1602 1603 /** 1604 @brief Get the size of blocks in the `CeedElemRestriction` 1605 1606 @param[in] rstr `CeedElemRestriction` 1607 @param[out] block_size Variable to store size of blocks 1608 1609 @return An error code: 0 - success, otherwise - failure 1610 1611 @ref Advanced 1612 **/ 1613 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *block_size) { 1614 *block_size = rstr->block_size; 1615 return CEED_ERROR_SUCCESS; 1616 } 1617 1618 /** 1619 @brief Get the multiplicity of nodes in a `CeedElemRestriction` 1620 1621 @param[in] rstr `CeedElemRestriction` 1622 @param[out] mult Vector to store multiplicity (of size `l_size`) 1623 1624 @return An error code: 0 - success, otherwise - failure 1625 1626 @ref User 1627 **/ 1628 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 1629 CeedVector e_vec; 1630 1631 // Create e_vec to hold intermediate computation in E^T (E 1) 1632 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 1633 1634 // Compute e_vec = E * 1 1635 CeedCall(CeedVectorSetValue(mult, 1.0)); 1636 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 1637 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 1638 CeedCall(CeedVectorSetValue(mult, 0.0)); 1639 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 1640 // Cleanup 1641 CeedCall(CeedVectorDestroy(&e_vec)); 1642 return CEED_ERROR_SUCCESS; 1643 } 1644 1645 /** 1646 @brief View a `CeedElemRestriction` 1647 1648 @param[in] rstr `CeedElemRestriction` to view 1649 @param[in] stream Stream to write; typically `stdout` or a file 1650 1651 @return Error code: 0 - success, otherwise - failure 1652 1653 @ref User 1654 **/ 1655 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 1656 CeedRestrictionType rstr_type; 1657 1658 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1659 if (rstr_type == CEED_RESTRICTION_POINTS) { 1660 CeedInt max_points; 1661 1662 CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr, &max_points)); 1663 fprintf(stream, 1664 "CeedElemRestriction at points from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with a maximum of %" CeedInt_FMT 1665 " points on an element\n", 1666 rstr->l_size, rstr->num_comp, rstr->num_elem, max_points); 1667 } else { 1668 char strides_str[500]; 1669 1670 if (rstr->strides) { 1671 sprintf(strides_str, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 1672 } else { 1673 sprintf(strides_str, "%" CeedInt_FMT, rstr->comp_stride); 1674 } 1675 fprintf(stream, 1676 "%sCeedElemRestriction from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT 1677 " nodes each and %s %s\n", 1678 rstr->block_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 1679 rstr->strides ? "strides" : "component stride", strides_str); 1680 } 1681 return CEED_ERROR_SUCCESS; 1682 } 1683 1684 /** 1685 @brief Destroy a `CeedElemRestriction` 1686 1687 @param[in,out] rstr `CeedElemRestriction` to destroy 1688 1689 @return An error code: 0 - success, otherwise - failure 1690 1691 @ref User 1692 **/ 1693 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 1694 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 1695 *rstr = NULL; 1696 return CEED_ERROR_SUCCESS; 1697 } 1698 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 1699 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 1700 1701 // Only destroy backend data once between rstr and unsigned copy 1702 if ((*rstr)->rstr_base) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_base)); 1703 else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 1704 1705 CeedCall(CeedFree(&(*rstr)->strides)); 1706 CeedCall(CeedDestroy(&(*rstr)->ceed)); 1707 CeedCall(CeedFree(rstr)); 1708 return CEED_ERROR_SUCCESS; 1709 } 1710 1711 /// @} 1712