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