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