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 CeedElemRestrictionIsAtPoints(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 473 @brief Set the E-vector size of a `CeedElemRestriction` at points 474 475 @param[in,out] rstr `CeedElemRestriction` 476 @param[in] e_size New E-vector size; must be longer than the current E-vector size 477 478 @return An error code: 0 - success, otherwise - failure 479 480 @ref Backend 481 **/ 482 int CeedElemRestrictionSetAtPointsEVectorSize(CeedElemRestriction rstr, CeedSize e_size) { 483 CeedRestrictionType rstr_type; 484 Ceed ceed; 485 486 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 487 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 488 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_INCOMPATIBLE, "Can only compute offset for a points CeedElemRestriction"); 489 CeedCheck(e_size >= rstr->e_size, ceed, CEED_ERROR_INCOMPATIBLE, "Can only increase the size of the E-vector for the CeedElemRestriction"); 490 rstr->e_size = e_size; 491 return CEED_ERROR_SUCCESS; 492 } 493 494 /** 495 @brief Get the backend data of a `CeedElemRestriction` 496 497 @param[in] rstr `CeedElemRestriction` 498 @param[out] data Variable to store data 499 500 @return An error code: 0 - success, otherwise - failure 501 502 @ref Backend 503 **/ 504 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) { 505 *(void **)data = rstr->data; 506 return CEED_ERROR_SUCCESS; 507 } 508 509 /** 510 @brief Set the backend data of a `CeedElemRestriction` 511 512 @param[in,out] rstr `CeedElemRestriction` 513 @param[in] data Data to set 514 515 @return An error code: 0 - success, otherwise - failure 516 517 @ref Backend 518 **/ 519 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) { 520 rstr->data = data; 521 return CEED_ERROR_SUCCESS; 522 } 523 524 /** 525 @brief Increment the reference counter for a `CeedElemRestriction` 526 527 @param[in,out] rstr `CeedElemRestriction` to increment the reference counter 528 529 @return An error code: 0 - success, otherwise - failure 530 531 @ref Backend 532 **/ 533 int CeedElemRestrictionReference(CeedElemRestriction rstr) { 534 rstr->ref_count++; 535 return CEED_ERROR_SUCCESS; 536 } 537 538 /** 539 @brief Estimate number of FLOPs required to apply `CeedElemRestriction` in `t_mode` 540 541 @param[in] rstr `CeedElemRestriction` to estimate FLOPs for 542 @param[in] t_mode Apply restriction or transpose 543 @param[out] flops Address of variable to hold FLOPs estimate 544 545 @ref Backend 546 **/ 547 int CeedElemRestrictionGetFlopsEstimate(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedSize *flops) { 548 CeedSize e_size, scale = 0; 549 CeedRestrictionType rstr_type; 550 551 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &e_size)); 552 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 553 if (t_mode == CEED_TRANSPOSE) { 554 switch (rstr_type) { 555 case CEED_RESTRICTION_POINTS: 556 scale = 0; 557 break; 558 case CEED_RESTRICTION_STRIDED: 559 case CEED_RESTRICTION_STANDARD: 560 scale = 1; 561 break; 562 case CEED_RESTRICTION_ORIENTED: 563 scale = 2; 564 break; 565 case CEED_RESTRICTION_CURL_ORIENTED: 566 scale = 6; 567 break; 568 } 569 } else { 570 switch (rstr_type) { 571 case CEED_RESTRICTION_STRIDED: 572 case CEED_RESTRICTION_STANDARD: 573 case CEED_RESTRICTION_POINTS: 574 scale = 0; 575 break; 576 case CEED_RESTRICTION_ORIENTED: 577 scale = 1; 578 break; 579 case CEED_RESTRICTION_CURL_ORIENTED: 580 scale = 5; 581 break; 582 } 583 } 584 *flops = e_size * scale; 585 return CEED_ERROR_SUCCESS; 586 } 587 588 /// @} 589 590 /// @cond DOXYGEN_SKIP 591 static struct CeedElemRestriction_private ceed_elemrestriction_none; 592 /// @endcond 593 594 /// ---------------------------------------------------------------------------- 595 /// CeedElemRestriction Public API 596 /// ---------------------------------------------------------------------------- 597 /// @addtogroup CeedElemRestrictionUser 598 /// @{ 599 600 /// Indicate that the stride is determined by the backend 601 const CeedInt CEED_STRIDES_BACKEND[3] = {0}; 602 603 /// Argument for @ref CeedOperatorSetField() indicating that the field does not require a `CeedElemRestriction` 604 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none; 605 606 /** 607 @brief Create a `CeedElemRestriction` 608 609 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 610 @param[in] num_elem Number of elements described in the `offsets` array 611 @param[in] elem_size Size (number of "nodes") per element 612 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 613 @param[in] comp_stride Stride between components for the same L-vector "node". 614 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`. 615 @param[in] l_size The size of the L-vector. 616 This vector may be larger than the elements and fields given by this restriction. 617 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 618 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 619 @param[in] offsets Array of shape `[num_elem, elem_size]`. 620 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. 621 All offsets must be in the range `[0, l_size - 1]`. 622 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 623 624 @return An error code: 0 - success, otherwise - failure 625 626 @ref User 627 **/ 628 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 629 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 630 if (!ceed->ElemRestrictionCreate) { 631 Ceed delegate; 632 633 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 634 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreate"); 635 CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 636 return CEED_ERROR_SUCCESS; 637 } 638 639 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 640 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 641 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 642 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 643 644 CeedCall(CeedCalloc(1, rstr)); 645 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 646 (*rstr)->ref_count = 1; 647 (*rstr)->num_elem = num_elem; 648 (*rstr)->elem_size = elem_size; 649 (*rstr)->num_comp = num_comp; 650 (*rstr)->comp_stride = comp_stride; 651 (*rstr)->l_size = l_size; 652 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 653 (*rstr)->num_block = num_elem; 654 (*rstr)->block_size = 1; 655 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 656 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 657 return CEED_ERROR_SUCCESS; 658 } 659 660 /** 661 @brief Create a `CeedElemRestriction` with orientation signs 662 663 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 664 @param[in] num_elem Number of elements described in the `offsets` array 665 @param[in] elem_size Size (number of "nodes") per element 666 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 667 @param[in] comp_stride Stride between components for the same L-vector "node". 668 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`. 669 @param[in] l_size The size of the L-vector. 670 This vector may be larger than the elements and fields given by this restriction. 671 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 672 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 673 @param[in] offsets Array of shape `[num_elem, elem_size]`. 674 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`. 675 All offsets must be in the range `[0, l_size - 1]`. 676 @param[in] orients Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation 677 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 678 679 @return An error code: 0 - success, otherwise - failure 680 681 @ref User 682 **/ 683 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 684 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orients, 685 CeedElemRestriction *rstr) { 686 if (!ceed->ElemRestrictionCreate) { 687 Ceed delegate; 688 689 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 690 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateOriented"); 691 CeedCall( 692 CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orients, rstr)); 693 return CEED_ERROR_SUCCESS; 694 } 695 696 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 697 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 698 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 699 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 700 701 CeedCall(CeedCalloc(1, rstr)); 702 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 703 (*rstr)->ref_count = 1; 704 (*rstr)->num_elem = num_elem; 705 (*rstr)->elem_size = elem_size; 706 (*rstr)->num_comp = num_comp; 707 (*rstr)->comp_stride = comp_stride; 708 (*rstr)->l_size = l_size; 709 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 710 (*rstr)->num_block = num_elem; 711 (*rstr)->block_size = 1; 712 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 713 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, orients, NULL, *rstr)); 714 return CEED_ERROR_SUCCESS; 715 } 716 717 /** 718 @brief Create a `CeedElemRestriction` with a general tridiagonal transformation matrix for curl-conforming elements 719 720 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 721 @param[in] num_elem Number of elements described in the `offsets` array 722 @param[in] elem_size Size (number of "nodes") per element 723 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 724 @param[in] comp_stride Stride between components for the same L-vector "node". 725 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`. 726 @param[in] l_size The size of the L-vector. 727 This vector may be larger than the elements and fields given by this restriction. 728 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 729 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 730 @param[in] offsets Array of shape `[num_elem, elem_size]`. 731 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`. 732 All offsets must be in the range `[0, l_size - 1]`. 733 @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. 734 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). 735 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 736 737 @return An error code: 0 - success, otherwise - failure 738 739 @ref User 740 **/ 741 int CeedElemRestrictionCreateCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 742 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const CeedInt8 *curl_orients, 743 CeedElemRestriction *rstr) { 744 if (!ceed->ElemRestrictionCreate) { 745 Ceed delegate; 746 747 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 748 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateCurlOriented"); 749 CeedCall(CeedElemRestrictionCreateCurlOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 750 curl_orients, rstr)); 751 return CEED_ERROR_SUCCESS; 752 } 753 754 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 755 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 756 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 757 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 758 759 CeedCall(CeedCalloc(1, rstr)); 760 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 761 (*rstr)->ref_count = 1; 762 (*rstr)->num_elem = num_elem; 763 (*rstr)->elem_size = elem_size; 764 (*rstr)->num_comp = num_comp; 765 (*rstr)->comp_stride = comp_stride; 766 (*rstr)->l_size = l_size; 767 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 768 (*rstr)->num_block = num_elem; 769 (*rstr)->block_size = 1; 770 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 771 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, curl_orients, *rstr)); 772 return CEED_ERROR_SUCCESS; 773 } 774 775 /** 776 @brief Create a strided `CeedElemRestriction` 777 778 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 779 @param[in] num_elem Number of elements described by the restriction 780 @param[in] elem_size Size (number of "nodes") per element 781 @param[in] num_comp Number of field components per interpolation "node" (1 for scalar fields) 782 @param[in] l_size The size of the L-vector. 783 This vector may be larger than the elements and fields given by this restriction. 784 @param[in] strides Array for strides between `[nodes, components, elements]`. 785 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]`. 786 @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend. 787 `CEED_STRIDES_BACKEND` should only be used pass data between `CeedOperator` created with the same `Ceed` backend. 788 The L-vector layout will, in general, be different between `Ceed` backends. 789 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 790 791 @return An error code: 0 - success, otherwise - failure 792 793 @ref User 794 **/ 795 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3], 796 CeedElemRestriction *rstr) { 797 if (!ceed->ElemRestrictionCreate) { 798 Ceed delegate; 799 800 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 801 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateStrided"); 802 CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr)); 803 return CEED_ERROR_SUCCESS; 804 } 805 806 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 807 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 808 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 809 CeedCheck(l_size >= (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp, ceed, CEED_ERROR_DIMENSION, 810 "L-vector size must be at least num_elem * elem_size * num_comp. Expected: > %" CeedSize_FMT " Found: %" CeedSize_FMT, 811 (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp, l_size); 812 813 CeedCall(CeedCalloc(1, rstr)); 814 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 815 (*rstr)->ref_count = 1; 816 (*rstr)->num_elem = num_elem; 817 (*rstr)->elem_size = elem_size; 818 (*rstr)->num_comp = num_comp; 819 (*rstr)->l_size = l_size; 820 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 821 (*rstr)->num_block = num_elem; 822 (*rstr)->block_size = 1; 823 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 824 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 825 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 826 CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 827 return CEED_ERROR_SUCCESS; 828 } 829 830 /** 831 @brief Create a points `CeedElemRestriction`, for restricting for restricting from a all local points to the current element in which they are located. 832 833 The offsets array is arranged as 834 835 element_0_start_index 836 element_1_start_index 837 ... 838 element_n_start_index 839 element_n_stop_index 840 element_0_point_0 841 element_0_point_1 842 ... 843 844 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 845 @param[in] num_elem Number of elements described in the `offsets` array 846 @param[in] num_points Number of points described in the `offsets` array 847 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields). 848 Components are assumed to be contiguous by point. 849 @param[in] l_size The size of the L-vector. 850 This vector may be larger than the elements and fields given by this restriction. 851 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 852 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 853 @param[in] offsets Array of size `num_elem + 1 + num_points`. 854 The first portion of the offsets array holds the ranges of indices corresponding to each element. 855 The second portion holds the indices for each element. 856 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 857 858 @return An error code: 0 - success, otherwise - failure 859 860 @ref Backend 861 **/ 862 int CeedElemRestrictionCreateAtPoints(Ceed ceed, CeedInt num_elem, CeedInt num_points, CeedInt num_comp, CeedSize l_size, CeedMemType mem_type, 863 CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 864 if (!ceed->ElemRestrictionCreateAtPoints) { 865 Ceed delegate; 866 867 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 868 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateAtPoints"); 869 CeedCall(CeedElemRestrictionCreateAtPoints(delegate, num_elem, num_points, num_comp, l_size, mem_type, copy_mode, offsets, rstr)); 870 return CEED_ERROR_SUCCESS; 871 } 872 873 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 874 CeedCheck(num_points >= 0, ceed, CEED_ERROR_DIMENSION, "Number of points must be non-negative"); 875 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 876 CeedCheck(l_size >= (CeedSize)num_points * num_comp, ceed, CEED_ERROR_DIMENSION, 877 "L-vector must be at least num_points * num_comp. Expected: > %" CeedSize_FMT " Found: %" CeedSize_FMT, (CeedSize)num_points * num_comp, 878 l_size); 879 880 CeedCall(CeedCalloc(1, rstr)); 881 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 882 (*rstr)->ref_count = 1; 883 (*rstr)->num_elem = num_elem; 884 (*rstr)->num_points = num_points; 885 (*rstr)->num_comp = num_comp; 886 (*rstr)->comp_stride = 1; 887 (*rstr)->l_size = l_size; 888 (*rstr)->e_size = (CeedSize)num_points * (CeedSize)num_comp; 889 (*rstr)->num_block = num_elem; 890 (*rstr)->block_size = 1; 891 (*rstr)->rstr_type = CEED_RESTRICTION_POINTS; 892 CeedCall(ceed->ElemRestrictionCreateAtPoints(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 893 return CEED_ERROR_SUCCESS; 894 } 895 896 /** 897 @brief Create a blocked `CeedElemRestriction`, typically only used by backends 898 899 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 900 @param[in] num_elem Number of elements described in the `offsets` array 901 @param[in] elem_size Size (number of unknowns) per element 902 @param[in] block_size Number of elements in a block 903 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 904 @param[in] comp_stride Stride between components for the same L-vector "node". 905 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`. 906 @param[in] l_size The size of the L-vector. 907 This vector may be larger than the elements and fields given by this restriction. 908 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 909 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 910 @param[in] offsets Array of shape `[num_elem, elem_size]`. 911 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`. 912 All offsets must be in the range `[0, l_size - 1]`. 913 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 914 The default reordering is to interlace elements. 915 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 916 917 @return An error code: 0 - success, otherwise - failure 918 919 @ref Backend 920 **/ 921 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedInt comp_stride, 922 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 923 CeedElemRestriction *rstr) { 924 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 925 926 if (!ceed->ElemRestrictionCreateBlocked) { 927 Ceed delegate; 928 929 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 930 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlocked"); 931 CeedCall(CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 932 rstr)); 933 return CEED_ERROR_SUCCESS; 934 } 935 936 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 937 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 938 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 939 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 940 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 941 942 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 943 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 944 945 CeedCall(CeedCalloc(1, rstr)); 946 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 947 (*rstr)->ref_count = 1; 948 (*rstr)->num_elem = num_elem; 949 (*rstr)->elem_size = elem_size; 950 (*rstr)->num_comp = num_comp; 951 (*rstr)->comp_stride = comp_stride; 952 (*rstr)->l_size = l_size; 953 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 954 (*rstr)->num_block = num_block; 955 (*rstr)->block_size = block_size; 956 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 957 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, NULL, *rstr)); 958 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 959 return CEED_ERROR_SUCCESS; 960 } 961 962 /** 963 @brief Create a blocked oriented `CeedElemRestriction`, typically only used by backends 964 965 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 966 @param[in] num_elem Number of elements described in the `offsets` array. 967 @param[in] elem_size Size (number of unknowns) per element 968 @param[in] block_size Number of elements in a block 969 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 970 @param[in] comp_stride Stride between components for the same L-vector "node". 971 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`. 972 @param[in] l_size The size of the L-vector. 973 This vector may be larger than the elements and fields given by this restriction. 974 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 975 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 976 @param[in] offsets Array of shape `[num_elem, elem_size]`. 977 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`. 978 All offsets must be in the range `[0, l_size - 1]`. 979 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 980 The default reordering is to interlace elements. 981 @param[in] orients Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation. 982 Will also be permuted and padded similarly to `offsets`. 983 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 984 985 @return An error code: 0 - success, otherwise - failure 986 987 @ref Backend 988 **/ 989 int CeedElemRestrictionCreateBlockedOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, 990 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 991 const CeedInt *offsets, const bool *orients, CeedElemRestriction *rstr) { 992 bool *block_orients; 993 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 994 995 if (!ceed->ElemRestrictionCreateBlocked) { 996 Ceed delegate; 997 998 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 999 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedOriented"); 1000 CeedCall(CeedElemRestrictionCreateBlockedOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, 1001 offsets, orients, rstr)); 1002 return CEED_ERROR_SUCCESS; 1003 } 1004 1005 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1006 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1007 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1008 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 1009 1010 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 1011 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_orients)); 1012 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 1013 CeedCall(CeedPermutePadOrients(orients, block_orients, num_block, num_elem, block_size, elem_size)); 1014 1015 CeedCall(CeedCalloc(1, rstr)); 1016 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1017 (*rstr)->ref_count = 1; 1018 (*rstr)->num_elem = num_elem; 1019 (*rstr)->elem_size = elem_size; 1020 (*rstr)->num_comp = num_comp; 1021 (*rstr)->comp_stride = comp_stride; 1022 (*rstr)->l_size = l_size; 1023 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1024 (*rstr)->num_block = num_block; 1025 (*rstr)->block_size = block_size; 1026 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 1027 CeedCall( 1028 ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, (const bool *)block_orients, NULL, *rstr)); 1029 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 1030 return CEED_ERROR_SUCCESS; 1031 } 1032 1033 /** 1034 @brief Create a blocked curl-oriented `CeedElemRestriction`, typically only used by backends 1035 1036 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 1037 @param[in] num_elem Number of elements described in the `offsets` array. 1038 @param[in] elem_size Size (number of unknowns) per element 1039 @param[in] block_size Number of elements in a block 1040 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 1041 @param[in] comp_stride Stride between components for the same L-vector "node". 1042 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`. 1043 @param[in] l_size The size of the L-vector. 1044 This vector may be larger than the elements and fields given by this restriction. 1045 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 1046 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 1047 @param[in] offsets Array of shape `[num_elem, elem_size]`. 1048 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`. 1049 All offsets must be in the range `[0, l_size - 1]`. 1050 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 1051 The default reordering is to interlace elements. 1052 @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. 1053 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). 1054 Will also be permuted and padded similarly to offsets. 1055 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 1056 1057 @return An error code: 0 - success, otherwise - failure 1058 1059 @ref Backend 1060 **/ 1061 int CeedElemRestrictionCreateBlockedCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, 1062 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 1063 const CeedInt *offsets, const CeedInt8 *curl_orients, CeedElemRestriction *rstr) { 1064 CeedInt8 *block_curl_orients; 1065 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 1066 1067 if (!ceed->ElemRestrictionCreateBlocked) { 1068 Ceed delegate; 1069 1070 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 1071 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedCurlOriented"); 1072 CeedCall(CeedElemRestrictionCreateBlockedCurlOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, 1073 copy_mode, offsets, curl_orients, rstr)); 1074 return CEED_ERROR_SUCCESS; 1075 } 1076 1077 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 1078 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1079 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1080 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1081 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 1082 1083 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 1084 CeedCall(CeedCalloc(num_block * block_size * 3 * elem_size, &block_curl_orients)); 1085 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 1086 CeedCall(CeedPermutePadCurlOrients(curl_orients, block_curl_orients, num_block, num_elem, block_size, 3 * elem_size)); 1087 1088 CeedCall(CeedCalloc(1, rstr)); 1089 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1090 (*rstr)->ref_count = 1; 1091 (*rstr)->num_elem = num_elem; 1092 (*rstr)->elem_size = elem_size; 1093 (*rstr)->num_comp = num_comp; 1094 (*rstr)->comp_stride = comp_stride; 1095 (*rstr)->l_size = l_size; 1096 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1097 (*rstr)->num_block = num_block; 1098 (*rstr)->block_size = block_size; 1099 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 1100 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, 1101 (const CeedInt8 *)block_curl_orients, *rstr)); 1102 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 1103 return CEED_ERROR_SUCCESS; 1104 } 1105 1106 /** 1107 @brief Create a blocked strided `CeedElemRestriction`, typically only used by backends 1108 1109 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 1110 @param[in] num_elem Number of elements described by the restriction 1111 @param[in] elem_size Size (number of "nodes") per element 1112 @param[in] block_size Number of elements in a block 1113 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 1114 @param[in] l_size The size of the L-vector. 1115 This vector may be larger than the elements and fields given by this restriction. 1116 @param[in] strides Array for strides between `[nodes, components, elements]`. 1117 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]`. 1118 @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend. 1119 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 1120 1121 @return An error code: 0 - success, otherwise - failure 1122 1123 @ref User 1124 **/ 1125 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedSize l_size, 1126 const CeedInt strides[3], CeedElemRestriction *rstr) { 1127 CeedInt num_block = (num_elem / block_size) + !!(num_elem % block_size); 1128 1129 if (!ceed->ElemRestrictionCreateBlocked) { 1130 Ceed delegate; 1131 1132 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 1133 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedStrided"); 1134 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, block_size, num_comp, l_size, strides, rstr)); 1135 return CEED_ERROR_SUCCESS; 1136 } 1137 1138 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 1139 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1140 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1141 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1142 CeedCheck(l_size >= (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp, ceed, CEED_ERROR_DIMENSION, 1143 "L-vector size must be at least num_elem * elem_size * num_comp. Expected: > %" CeedSize_FMT " Found: %" CeedSize_FMT, 1144 (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp, l_size); 1145 1146 CeedCall(CeedCalloc(1, rstr)); 1147 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1148 (*rstr)->ref_count = 1; 1149 (*rstr)->num_elem = num_elem; 1150 (*rstr)->elem_size = elem_size; 1151 (*rstr)->num_comp = num_comp; 1152 (*rstr)->l_size = l_size; 1153 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1154 (*rstr)->num_block = num_block; 1155 (*rstr)->block_size = block_size; 1156 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 1157 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 1158 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 1159 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 1160 return CEED_ERROR_SUCCESS; 1161 } 1162 1163 /** 1164 @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unsigned version. 1165 1166 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1167 1168 @param[in] rstr `CeedElemRestriction` to create unsigned reference to 1169 @param[in,out] rstr_unsigned Variable to store unsigned `CeedElemRestriction` 1170 1171 @return An error code: 0 - success, otherwise - failure 1172 1173 @ref User 1174 **/ 1175 int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) { 1176 CeedCall(CeedCalloc(1, rstr_unsigned)); 1177 1178 // Copy old rstr 1179 memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private)); 1180 (*rstr_unsigned)->ceed = NULL; 1181 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed)); 1182 (*rstr_unsigned)->ref_count = 1; 1183 (*rstr_unsigned)->strides = NULL; 1184 if (rstr->strides) { 1185 CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides)); 1186 for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i]; 1187 } 1188 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_base)); 1189 1190 // Override Apply 1191 (*rstr_unsigned)->Apply = rstr->ApplyUnsigned; 1192 return CEED_ERROR_SUCCESS; 1193 } 1194 1195 /** 1196 @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unoriented version. 1197 1198 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1199 1200 @param[in] rstr `CeedElemRestriction` to create unoriented reference to 1201 @param[in,out] rstr_unoriented Variable to store unoriented `CeedElemRestriction` 1202 1203 @return An error code: 0 - success, otherwise - failure 1204 1205 @ref User 1206 **/ 1207 int CeedElemRestrictionCreateUnorientedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unoriented) { 1208 CeedCall(CeedCalloc(1, rstr_unoriented)); 1209 1210 // Copy old rstr 1211 memcpy(*rstr_unoriented, rstr, sizeof(struct CeedElemRestriction_private)); 1212 (*rstr_unoriented)->ceed = NULL; 1213 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unoriented)->ceed)); 1214 (*rstr_unoriented)->ref_count = 1; 1215 (*rstr_unoriented)->strides = NULL; 1216 if (rstr->strides) { 1217 CeedCall(CeedMalloc(3, &(*rstr_unoriented)->strides)); 1218 for (CeedInt i = 0; i < 3; i++) (*rstr_unoriented)->strides[i] = rstr->strides[i]; 1219 } 1220 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unoriented)->rstr_base)); 1221 1222 // Override Apply 1223 (*rstr_unoriented)->Apply = rstr->ApplyUnoriented; 1224 return CEED_ERROR_SUCCESS; 1225 } 1226 1227 /** 1228 @brief Copy the pointer to a `CeedElemRestriction`. 1229 1230 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1231 1232 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`. 1233 This `CeedElemRestriction` will be destroyed if `*rstr_copy` is the only reference to this `CeedElemRestriction`. 1234 1235 @param[in] rstr `CeedElemRestriction` to copy reference to 1236 @param[in,out] rstr_copy Variable to store copied reference 1237 1238 @return An error code: 0 - success, otherwise - failure 1239 1240 @ref User 1241 **/ 1242 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 1243 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 1244 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 1245 *rstr_copy = rstr; 1246 return CEED_ERROR_SUCCESS; 1247 } 1248 1249 /** 1250 @brief Create `CeedVector` associated with a `CeedElemRestriction` 1251 1252 @param[in] rstr `CeedElemRestriction` 1253 @param[out] l_vec The address of the L-vector to be created, or `NULL` 1254 @param[out] e_vec The address of the E-vector to be created, or `NULL` 1255 1256 @return An error code: 0 - success, otherwise - failure 1257 1258 @ref User 1259 **/ 1260 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 1261 CeedSize e_size, l_size; 1262 Ceed ceed; 1263 1264 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1265 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 1266 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &e_size)); 1267 if (l_vec) CeedCall(CeedVectorCreate(ceed, l_size, l_vec)); 1268 if (e_vec) CeedCall(CeedVectorCreate(ceed, e_size, e_vec)); 1269 return CEED_ERROR_SUCCESS; 1270 } 1271 1272 /** 1273 @brief Restrict an L-vector to an E-vector or apply its transpose 1274 1275 @param[in] rstr `CeedElemRestriction` 1276 @param[in] t_mode Apply restriction or transpose 1277 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1278 @param[out] ru Output vector (of shape `[num_elem * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1279 Ordering of the e-vector is decided by the backend. 1280 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1281 1282 @return An error code: 0 - success, otherwise - failure 1283 1284 @ref User 1285 **/ 1286 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 1287 CeedSize min_u_len, min_ru_len, len; 1288 CeedInt num_elem; 1289 Ceed ceed; 1290 1291 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1292 if (t_mode == CEED_NOTRANSPOSE) { 1293 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &min_ru_len)); 1294 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1295 } else { 1296 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &min_u_len)); 1297 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1298 } 1299 CeedCall(CeedVectorGetLength(u, &len)); 1300 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1301 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1302 min_u_len); 1303 CeedCall(CeedVectorGetLength(ru, &len)); 1304 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1305 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1306 min_ru_len); 1307 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1308 if (num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 1309 return CEED_ERROR_SUCCESS; 1310 } 1311 1312 /** 1313 @brief Restrict an L-vector of points to a single element or apply its transpose 1314 1315 @param[in] rstr `CeedElemRestriction` 1316 @param[in] elem Element number in range `[0, num_elem)` 1317 @param[in] t_mode Apply restriction or transpose 1318 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1319 @param[out] ru Output vector (of shape [`num_points * num_comp]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1320 Ordering of the e-vector is decided by the backend. 1321 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1322 1323 @return An error code: 0 - success, otherwise - failure 1324 1325 @ref User 1326 **/ 1327 int CeedElemRestrictionApplyAtPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1328 CeedRequest *request) { 1329 CeedSize min_u_len, min_ru_len, len; 1330 CeedInt num_elem; 1331 Ceed ceed; 1332 1333 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1334 CeedCheck(rstr->ApplyAtPointsInElement, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionApplyAtPointsInElement"); 1335 1336 if (t_mode == CEED_NOTRANSPOSE) { 1337 CeedInt num_points, num_comp; 1338 1339 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1340 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1341 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1342 min_ru_len = (CeedSize)num_points * (CeedSize)num_comp; 1343 } else { 1344 CeedInt num_points, num_comp; 1345 1346 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1347 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1348 min_u_len = (CeedSize)num_points * (CeedSize)num_comp; 1349 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1350 } 1351 CeedCall(CeedVectorGetLength(u, &len)); 1352 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1353 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1354 ") for element %" CeedInt_FMT, 1355 len, min_ru_len, min_u_len, elem); 1356 CeedCall(CeedVectorGetLength(ru, &len)); 1357 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1358 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1359 ") for element %" CeedInt_FMT, 1360 len, min_ru_len, min_u_len, elem); 1361 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1362 CeedCheck(elem < num_elem, ceed, CEED_ERROR_DIMENSION, 1363 "Cannot retrieve element %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", elem, elem, num_elem); 1364 if (num_elem > 0) CeedCall(rstr->ApplyAtPointsInElement(rstr, elem, t_mode, u, ru, request)); 1365 return CEED_ERROR_SUCCESS; 1366 } 1367 1368 /** 1369 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 1370 1371 @param[in] rstr `CeedElemRestriction` 1372 @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]` 1373 @param[in] t_mode Apply restriction or transpose 1374 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1375 @param[out] ru Output vector (of shape `[block_size * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1376 Ordering of the e-vector is decided by the backend. 1377 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1378 1379 @return An error code: 0 - success, otherwise - failure 1380 1381 @ref Backend 1382 **/ 1383 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1384 CeedRequest *request) { 1385 CeedSize min_u_len, min_ru_len, len; 1386 CeedInt block_size, num_elem; 1387 Ceed ceed; 1388 1389 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1390 CeedCheck(rstr->ApplyBlock, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionApplyBlock"); 1391 1392 CeedCall(CeedElemRestrictionGetBlockSize(rstr, &block_size)); 1393 if (t_mode == CEED_NOTRANSPOSE) { 1394 CeedInt elem_size, num_comp; 1395 1396 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1397 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1398 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1399 min_ru_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1400 } else { 1401 CeedInt elem_size, num_comp; 1402 1403 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1404 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1405 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1406 min_u_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1407 } 1408 CeedCall(CeedVectorGetLength(u, &len)); 1409 CeedCheck(min_u_len == len, ceed, CEED_ERROR_DIMENSION, 1410 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1411 min_ru_len); 1412 CeedCall(CeedVectorGetLength(ru, &len)); 1413 CeedCheck(min_ru_len == len, ceed, CEED_ERROR_DIMENSION, 1414 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1415 min_u_len); 1416 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1417 CeedCheck(block_size * block <= num_elem, ceed, CEED_ERROR_DIMENSION, 1418 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, block_size * block, 1419 num_elem); 1420 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 1421 return CEED_ERROR_SUCCESS; 1422 } 1423 1424 /** 1425 @brief Get the `Ceed` associated with a `CeedElemRestriction` 1426 1427 @param[in] rstr `CeedElemRestriction` 1428 @param[out] ceed Variable to store `Ceed` 1429 1430 @return An error code: 0 - success, otherwise - failure 1431 1432 @ref Advanced 1433 **/ 1434 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 1435 *ceed = CeedElemRestrictionReturnCeed(rstr); 1436 return CEED_ERROR_SUCCESS; 1437 } 1438 1439 /** 1440 @brief Return the `Ceed` associated with a `CeedElemRestriction` 1441 1442 @param[in] rstr `CeedElemRestriction` 1443 1444 @return `Ceed` associated with the `rstr` 1445 1446 @ref Advanced 1447 **/ 1448 Ceed CeedElemRestrictionReturnCeed(CeedElemRestriction rstr) { return rstr->ceed; } 1449 1450 /** 1451 @brief Get the L-vector component stride 1452 1453 @param[in] rstr `CeedElemRestriction` 1454 @param[out] comp_stride Variable to store component stride 1455 1456 @return An error code: 0 - success, otherwise - failure 1457 1458 @ref Advanced 1459 **/ 1460 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 1461 *comp_stride = rstr->comp_stride; 1462 return CEED_ERROR_SUCCESS; 1463 } 1464 1465 /** 1466 @brief Get the total number of elements in the range of a `CeedElemRestriction` 1467 1468 @param[in] rstr `CeedElemRestriction` 1469 @param[out] num_elem Variable to store number of elements 1470 1471 @return An error code: 0 - success, otherwise - failure 1472 1473 @ref Advanced 1474 **/ 1475 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 1476 *num_elem = rstr->num_elem; 1477 return CEED_ERROR_SUCCESS; 1478 } 1479 1480 /** 1481 @brief Get the size of elements in the `CeedElemRestriction` 1482 1483 @param[in] rstr `CeedElemRestriction` 1484 @param[out] elem_size Variable to store size of elements 1485 1486 @return An error code: 0 - success, otherwise - failure 1487 1488 @ref Advanced 1489 **/ 1490 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 1491 *elem_size = rstr->elem_size; 1492 return CEED_ERROR_SUCCESS; 1493 } 1494 1495 /** 1496 1497 @brief Get the number of points in the offsets array for a points `CeedElemRestriction` 1498 1499 @param[in] rstr `CeedElemRestriction` 1500 @param[out] num_points The number of points in the offsets array 1501 1502 @return An error code: 0 - success, otherwise - failure 1503 1504 @ref User 1505 **/ 1506 int CeedElemRestrictionGetNumPoints(CeedElemRestriction rstr, CeedInt *num_points) { 1507 CeedRestrictionType rstr_type; 1508 1509 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1510 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1511 "Can only retrieve the number of points for a points CeedElemRestriction"); 1512 1513 *num_points = rstr->num_points; 1514 return CEED_ERROR_SUCCESS; 1515 } 1516 1517 /** 1518 1519 @brief Get the number of points in an element of a `CeedElemRestriction` at points 1520 1521 @param[in] rstr `CeedElemRestriction` 1522 @param[in] elem Index number of element to retrieve the number of points for 1523 @param[out] num_points The number of points in the element at index elem 1524 1525 @return An error code: 0 - success, otherwise - failure 1526 1527 @ref User 1528 **/ 1529 int CeedElemRestrictionGetNumPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedInt *num_points) { 1530 CeedRestrictionType rstr_type; 1531 const CeedInt *offsets; 1532 1533 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1534 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1535 "Can only retrieve the number of points for a points CeedElemRestriction"); 1536 1537 CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets)); 1538 *num_points = offsets[elem + 1] - offsets[elem]; 1539 CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets)); 1540 return CEED_ERROR_SUCCESS; 1541 } 1542 1543 /** 1544 @brief Get the maximum number of points in an element for a `CeedElemRestriction` at points 1545 1546 @param[in] rstr `CeedElemRestriction` 1547 @param[out] max_points Variable to store size of elements 1548 1549 @return An error code: 0 - success, otherwise - failure 1550 1551 @ref Advanced 1552 **/ 1553 int CeedElemRestrictionGetMaxPointsInElement(CeedElemRestriction rstr, CeedInt *max_points) { 1554 CeedInt num_elem; 1555 CeedRestrictionType rstr_type; 1556 1557 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1558 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, CeedElemRestrictionReturnCeed(rstr), CEED_ERROR_INCOMPATIBLE, 1559 "Cannot compute max points for a CeedElemRestriction that does not use points"); 1560 1561 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1562 *max_points = 0; 1563 for (CeedInt e = 0; e < num_elem; e++) { 1564 CeedInt num_points; 1565 1566 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, e, &num_points)); 1567 *max_points = CeedIntMax(num_points, *max_points); 1568 } 1569 return CEED_ERROR_SUCCESS; 1570 } 1571 1572 /** 1573 @brief Get the size of the l-vector for a `CeedElemRestriction` 1574 1575 @param[in] rstr `CeedElemRestriction` 1576 @param[out] l_size Variable to store l-vector size 1577 1578 @return An error code: 0 - success, otherwise - failure 1579 1580 @ref Advanced 1581 **/ 1582 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 1583 *l_size = rstr->l_size; 1584 return CEED_ERROR_SUCCESS; 1585 } 1586 1587 /** 1588 @brief Get the size of the e-vector for a `CeedElemRestriction` 1589 1590 @param[in] rstr `CeedElemRestriction` 1591 @param[out] e_size Variable to store e-vector size 1592 1593 @return An error code: 0 - success, otherwise - failure 1594 1595 @ref Advanced 1596 **/ 1597 int CeedElemRestrictionGetEVectorSize(CeedElemRestriction rstr, CeedSize *e_size) { 1598 *e_size = rstr->e_size; 1599 return CEED_ERROR_SUCCESS; 1600 } 1601 1602 /** 1603 @brief Get the number of components in the elements of a `CeedElemRestriction` 1604 1605 @param[in] rstr `CeedElemRestriction` 1606 @param[out] num_comp Variable to store number of components 1607 1608 @return An error code: 0 - success, otherwise - failure 1609 1610 @ref Advanced 1611 **/ 1612 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 1613 *num_comp = rstr->num_comp; 1614 return CEED_ERROR_SUCCESS; 1615 } 1616 1617 /** 1618 @brief Get the number of blocks in a `CeedElemRestriction` 1619 1620 @param[in] rstr `CeedElemRestriction` 1621 @param[out] num_block Variable to store number of blocks 1622 1623 @return An error code: 0 - success, otherwise - failure 1624 1625 @ref Advanced 1626 **/ 1627 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 1628 *num_block = rstr->num_block; 1629 return CEED_ERROR_SUCCESS; 1630 } 1631 1632 /** 1633 @brief Get the size of blocks in the `CeedElemRestriction` 1634 1635 @param[in] rstr `CeedElemRestriction` 1636 @param[out] block_size Variable to store size of blocks 1637 1638 @return An error code: 0 - success, otherwise - failure 1639 1640 @ref Advanced 1641 **/ 1642 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *block_size) { 1643 *block_size = rstr->block_size; 1644 return CEED_ERROR_SUCCESS; 1645 } 1646 1647 /** 1648 @brief Get the multiplicity of nodes in a `CeedElemRestriction` 1649 1650 @param[in] rstr `CeedElemRestriction` 1651 @param[out] mult Vector to store multiplicity (of size `l_size`) 1652 1653 @return An error code: 0 - success, otherwise - failure 1654 1655 @ref User 1656 **/ 1657 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 1658 CeedVector e_vec; 1659 1660 // Create e_vec to hold intermediate computation in E^T (E 1) 1661 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 1662 1663 // Compute e_vec = E * 1 1664 CeedCall(CeedVectorSetValue(mult, 1.0)); 1665 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 1666 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 1667 CeedCall(CeedVectorSetValue(mult, 0.0)); 1668 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 1669 // Cleanup 1670 CeedCall(CeedVectorDestroy(&e_vec)); 1671 return CEED_ERROR_SUCCESS; 1672 } 1673 1674 /** 1675 @brief View a `CeedElemRestriction` 1676 1677 @param[in] rstr `CeedElemRestriction` to view 1678 @param[in] stream Stream to write; typically `stdout` or a file 1679 1680 @return Error code: 0 - success, otherwise - failure 1681 1682 @ref User 1683 **/ 1684 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 1685 CeedRestrictionType rstr_type; 1686 1687 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1688 if (rstr_type == CEED_RESTRICTION_POINTS) { 1689 CeedInt max_points; 1690 1691 CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr, &max_points)); 1692 fprintf(stream, 1693 "CeedElemRestriction at points from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with a maximum of %" CeedInt_FMT 1694 " points on an element\n", 1695 rstr->l_size, rstr->num_comp, rstr->num_elem, max_points); 1696 } else { 1697 char strides_str[500]; 1698 1699 if (rstr->strides) { 1700 sprintf(strides_str, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 1701 } else { 1702 sprintf(strides_str, "%" CeedInt_FMT, rstr->comp_stride); 1703 } 1704 fprintf(stream, 1705 "%sCeedElemRestriction from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT 1706 " nodes each and %s %s\n", 1707 rstr->block_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 1708 rstr->strides ? "strides" : "component stride", strides_str); 1709 } 1710 return CEED_ERROR_SUCCESS; 1711 } 1712 1713 /** 1714 @brief Destroy a `CeedElemRestriction` 1715 1716 @param[in,out] rstr `CeedElemRestriction` to destroy 1717 1718 @return An error code: 0 - success, otherwise - failure 1719 1720 @ref User 1721 **/ 1722 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 1723 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 1724 *rstr = NULL; 1725 return CEED_ERROR_SUCCESS; 1726 } 1727 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 1728 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 1729 1730 // Only destroy backend data once between rstr and unsigned copy 1731 if ((*rstr)->rstr_base) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_base)); 1732 else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 1733 1734 CeedCall(CeedFree(&(*rstr)->strides)); 1735 CeedCall(CeedDestroy(&(*rstr)->ceed)); 1736 CeedCall(CeedFree(rstr)); 1737 return CEED_ERROR_SUCCESS; 1738 } 1739 1740 /// @} 1741