1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 8 #include <ceed-impl.h> 9 #include <ceed.h> 10 #include <ceed/backend.h> 11 #include <stdbool.h> 12 #include <stdio.h> 13 #include <string.h> 14 15 /// @file 16 /// Implementation of CeedElemRestriction interfaces 17 18 /// ---------------------------------------------------------------------------- 19 /// CeedElemRestriction Library Internal Functions 20 /// ---------------------------------------------------------------------------- 21 /// @addtogroup CeedElemRestrictionDeveloper 22 /// @{ 23 24 /** 25 @brief Permute and pad offsets for a blocked `CeedElemRestriction` 26 27 @param[in] offsets Array of shape `[num_elem, elem_size]` 28 @param[out] block_offsets Array of permuted and padded array values of shape `[num_block, elem_size, block_size]` 29 @param[in] num_block Number of blocks 30 @param[in] num_elem Number of elements 31 @param[in] block_size Number of elements in a block 32 @param[in] elem_size Size of each element 33 34 @return An error code: 0 - success, otherwise - failure 35 36 @ref Utility 37 **/ 38 int CeedPermutePadOffsets(const CeedInt *offsets, CeedInt *block_offsets, CeedInt num_block, CeedInt num_elem, CeedInt block_size, 39 CeedInt elem_size) { 40 for (CeedInt e = 0; e < num_block * block_size; e += block_size) { 41 for (CeedInt j = 0; j < block_size; j++) { 42 for (CeedInt k = 0; k < elem_size; k++) { 43 block_offsets[e * elem_size + k * block_size + j] = offsets[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 44 } 45 } 46 } 47 return CEED_ERROR_SUCCESS; 48 } 49 50 /** 51 @brief Permute and pad orientations for a blocked `CeedElemRestriction` 52 53 @param[in] orients Array of shape `[num_elem, elem_size]` 54 @param[out] block_orients Array of permuted and padded array values of shape `[num_block, elem_size, block_size]` 55 @param[in] num_block Number of blocks 56 @param[in] num_elem Number of elements 57 @param[in] block_size Number of elements in a block 58 @param[in] elem_size Size of each element 59 60 @return An error code: 0 - success, otherwise - failure 61 62 @ref Utility 63 **/ 64 int CeedPermutePadOrients(const bool *orients, bool *block_orients, CeedInt num_block, CeedInt num_elem, CeedInt block_size, CeedInt elem_size) { 65 for (CeedInt e = 0; e < num_block * block_size; e += block_size) { 66 for (CeedInt j = 0; j < block_size; j++) { 67 for (CeedInt k = 0; k < elem_size; k++) { 68 block_orients[e * elem_size + k * block_size + j] = orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 69 } 70 } 71 } 72 return CEED_ERROR_SUCCESS; 73 } 74 75 /** 76 @brief Permute and pad curl-conforming orientations for a blocked `CeedElemRestriction` 77 78 @param[in] curl_orients Array of shape `[num_elem, elem_size]` 79 @param[out] block_curl_orients Array of permuted and padded array values of shape `[num_block, elem_size, block_size]` 80 @param[in] num_block Number of blocks 81 @param[in] num_elem Number of elements 82 @param[in] block_size Number of elements in a block 83 @param[in] elem_size Size of each element 84 85 @return An error code: 0 - success, otherwise - failure 86 87 @ref Utility 88 **/ 89 int CeedPermutePadCurlOrients(const CeedInt8 *curl_orients, CeedInt8 *block_curl_orients, CeedInt num_block, CeedInt num_elem, CeedInt block_size, 90 CeedInt elem_size) { 91 for (CeedInt e = 0; e < num_block * block_size; e += block_size) { 92 for (CeedInt j = 0; j < block_size; j++) { 93 for (CeedInt k = 0; k < elem_size; k++) { 94 block_curl_orients[e * elem_size + k * block_size + j] = curl_orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 95 } 96 } 97 } 98 return CEED_ERROR_SUCCESS; 99 } 100 101 /// @} 102 103 /// ---------------------------------------------------------------------------- 104 /// CeedElemRestriction Backend API 105 /// ---------------------------------------------------------------------------- 106 /// @addtogroup CeedElemRestrictionBackend 107 /// @{ 108 109 /** 110 @brief Get the type of a `CeedElemRestriction` 111 112 @param[in] rstr `CeedElemRestriction` 113 @param[out] rstr_type Variable to store restriction type 114 115 @return An error code: 0 - success, otherwise - failure 116 117 @ref Backend 118 **/ 119 int CeedElemRestrictionGetType(CeedElemRestriction rstr, CeedRestrictionType *rstr_type) { 120 *rstr_type = rstr->rstr_type; 121 return CEED_ERROR_SUCCESS; 122 } 123 124 /** 125 @brief Get the strided status of a `CeedElemRestriction` 126 127 @param[in] rstr `CeedElemRestriction` 128 @param[out] is_strided Variable to store strided status 129 130 @return An error code: 0 - success, otherwise - failure 131 132 @ref Backend 133 **/ 134 int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) { 135 *is_strided = (rstr->rstr_type == CEED_RESTRICTION_STRIDED); 136 return CEED_ERROR_SUCCESS; 137 } 138 139 /** 140 @brief Get the points status of a `CeedElemRestriction` 141 142 @param[in] rstr `CeedElemRestriction` 143 @param[out] is_points Variable to store points status 144 145 @return An error code: 0 - success, otherwise - failure 146 147 @ref Backend 148 **/ 149 int CeedElemRestrictionIsPoints(CeedElemRestriction rstr, bool *is_points) { 150 *is_points = (rstr->rstr_type == CEED_RESTRICTION_POINTS); 151 return CEED_ERROR_SUCCESS; 152 } 153 154 /** 155 @brief Check if two `CeedElemRestriction` created with @ref CeedElemRestrictionCreateAtPoints() and use the same points per element 156 157 @param[in] rstr_a First `CeedElemRestriction` 158 @param[in] rstr_b Second `CeedElemRestriction` 159 @param[out] are_compatible Variable to store compatibility status 160 161 @return An error code: 0 - success, otherwise - failure 162 163 @ref Backend 164 **/ 165 int CeedElemRestrictionAtPointsAreCompatible(CeedElemRestriction rstr_a, CeedElemRestriction rstr_b, bool *are_compatible) { 166 CeedInt num_elem_a, num_elem_b, num_points_a, num_points_b; 167 Ceed ceed; 168 169 CeedCall(CeedElemRestrictionGetCeed(rstr_a, &ceed)); 170 171 // Cannot compare non-points restrictions 172 CeedCheck(rstr_a->rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_UNSUPPORTED, "First CeedElemRestriction must be AtPoints"); 173 CeedCheck(rstr_b->rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_UNSUPPORTED, "Second CeedElemRestriction must be AtPoints"); 174 175 CeedCall(CeedElemRestrictionGetNumElements(rstr_a, &num_elem_a)); 176 CeedCall(CeedElemRestrictionGetNumElements(rstr_b, &num_elem_b)); 177 CeedCall(CeedElemRestrictionGetNumPoints(rstr_a, &num_points_a)); 178 CeedCall(CeedElemRestrictionGetNumPoints(rstr_b, &num_points_b)); 179 180 // Check size and contents of offsets arrays 181 *are_compatible = true; 182 if (num_elem_a != num_elem_b) *are_compatible = false; 183 if (num_points_a != num_points_b) *are_compatible = false; 184 if (*are_compatible) { 185 const CeedInt *offsets_a, *offsets_b; 186 187 CeedCall(CeedElemRestrictionGetOffsets(rstr_a, CEED_MEM_HOST, &offsets_a)); 188 CeedCall(CeedElemRestrictionGetOffsets(rstr_b, CEED_MEM_HOST, &offsets_b)); 189 for (CeedInt i = 0; i < num_elem_a + 1 + num_points_a; i++) *are_compatible &= offsets_a[i] == offsets_b[i]; 190 CeedCall(CeedElemRestrictionRestoreOffsets(rstr_a, &offsets_a)); 191 CeedCall(CeedElemRestrictionRestoreOffsets(rstr_b, &offsets_b)); 192 } 193 return CEED_ERROR_SUCCESS; 194 } 195 196 /** 197 @brief Get the strides of a strided `CeedElemRestriction` 198 199 @param[in] rstr `CeedElemRestriction` 200 @param[out] strides Variable to store strides array 201 202 @return An error code: 0 - success, otherwise - failure 203 204 @ref Backend 205 **/ 206 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr, CeedInt strides[3]) { 207 Ceed ceed; 208 209 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 210 CeedCheck(rstr->strides, ceed, CEED_ERROR_MINOR, "CeedElemRestriction has no stride data"); 211 for (CeedInt i = 0; i < 3; i++) strides[i] = rstr->strides[i]; 212 return CEED_ERROR_SUCCESS; 213 } 214 215 /** 216 @brief Get the backend stride status of a `CeedElemRestriction` 217 218 @param[in] rstr `CeedElemRestriction` 219 @param[out] has_backend_strides Variable to store stride status 220 221 @return An error code: 0 - success, otherwise - failure 222 223 @ref Backend 224 **/ 225 int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr, bool *has_backend_strides) { 226 Ceed ceed; 227 228 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 229 CeedCheck(rstr->strides, ceed, CEED_ERROR_MINOR, "CeedElemRestriction has no stride data"); 230 *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) && (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) && 231 (rstr->strides[2] == CEED_STRIDES_BACKEND[2])); 232 return CEED_ERROR_SUCCESS; 233 } 234 235 /** 236 @brief Get read-only access to a `CeedElemRestriction` offsets array by @ref CeedMemType 237 238 @param[in] rstr `CeedElemRestriction` to retrieve offsets 239 @param[in] mem_type Memory type on which to access the array. 240 If the backend uses a different memory type, this will perform a copy (possibly cached). 241 @param[out] offsets Array on memory type `mem_type` 242 243 @return An error code: 0 - success, otherwise - failure 244 245 @ref User 246 **/ 247 int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **offsets) { 248 if (rstr->rstr_base) { 249 CeedCall(CeedElemRestrictionGetOffsets(rstr->rstr_base, mem_type, offsets)); 250 } else { 251 Ceed ceed; 252 253 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 254 CeedCheck(rstr->GetOffsets, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedElemRestrictionGetOffsets"); 255 CeedCall(rstr->GetOffsets(rstr, mem_type, offsets)); 256 rstr->num_readers++; 257 } 258 return CEED_ERROR_SUCCESS; 259 } 260 261 /** 262 @brief Restore an offsets array obtained using @ref CeedElemRestrictionGetOffsets() 263 264 @param[in] rstr `CeedElemRestriction` to restore 265 @param[in] offsets Array of offset data 266 267 @return An error code: 0 - success, otherwise - failure 268 269 @ref User 270 **/ 271 int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr, const CeedInt **offsets) { 272 if (rstr->rstr_base) { 273 CeedCall(CeedElemRestrictionRestoreOffsets(rstr->rstr_base, offsets)); 274 } else { 275 *offsets = NULL; 276 rstr->num_readers--; 277 } 278 return CEED_ERROR_SUCCESS; 279 } 280 281 /** 282 @brief Get read-only access to a `CeedElemRestriction` orientations array by @ref CeedMemType 283 284 @param[in] rstr `CeedElemRestriction` to retrieve orientations 285 @param[in] mem_type Memory type on which to access the array. 286 If the backend uses a different memory type, this will perform a copy (possibly cached). 287 @param[out] orients Array on memory type `mem_type` 288 289 @return An error code: 0 - success, otherwise - failure 290 291 @ref User 292 **/ 293 int CeedElemRestrictionGetOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const bool **orients) { 294 Ceed ceed; 295 296 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 297 CeedCheck(rstr->GetOrientations, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedElemRestrictionGetOrientations"); 298 CeedCall(rstr->GetOrientations(rstr, mem_type, orients)); 299 rstr->num_readers++; 300 return CEED_ERROR_SUCCESS; 301 } 302 303 /** 304 @brief Restore an orientations array obtained using @ref CeedElemRestrictionGetOrientations() 305 306 @param[in] rstr `CeedElemRestriction` to restore 307 @param[in] orients Array of orientation data 308 309 @return An error code: 0 - success, otherwise - failure 310 311 @ref User 312 **/ 313 int CeedElemRestrictionRestoreOrientations(CeedElemRestriction rstr, const bool **orients) { 314 *orients = NULL; 315 rstr->num_readers--; 316 return CEED_ERROR_SUCCESS; 317 } 318 319 /** 320 @brief Get read-only access to a `CeedElemRestriction` curl-conforming orientations array by @ref CeedMemType 321 322 @param[in] rstr `CeedElemRestriction` to retrieve curl-conforming orientations 323 @param[in] mem_type Memory type on which to access the array. 324 If the backend uses a different memory type, this will perform a copy (possibly cached). 325 @param[out] curl_orients Array on memory type `mem_type` 326 327 @return An error code: 0 - success, otherwise - failure 328 329 @ref User 330 **/ 331 int CeedElemRestrictionGetCurlOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt8 **curl_orients) { 332 Ceed ceed; 333 334 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 335 CeedCheck(rstr->GetCurlOrientations, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedElemRestrictionGetCurlOrientations"); 336 CeedCall(rstr->GetCurlOrientations(rstr, mem_type, curl_orients)); 337 rstr->num_readers++; 338 return CEED_ERROR_SUCCESS; 339 } 340 341 /** 342 @brief Restore an orientations array obtained using @ref CeedElemRestrictionGetCurlOrientations() 343 344 @param[in] rstr `CeedElemRestriction` to restore 345 @param[in] curl_orients Array of orientation data 346 347 @return An error code: 0 - success, otherwise - failure 348 349 @ref User 350 **/ 351 int CeedElemRestrictionRestoreCurlOrientations(CeedElemRestriction rstr, const CeedInt8 **curl_orients) { 352 *curl_orients = NULL; 353 rstr->num_readers--; 354 return CEED_ERROR_SUCCESS; 355 } 356 357 /** 358 359 @brief Get the L-vector layout of a strided `CeedElemRestriction` 360 361 @param[in] rstr `CeedElemRestriction` 362 @param[out] layout Variable to store layout array, stored as `[nodes, components, elements]`. 363 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]`. 364 365 @return An error code: 0 - success, otherwise - failure 366 367 @ref Backend 368 **/ 369 int CeedElemRestrictionGetLLayout(CeedElemRestriction rstr, CeedInt layout[3]) { 370 bool has_backend_strides; 371 CeedRestrictionType rstr_type; 372 Ceed ceed; 373 374 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 375 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 376 CeedCheck(rstr_type == CEED_RESTRICTION_STRIDED, ceed, CEED_ERROR_MINOR, "Only strided CeedElemRestriction have strided L-vector layout"); 377 CeedCall(CeedElemRestrictionHasBackendStrides(rstr, &has_backend_strides)); 378 if (has_backend_strides) { 379 CeedCheck(rstr->l_layout[0], ceed, CEED_ERROR_MINOR, "CeedElemRestriction has no L-vector layout data"); 380 for (CeedInt i = 0; i < 3; i++) layout[i] = rstr->l_layout[i]; 381 } else { 382 CeedCall(CeedElemRestrictionGetStrides(rstr, layout)); 383 } 384 return CEED_ERROR_SUCCESS; 385 } 386 387 /** 388 389 @brief Set the L-vector layout of a strided `CeedElemRestriction` 390 391 @param[in] rstr `CeedElemRestriction` 392 @param[in] layout Variable to containing layout array, stored as `[nodes, components, elements]`. 393 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]`. 394 395 @return An error code: 0 - success, otherwise - failure 396 397 @ref Backend 398 **/ 399 int CeedElemRestrictionSetLLayout(CeedElemRestriction rstr, CeedInt layout[3]) { 400 CeedRestrictionType rstr_type; 401 Ceed ceed; 402 403 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 404 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 405 CeedCheck(rstr_type == CEED_RESTRICTION_STRIDED, ceed, CEED_ERROR_MINOR, "Only strided CeedElemRestriction have strided L-vector layout"); 406 for (CeedInt i = 0; i < 3; i++) rstr->l_layout[i] = layout[i]; 407 return CEED_ERROR_SUCCESS; 408 } 409 410 /** 411 412 @brief Get the E-vector layout of a `CeedElemRestriction` 413 414 @param[in] rstr `CeedElemRestriction` 415 @param[out] layout Variable to store layout array, stored as `[nodes, components, elements]`. 416 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]`. 417 418 @return An error code: 0 - success, otherwise - failure 419 420 @ref Backend 421 **/ 422 int CeedElemRestrictionGetELayout(CeedElemRestriction rstr, CeedInt layout[3]) { 423 Ceed ceed; 424 425 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 426 CeedCheck(rstr->e_layout[0], ceed, CEED_ERROR_MINOR, "CeedElemRestriction has no E-vector layout data"); 427 for (CeedInt i = 0; i < 3; i++) layout[i] = rstr->e_layout[i]; 428 return CEED_ERROR_SUCCESS; 429 } 430 431 /** 432 433 @brief Set the E-vector layout of a `CeedElemRestriction` 434 435 @param[in] rstr `CeedElemRestriction` 436 @param[in] layout Variable to containing layout array, stored as `[nodes, components, elements]`. 437 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]`. 438 439 @return An error code: 0 - success, otherwise - failure 440 441 @ref Backend 442 **/ 443 int CeedElemRestrictionSetELayout(CeedElemRestriction rstr, CeedInt layout[3]) { 444 for (CeedInt i = 0; i < 3; i++) rstr->e_layout[i] = layout[i]; 445 return CEED_ERROR_SUCCESS; 446 } 447 448 /** 449 @brief Get the backend data of a `CeedElemRestriction` 450 451 @param[in] rstr `CeedElemRestriction` 452 @param[out] data Variable to store data 453 454 @return An error code: 0 - success, otherwise - failure 455 456 @ref Backend 457 **/ 458 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) { 459 *(void **)data = rstr->data; 460 return CEED_ERROR_SUCCESS; 461 } 462 463 /** 464 @brief Set the backend data of a `CeedElemRestriction` 465 466 @param[in,out] rstr `CeedElemRestriction` 467 @param[in] data Data to set 468 469 @return An error code: 0 - success, otherwise - failure 470 471 @ref Backend 472 **/ 473 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) { 474 rstr->data = data; 475 return CEED_ERROR_SUCCESS; 476 } 477 478 /** 479 @brief Increment the reference counter for a `CeedElemRestriction` 480 481 @param[in,out] rstr `CeedElemRestriction` to increment the reference counter 482 483 @return An error code: 0 - success, otherwise - failure 484 485 @ref Backend 486 **/ 487 int CeedElemRestrictionReference(CeedElemRestriction rstr) { 488 rstr->ref_count++; 489 return CEED_ERROR_SUCCESS; 490 } 491 492 /** 493 @brief Estimate number of FLOPs required to apply `CeedElemRestriction` in `t_mode` 494 495 @param[in] rstr `CeedElemRestriction` to estimate FLOPs for 496 @param[in] t_mode Apply restriction or transpose 497 @param[out] flops Address of variable to hold FLOPs estimate 498 499 @ref Backend 500 **/ 501 int CeedElemRestrictionGetFlopsEstimate(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedSize *flops) { 502 CeedSize e_size, scale = 0; 503 CeedRestrictionType rstr_type; 504 505 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &e_size)); 506 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 507 if (t_mode == CEED_TRANSPOSE) { 508 switch (rstr_type) { 509 case CEED_RESTRICTION_POINTS: 510 scale = 0; 511 break; 512 case CEED_RESTRICTION_STRIDED: 513 case CEED_RESTRICTION_STANDARD: 514 scale = 1; 515 break; 516 case CEED_RESTRICTION_ORIENTED: 517 scale = 2; 518 break; 519 case CEED_RESTRICTION_CURL_ORIENTED: 520 scale = 6; 521 break; 522 } 523 } else { 524 switch (rstr_type) { 525 case CEED_RESTRICTION_STRIDED: 526 case CEED_RESTRICTION_STANDARD: 527 case CEED_RESTRICTION_POINTS: 528 scale = 0; 529 break; 530 case CEED_RESTRICTION_ORIENTED: 531 scale = 1; 532 break; 533 case CEED_RESTRICTION_CURL_ORIENTED: 534 scale = 5; 535 break; 536 } 537 } 538 *flops = e_size * scale; 539 return CEED_ERROR_SUCCESS; 540 } 541 542 /// @} 543 544 /// @cond DOXYGEN_SKIP 545 static struct CeedElemRestriction_private ceed_elemrestriction_none; 546 /// @endcond 547 548 /// ---------------------------------------------------------------------------- 549 /// CeedElemRestriction Public API 550 /// ---------------------------------------------------------------------------- 551 /// @addtogroup CeedElemRestrictionUser 552 /// @{ 553 554 /// Indicate that the stride is determined by the backend 555 const CeedInt CEED_STRIDES_BACKEND[3] = {0}; 556 557 /// Argument for @ref CeedOperatorSetField() indicating that the field does not require a `CeedElemRestriction` 558 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none; 559 560 /** 561 @brief Create a `CeedElemRestriction` 562 563 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 564 @param[in] num_elem Number of elements described in the `offsets` array 565 @param[in] elem_size Size (number of "nodes") per element 566 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 567 @param[in] comp_stride Stride between components for the same L-vector "node". 568 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`. 569 @param[in] l_size The size of the L-vector. 570 This vector may be larger than the elements and fields given by this restriction. 571 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 572 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 573 @param[in] offsets Array of shape `[num_elem, elem_size]`. 574 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. 575 All offsets must be in the range `[0, l_size - 1]`. 576 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 577 578 @return An error code: 0 - success, otherwise - failure 579 580 @ref User 581 **/ 582 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 583 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 584 if (!ceed->ElemRestrictionCreate) { 585 Ceed delegate; 586 587 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 588 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreate"); 589 CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 590 return CEED_ERROR_SUCCESS; 591 } 592 593 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 594 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 595 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 596 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 597 598 CeedCall(CeedCalloc(1, rstr)); 599 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 600 (*rstr)->ref_count = 1; 601 (*rstr)->num_elem = num_elem; 602 (*rstr)->elem_size = elem_size; 603 (*rstr)->num_comp = num_comp; 604 (*rstr)->comp_stride = comp_stride; 605 (*rstr)->l_size = l_size; 606 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 607 (*rstr)->num_block = num_elem; 608 (*rstr)->block_size = 1; 609 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 610 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 611 return CEED_ERROR_SUCCESS; 612 } 613 614 /** 615 @brief Create a `CeedElemRestriction` with orientation signs 616 617 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 618 @param[in] num_elem Number of elements described in the `offsets` array 619 @param[in] elem_size Size (number of "nodes") per element 620 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 621 @param[in] comp_stride Stride between components for the same L-vector "node". 622 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`. 623 @param[in] l_size The size of the L-vector. 624 This vector may be larger than the elements and fields given by this restriction. 625 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 626 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 627 @param[in] offsets Array of shape `[num_elem, elem_size]`. 628 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`. 629 All offsets must be in the range `[0, l_size - 1]`. 630 @param[in] orients Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation 631 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 632 633 @return An error code: 0 - success, otherwise - failure 634 635 @ref User 636 **/ 637 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 638 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orients, 639 CeedElemRestriction *rstr) { 640 if (!ceed->ElemRestrictionCreate) { 641 Ceed delegate; 642 643 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 644 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateOriented"); 645 CeedCall( 646 CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orients, rstr)); 647 return CEED_ERROR_SUCCESS; 648 } 649 650 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 651 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 652 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 653 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 654 655 CeedCall(CeedCalloc(1, rstr)); 656 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 657 (*rstr)->ref_count = 1; 658 (*rstr)->num_elem = num_elem; 659 (*rstr)->elem_size = elem_size; 660 (*rstr)->num_comp = num_comp; 661 (*rstr)->comp_stride = comp_stride; 662 (*rstr)->l_size = l_size; 663 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 664 (*rstr)->num_block = num_elem; 665 (*rstr)->block_size = 1; 666 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 667 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, orients, NULL, *rstr)); 668 return CEED_ERROR_SUCCESS; 669 } 670 671 /** 672 @brief Create a `CeedElemRestriction` with a general tridiagonal transformation matrix for curl-conforming elements 673 674 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 675 @param[in] num_elem Number of elements described in the `offsets` array 676 @param[in] elem_size Size (number of "nodes") per element 677 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 678 @param[in] comp_stride Stride between components for the same L-vector "node". 679 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`. 680 @param[in] l_size The size of the L-vector. 681 This vector may be larger than the elements and fields given by this restriction. 682 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 683 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 684 @param[in] offsets Array of shape `[num_elem, elem_size]`. 685 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`. 686 All offsets must be in the range `[0, l_size - 1]`. 687 @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. 688 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). 689 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 690 691 @return An error code: 0 - success, otherwise - failure 692 693 @ref User 694 **/ 695 int CeedElemRestrictionCreateCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 696 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const CeedInt8 *curl_orients, 697 CeedElemRestriction *rstr) { 698 if (!ceed->ElemRestrictionCreate) { 699 Ceed delegate; 700 701 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 702 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateCurlOriented"); 703 CeedCall(CeedElemRestrictionCreateCurlOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 704 curl_orients, rstr)); 705 return CEED_ERROR_SUCCESS; 706 } 707 708 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 709 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 710 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 711 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 712 713 CeedCall(CeedCalloc(1, rstr)); 714 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 715 (*rstr)->ref_count = 1; 716 (*rstr)->num_elem = num_elem; 717 (*rstr)->elem_size = elem_size; 718 (*rstr)->num_comp = num_comp; 719 (*rstr)->comp_stride = comp_stride; 720 (*rstr)->l_size = l_size; 721 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 722 (*rstr)->num_block = num_elem; 723 (*rstr)->block_size = 1; 724 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 725 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, curl_orients, *rstr)); 726 return CEED_ERROR_SUCCESS; 727 } 728 729 /** 730 @brief Create a strided `CeedElemRestriction` 731 732 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 733 @param[in] num_elem Number of elements described by the restriction 734 @param[in] elem_size Size (number of "nodes") per element 735 @param[in] num_comp Number of field components per interpolation "node" (1 for scalar fields) 736 @param[in] l_size The size of the L-vector. 737 This vector may be larger than the elements and fields given by this restriction. 738 @param[in] strides Array for strides between `[nodes, components, elements]`. 739 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]`. 740 @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend. 741 `CEED_STRIDES_BACKEND` should only be used pass data between `CeedOperator` created with the same `Ceed` backend. 742 The L-vector layout will, in general, be different between `Ceed` backends. 743 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 744 745 @return An error code: 0 - success, otherwise - failure 746 747 @ref User 748 **/ 749 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3], 750 CeedElemRestriction *rstr) { 751 if (!ceed->ElemRestrictionCreate) { 752 Ceed delegate; 753 754 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 755 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateStrided"); 756 CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr)); 757 return CEED_ERROR_SUCCESS; 758 } 759 760 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 761 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 762 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 763 CeedCheck(l_size >= num_elem * elem_size * num_comp, ceed, CEED_ERROR_DIMENSION, "L-vector size must be at least num_elem * elem_size * num_comp"); 764 765 CeedCall(CeedCalloc(1, rstr)); 766 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 767 (*rstr)->ref_count = 1; 768 (*rstr)->num_elem = num_elem; 769 (*rstr)->elem_size = elem_size; 770 (*rstr)->num_comp = num_comp; 771 (*rstr)->l_size = l_size; 772 (*rstr)->e_size = (CeedSize)num_elem * (CeedSize)elem_size * (CeedSize)num_comp; 773 (*rstr)->num_block = num_elem; 774 (*rstr)->block_size = 1; 775 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 776 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 777 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 778 CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 779 return CEED_ERROR_SUCCESS; 780 } 781 782 /** 783 @brief Create a points `CeedElemRestriction`, for restricting for restricting from a all local points to the current element in which they are located. 784 785 The offsets array is arranged as 786 787 element_0_start_index 788 element_1_start_index 789 ... 790 element_n_start_index 791 element_n_stop_index 792 element_0_point_0 793 element_0_point_1 794 ... 795 796 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 797 @param[in] num_elem Number of elements described in the `offsets` array 798 @param[in] num_points Number of points described in the `offsets` array 799 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields). 800 Components are assumed to be contiguous by point. 801 @param[in] l_size The size of the L-vector. 802 This vector may be larger than the elements and fields given by this restriction. 803 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 804 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 805 @param[in] offsets Array of size `num_elem + 1 + num_points`. 806 The first portion of the offsets array holds the ranges of indices corresponding to each element. 807 The second portion holds the indices for each element. 808 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 809 810 @return An error code: 0 - success, otherwise - failure 811 812 @ref Backend 813 **/ 814 int CeedElemRestrictionCreateAtPoints(Ceed ceed, CeedInt num_elem, CeedInt num_points, CeedInt num_comp, CeedSize l_size, CeedMemType mem_type, 815 CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 816 if (!ceed->ElemRestrictionCreateAtPoints) { 817 Ceed delegate; 818 819 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 820 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateAtPoints"); 821 CeedCall(CeedElemRestrictionCreateAtPoints(delegate, num_elem, num_points, num_comp, l_size, mem_type, copy_mode, offsets, rstr)); 822 return CEED_ERROR_SUCCESS; 823 } 824 825 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 826 CeedCheck(num_points >= 0, ceed, CEED_ERROR_DIMENSION, "Number of points must be non-negative"); 827 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 828 CeedCheck(l_size >= num_points * num_comp, ceed, CEED_ERROR_DIMENSION, "L-vector must be at least num_points * num_comp"); 829 830 CeedCall(CeedCalloc(1, rstr)); 831 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 832 (*rstr)->ref_count = 1; 833 (*rstr)->num_elem = num_elem; 834 (*rstr)->num_points = num_points; 835 (*rstr)->num_comp = num_comp; 836 (*rstr)->l_size = l_size; 837 (*rstr)->e_size = (CeedSize)num_points * (CeedSize)num_comp; 838 (*rstr)->num_block = num_elem; 839 (*rstr)->block_size = 1; 840 (*rstr)->rstr_type = CEED_RESTRICTION_POINTS; 841 CeedCall(ceed->ElemRestrictionCreateAtPoints(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 842 return CEED_ERROR_SUCCESS; 843 } 844 845 /** 846 @brief Create a blocked `CeedElemRestriction`, typically only used by backends 847 848 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 849 @param[in] num_elem Number of elements described in the `offsets` array 850 @param[in] elem_size Size (number of unknowns) per element 851 @param[in] block_size Number of elements in a block 852 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 853 @param[in] comp_stride Stride between components for the same L-vector "node". 854 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`. 855 @param[in] l_size The size of the L-vector. 856 This vector may be larger than the elements and fields given by this restriction. 857 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 858 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 859 @param[in] offsets Array of shape `[num_elem, elem_size]`. 860 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`. 861 All offsets must be in the range `[0, l_size - 1]`. 862 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 863 The default reordering is to interlace elements. 864 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 865 866 @return An error code: 0 - success, otherwise - failure 867 868 @ref Backend 869 **/ 870 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedInt comp_stride, 871 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 872 CeedElemRestriction *rstr) { 873 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 874 875 if (!ceed->ElemRestrictionCreateBlocked) { 876 Ceed delegate; 877 878 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 879 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlocked"); 880 CeedCall(CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 881 rstr)); 882 return CEED_ERROR_SUCCESS; 883 } 884 885 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 886 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 887 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 888 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 889 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 890 891 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 892 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 893 894 CeedCall(CeedCalloc(1, rstr)); 895 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 896 (*rstr)->ref_count = 1; 897 (*rstr)->num_elem = num_elem; 898 (*rstr)->elem_size = elem_size; 899 (*rstr)->num_comp = num_comp; 900 (*rstr)->comp_stride = comp_stride; 901 (*rstr)->l_size = l_size; 902 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 903 (*rstr)->num_block = num_block; 904 (*rstr)->block_size = block_size; 905 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 906 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, NULL, *rstr)); 907 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 908 return CEED_ERROR_SUCCESS; 909 } 910 911 /** 912 @brief Create a blocked oriented `CeedElemRestriction`, typically only used by backends 913 914 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 915 @param[in] num_elem Number of elements described in the `offsets` array. 916 @param[in] elem_size Size (number of unknowns) per element 917 @param[in] block_size Number of elements in a block 918 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 919 @param[in] comp_stride Stride between components for the same L-vector "node". 920 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`. 921 @param[in] l_size The size of the L-vector. 922 This vector may be larger than the elements and fields given by this restriction. 923 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 924 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 925 @param[in] offsets Array of shape `[num_elem, elem_size]`. 926 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`. 927 All offsets must be in the range `[0, l_size - 1]`. 928 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 929 The default reordering is to interlace elements. 930 @param[in] orients Boolean array of shape `[num_elem, elem_size]` with `false` for positively oriented and `true` to flip the orientation. 931 Will also be permuted and padded similarly to `offsets`. 932 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 933 934 @return An error code: 0 - success, otherwise - failure 935 936 @ref Backend 937 **/ 938 int CeedElemRestrictionCreateBlockedOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, 939 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 940 const CeedInt *offsets, const bool *orients, CeedElemRestriction *rstr) { 941 bool *block_orients; 942 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 943 944 if (!ceed->ElemRestrictionCreateBlocked) { 945 Ceed delegate; 946 947 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 948 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedOriented"); 949 CeedCall(CeedElemRestrictionCreateBlockedOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, copy_mode, 950 offsets, orients, rstr)); 951 return CEED_ERROR_SUCCESS; 952 } 953 954 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 955 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 956 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 957 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 958 959 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 960 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_orients)); 961 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 962 CeedCall(CeedPermutePadOrients(orients, block_orients, num_block, num_elem, block_size, elem_size)); 963 964 CeedCall(CeedCalloc(1, rstr)); 965 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 966 (*rstr)->ref_count = 1; 967 (*rstr)->num_elem = num_elem; 968 (*rstr)->elem_size = elem_size; 969 (*rstr)->num_comp = num_comp; 970 (*rstr)->comp_stride = comp_stride; 971 (*rstr)->l_size = l_size; 972 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 973 (*rstr)->num_block = num_block; 974 (*rstr)->block_size = block_size; 975 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 976 CeedCall( 977 ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, (const bool *)block_orients, NULL, *rstr)); 978 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 979 return CEED_ERROR_SUCCESS; 980 } 981 982 /** 983 @brief Create a blocked curl-oriented `CeedElemRestriction`, typically only used by backends 984 985 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 986 @param[in] num_elem Number of elements described in the `offsets` array. 987 @param[in] elem_size Size (number of unknowns) per element 988 @param[in] block_size Number of elements in a block 989 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 990 @param[in] comp_stride Stride between components for the same L-vector "node". 991 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`. 992 @param[in] l_size The size of the L-vector. 993 This vector may be larger than the elements and fields given by this restriction. 994 @param[in] mem_type Memory type of the `offsets` array, see @ref CeedMemType 995 @param[in] copy_mode Copy mode for the `offsets` array, see @ref CeedCopyMode 996 @param[in] offsets Array of shape `[num_elem, elem_size]`. 997 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`. 998 All offsets must be in the range `[0, l_size - 1]`. 999 The backend will permute and pad this array to the desired ordering for the blocksize, which is typically given by the backend. 1000 The default reordering is to interlace elements. 1001 @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. 1002 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). 1003 Will also be permuted and padded similarly to offsets. 1004 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 1005 1006 @return An error code: 0 - success, otherwise - failure 1007 1008 @ref Backend 1009 **/ 1010 int CeedElemRestrictionCreateBlockedCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, 1011 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 1012 const CeedInt *offsets, const CeedInt8 *curl_orients, CeedElemRestriction *rstr) { 1013 CeedInt8 *block_curl_orients; 1014 CeedInt *block_offsets, num_block = (num_elem / block_size) + !!(num_elem % block_size); 1015 1016 if (!ceed->ElemRestrictionCreateBlocked) { 1017 Ceed delegate; 1018 1019 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 1020 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedCurlOriented"); 1021 CeedCall(CeedElemRestrictionCreateBlockedCurlOriented(delegate, num_elem, elem_size, block_size, num_comp, comp_stride, l_size, mem_type, 1022 copy_mode, offsets, curl_orients, rstr)); 1023 return CEED_ERROR_SUCCESS; 1024 } 1025 1026 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 1027 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1028 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1029 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1030 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction component stride must be at least 1"); 1031 1032 CeedCall(CeedCalloc(num_block * block_size * elem_size, &block_offsets)); 1033 CeedCall(CeedCalloc(num_block * block_size * 3 * elem_size, &block_curl_orients)); 1034 CeedCall(CeedPermutePadOffsets(offsets, block_offsets, num_block, num_elem, block_size, elem_size)); 1035 CeedCall(CeedPermutePadCurlOrients(curl_orients, block_curl_orients, num_block, num_elem, block_size, 3 * elem_size)); 1036 1037 CeedCall(CeedCalloc(1, rstr)); 1038 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1039 (*rstr)->ref_count = 1; 1040 (*rstr)->num_elem = num_elem; 1041 (*rstr)->elem_size = elem_size; 1042 (*rstr)->num_comp = num_comp; 1043 (*rstr)->comp_stride = comp_stride; 1044 (*rstr)->l_size = l_size; 1045 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1046 (*rstr)->num_block = num_block; 1047 (*rstr)->block_size = block_size; 1048 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 1049 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)block_offsets, NULL, 1050 (const CeedInt8 *)block_curl_orients, *rstr)); 1051 if (copy_mode == CEED_OWN_POINTER) CeedCall(CeedFree(&offsets)); 1052 return CEED_ERROR_SUCCESS; 1053 } 1054 1055 /** 1056 @brief Create a blocked strided `CeedElemRestriction`, typically only used by backends 1057 1058 @param[in] ceed `Ceed` context used to create the `CeedElemRestriction` 1059 @param[in] num_elem Number of elements described by the restriction 1060 @param[in] elem_size Size (number of "nodes") per element 1061 @param[in] block_size Number of elements in a block 1062 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 1063 @param[in] l_size The size of the L-vector. 1064 This vector may be larger than the elements and fields given by this restriction. 1065 @param[in] strides Array for strides between `[nodes, components, elements]`. 1066 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]`. 1067 @ref CEED_STRIDES_BACKEND may be used for `CeedVector` ordered by the same `Ceed` backend. 1068 @param[out] rstr Address of the variable where the newly created `CeedElemRestriction` will be stored 1069 1070 @return An error code: 0 - success, otherwise - failure 1071 1072 @ref User 1073 **/ 1074 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt block_size, CeedInt num_comp, CeedSize l_size, 1075 const CeedInt strides[3], CeedElemRestriction *rstr) { 1076 CeedInt num_block = (num_elem / block_size) + !!(num_elem % block_size); 1077 1078 if (!ceed->ElemRestrictionCreateBlocked) { 1079 Ceed delegate; 1080 1081 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 1082 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionCreateBlockedStrided"); 1083 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, block_size, num_comp, l_size, strides, rstr)); 1084 return CEED_ERROR_SUCCESS; 1085 } 1086 1087 CeedCheck(num_elem >= 0, ceed, CEED_ERROR_DIMENSION, "Number of elements must be non-negative"); 1088 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 1089 CeedCheck(block_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 1090 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedElemRestriction must have at least 1 component"); 1091 CeedCheck(l_size >= num_elem * elem_size * num_comp, ceed, CEED_ERROR_DIMENSION, "L-vector size must be at least num_elem * elem_size * num_comp"); 1092 1093 CeedCall(CeedCalloc(1, rstr)); 1094 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 1095 (*rstr)->ref_count = 1; 1096 (*rstr)->num_elem = num_elem; 1097 (*rstr)->elem_size = elem_size; 1098 (*rstr)->num_comp = num_comp; 1099 (*rstr)->l_size = l_size; 1100 (*rstr)->e_size = (CeedSize)num_block * (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1101 (*rstr)->num_block = num_block; 1102 (*rstr)->block_size = block_size; 1103 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 1104 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 1105 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 1106 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 1107 return CEED_ERROR_SUCCESS; 1108 } 1109 1110 /** 1111 @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unsigned version. 1112 1113 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1114 1115 @param[in] rstr `CeedElemRestriction` to create unsigned reference to 1116 @param[in,out] rstr_unsigned Variable to store unsigned `CeedElemRestriction` 1117 1118 @return An error code: 0 - success, otherwise - failure 1119 1120 @ref User 1121 **/ 1122 int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) { 1123 CeedCall(CeedCalloc(1, rstr_unsigned)); 1124 1125 // Copy old rstr 1126 memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private)); 1127 (*rstr_unsigned)->ceed = NULL; 1128 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed)); 1129 (*rstr_unsigned)->ref_count = 1; 1130 (*rstr_unsigned)->strides = NULL; 1131 if (rstr->strides) { 1132 CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides)); 1133 for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i]; 1134 } 1135 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_base)); 1136 1137 // Override Apply 1138 (*rstr_unsigned)->Apply = rstr->ApplyUnsigned; 1139 return CEED_ERROR_SUCCESS; 1140 } 1141 1142 /** 1143 @brief Copy the pointer to a `CeedElemRestriction` and set @ref CeedElemRestrictionApply() implementation to use the unoriented version. 1144 1145 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1146 1147 @param[in] rstr `CeedElemRestriction` to create unoriented reference to 1148 @param[in,out] rstr_unoriented Variable to store unoriented `CeedElemRestriction` 1149 1150 @return An error code: 0 - success, otherwise - failure 1151 1152 @ref User 1153 **/ 1154 int CeedElemRestrictionCreateUnorientedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unoriented) { 1155 CeedCall(CeedCalloc(1, rstr_unoriented)); 1156 1157 // Copy old rstr 1158 memcpy(*rstr_unoriented, rstr, sizeof(struct CeedElemRestriction_private)); 1159 (*rstr_unoriented)->ceed = NULL; 1160 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unoriented)->ceed)); 1161 (*rstr_unoriented)->ref_count = 1; 1162 (*rstr_unoriented)->strides = NULL; 1163 if (rstr->strides) { 1164 CeedCall(CeedMalloc(3, &(*rstr_unoriented)->strides)); 1165 for (CeedInt i = 0; i < 3; i++) (*rstr_unoriented)->strides[i] = rstr->strides[i]; 1166 } 1167 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unoriented)->rstr_base)); 1168 1169 // Override Apply 1170 (*rstr_unoriented)->Apply = rstr->ApplyUnoriented; 1171 return CEED_ERROR_SUCCESS; 1172 } 1173 1174 /** 1175 @brief Copy the pointer to a `CeedElemRestriction`. 1176 1177 Both pointers should be destroyed with @ref CeedElemRestrictionDestroy(). 1178 1179 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`. 1180 This `CeedElemRestriction` will be destroyed if `*rstr_copy` is the only reference to this `CeedElemRestriction`. 1181 1182 @param[in] rstr `CeedElemRestriction` to copy reference to 1183 @param[in,out] rstr_copy Variable to store copied reference 1184 1185 @return An error code: 0 - success, otherwise - failure 1186 1187 @ref User 1188 **/ 1189 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 1190 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 1191 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 1192 *rstr_copy = rstr; 1193 return CEED_ERROR_SUCCESS; 1194 } 1195 1196 /** 1197 @brief Create `CeedVector` associated with a `CeedElemRestriction` 1198 1199 @param[in] rstr `CeedElemRestriction` 1200 @param[out] l_vec The address of the L-vector to be created, or `NULL` 1201 @param[out] e_vec The address of the E-vector to be created, or `NULL` 1202 1203 @return An error code: 0 - success, otherwise - failure 1204 1205 @ref User 1206 **/ 1207 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 1208 CeedSize e_size, l_size; 1209 Ceed ceed; 1210 1211 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1212 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size)); 1213 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &e_size)); 1214 if (l_vec) CeedCall(CeedVectorCreate(ceed, l_size, l_vec)); 1215 if (e_vec) CeedCall(CeedVectorCreate(ceed, e_size, e_vec)); 1216 return CEED_ERROR_SUCCESS; 1217 } 1218 1219 /** 1220 @brief Restrict an L-vector to an E-vector or apply its transpose 1221 1222 @param[in] rstr `CeedElemRestriction` 1223 @param[in] t_mode Apply restriction or transpose 1224 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1225 @param[out] ru Output vector (of shape `[num_elem * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1226 Ordering of the e-vector is decided by the backend. 1227 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1228 1229 @return An error code: 0 - success, otherwise - failure 1230 1231 @ref User 1232 **/ 1233 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 1234 CeedSize min_u_len, min_ru_len, len; 1235 CeedInt num_elem; 1236 Ceed ceed; 1237 1238 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1239 if (t_mode == CEED_NOTRANSPOSE) { 1240 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &min_ru_len)); 1241 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1242 } else { 1243 CeedCall(CeedElemRestrictionGetEVectorSize(rstr, &min_u_len)); 1244 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1245 } 1246 CeedCall(CeedVectorGetLength(u, &len)); 1247 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1248 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1249 min_u_len); 1250 CeedCall(CeedVectorGetLength(ru, &len)); 1251 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1252 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1253 min_ru_len); 1254 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1255 if (num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 1256 return CEED_ERROR_SUCCESS; 1257 } 1258 1259 /** 1260 @brief Restrict an L-vector of points to a single element or apply its transpose 1261 1262 @param[in] rstr `CeedElemRestriction` 1263 @param[in] elem Element number in range `[0, num_elem)` 1264 @param[in] t_mode Apply restriction or transpose 1265 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1266 @param[out] ru Output vector (of shape [`num_points * num_comp]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1267 Ordering of the e-vector is decided by the backend. 1268 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1269 1270 @return An error code: 0 - success, otherwise - failure 1271 1272 @ref User 1273 **/ 1274 int CeedElemRestrictionApplyAtPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1275 CeedRequest *request) { 1276 CeedSize min_u_len, min_ru_len, len; 1277 CeedInt num_elem; 1278 Ceed ceed; 1279 1280 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1281 if (t_mode == CEED_NOTRANSPOSE) { 1282 CeedInt num_points, num_comp; 1283 1284 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1285 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1286 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1287 min_ru_len = (CeedSize)num_points * (CeedSize)num_comp; 1288 } else { 1289 CeedInt num_points, num_comp; 1290 1291 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, elem, &num_points)); 1292 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1293 min_u_len = (CeedSize)num_points * (CeedSize)num_comp; 1294 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1295 } 1296 CeedCall(CeedVectorGetLength(u, &len)); 1297 CeedCheck(min_u_len <= len, ceed, CEED_ERROR_DIMENSION, 1298 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1299 ") for element %" CeedInt_FMT, 1300 len, min_ru_len, min_u_len, elem); 1301 CeedCall(CeedVectorGetLength(ru, &len)); 1302 CeedCheck(min_ru_len <= len, ceed, CEED_ERROR_DIMENSION, 1303 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT 1304 ") for element %" CeedInt_FMT, 1305 len, min_ru_len, min_u_len, elem); 1306 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1307 CeedCheck(elem < num_elem, ceed, CEED_ERROR_DIMENSION, 1308 "Cannot retrieve element %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", elem, elem, num_elem); 1309 if (num_elem > 0) CeedCall(rstr->ApplyAtPointsInElement(rstr, elem, t_mode, u, ru, request)); 1310 return CEED_ERROR_SUCCESS; 1311 } 1312 1313 /** 1314 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 1315 1316 @param[in] rstr `CeedElemRestriction` 1317 @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]` 1318 @param[in] t_mode Apply restriction or transpose 1319 @param[in] u Input vector (of size `l_size` when `t_mode` = @ref CEED_NOTRANSPOSE) 1320 @param[out] ru Output vector (of shape `[block_size * elem_size]` when `t_mode` = @ref CEED_NOTRANSPOSE). 1321 Ordering of the e-vector is decided by the backend. 1322 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1323 1324 @return An error code: 0 - success, otherwise - failure 1325 1326 @ref Backend 1327 **/ 1328 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1329 CeedRequest *request) { 1330 CeedSize min_u_len, min_ru_len, len; 1331 CeedInt block_size, num_elem; 1332 Ceed ceed; 1333 1334 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1335 CeedCheck(rstr->ApplyBlock, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedElemRestrictionApplyBlock"); 1336 1337 CeedCall(CeedElemRestrictionGetBlockSize(rstr, &block_size)); 1338 if (t_mode == CEED_NOTRANSPOSE) { 1339 CeedInt elem_size, num_comp; 1340 1341 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1342 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1343 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_u_len)); 1344 min_ru_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1345 } else { 1346 CeedInt elem_size, num_comp; 1347 1348 CeedCall(CeedElemRestrictionGetElementSize(rstr, &elem_size)); 1349 CeedCall(CeedElemRestrictionGetNumComponents(rstr, &num_comp)); 1350 CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &min_ru_len)); 1351 min_u_len = (CeedSize)block_size * (CeedSize)elem_size * (CeedSize)num_comp; 1352 } 1353 CeedCall(CeedVectorGetLength(u, &len)); 1354 CeedCheck(min_u_len == len, ceed, CEED_ERROR_DIMENSION, 1355 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_u_len, 1356 min_ru_len); 1357 CeedCall(CeedVectorGetLength(ru, &len)); 1358 CeedCheck(min_ru_len == len, ceed, CEED_ERROR_DIMENSION, 1359 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", len, min_ru_len, 1360 min_u_len); 1361 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1362 CeedCheck(block_size * block <= num_elem, ceed, CEED_ERROR_DIMENSION, 1363 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, block_size * block, 1364 num_elem); 1365 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 1366 return CEED_ERROR_SUCCESS; 1367 } 1368 1369 /** 1370 @brief Get the `Ceed` associated with a `CeedElemRestriction` 1371 1372 @param[in] rstr `CeedElemRestriction` 1373 @param[out] ceed Variable to store `Ceed` 1374 1375 @return An error code: 0 - success, otherwise - failure 1376 1377 @ref Advanced 1378 **/ 1379 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 1380 *ceed = rstr->ceed; 1381 return CEED_ERROR_SUCCESS; 1382 } 1383 1384 /** 1385 @brief Get the L-vector component stride 1386 1387 @param[in] rstr `CeedElemRestriction` 1388 @param[out] comp_stride Variable to store component stride 1389 1390 @return An error code: 0 - success, otherwise - failure 1391 1392 @ref Advanced 1393 **/ 1394 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 1395 *comp_stride = rstr->comp_stride; 1396 return CEED_ERROR_SUCCESS; 1397 } 1398 1399 /** 1400 @brief Get the total number of elements in the range of a `CeedElemRestriction` 1401 1402 @param[in] rstr `CeedElemRestriction` 1403 @param[out] num_elem Variable to store number of elements 1404 1405 @return An error code: 0 - success, otherwise - failure 1406 1407 @ref Advanced 1408 **/ 1409 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 1410 *num_elem = rstr->num_elem; 1411 return CEED_ERROR_SUCCESS; 1412 } 1413 1414 /** 1415 @brief Get the size of elements in the `CeedElemRestriction` 1416 1417 @param[in] rstr `CeedElemRestriction` 1418 @param[out] elem_size Variable to store size of elements 1419 1420 @return An error code: 0 - success, otherwise - failure 1421 1422 @ref Advanced 1423 **/ 1424 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 1425 *elem_size = rstr->elem_size; 1426 return CEED_ERROR_SUCCESS; 1427 } 1428 1429 /** 1430 1431 @brief Get the number of points in the l-vector for a points `CeedElemRestriction` 1432 1433 @param[in] rstr `CeedElemRestriction` 1434 @param[out] num_points The number of points in the l-vector 1435 1436 @return An error code: 0 - success, otherwise - failure 1437 1438 @ref User 1439 **/ 1440 int CeedElemRestrictionGetNumPoints(CeedElemRestriction rstr, CeedInt *num_points) { 1441 CeedRestrictionType rstr_type; 1442 Ceed ceed; 1443 1444 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1445 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1446 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_INCOMPATIBLE, 1447 "Can only retrieve the number of points for a points CeedElemRestriction"); 1448 1449 *num_points = rstr->num_points; 1450 return CEED_ERROR_SUCCESS; 1451 } 1452 1453 /** 1454 1455 @brief Get the number of points in an element of a `CeedElemRestriction` at points 1456 1457 @param[in] rstr `CeedElemRestriction` 1458 @param[in] elem Index number of element to retrieve the number of points for 1459 @param[out] num_points The number of points in the element at index elem 1460 1461 @return An error code: 0 - success, otherwise - failure 1462 1463 @ref User 1464 **/ 1465 int CeedElemRestrictionGetNumPointsInElement(CeedElemRestriction rstr, CeedInt elem, CeedInt *num_points) { 1466 CeedRestrictionType rstr_type; 1467 const CeedInt *offsets; 1468 Ceed ceed; 1469 1470 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1471 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1472 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_INCOMPATIBLE, 1473 "Can only retrieve the number of points for a points CeedElemRestriction"); 1474 1475 CeedCall(CeedElemRestrictionGetOffsets(rstr, CEED_MEM_HOST, &offsets)); 1476 *num_points = offsets[elem + 1] - offsets[elem]; 1477 CeedCall(CeedElemRestrictionRestoreOffsets(rstr, &offsets)); 1478 return CEED_ERROR_SUCCESS; 1479 } 1480 1481 /** 1482 @brief Get the maximum number of points in an element for a `CeedElemRestriction` at points 1483 1484 @param[in] rstr `CeedElemRestriction` 1485 @param[out] max_points Variable to store size of elements 1486 1487 @return An error code: 0 - success, otherwise - failure 1488 1489 @ref Advanced 1490 **/ 1491 int CeedElemRestrictionGetMaxPointsInElement(CeedElemRestriction rstr, CeedInt *max_points) { 1492 CeedInt num_elem; 1493 CeedRestrictionType rstr_type; 1494 Ceed ceed; 1495 1496 CeedCall(CeedElemRestrictionGetCeed(rstr, &ceed)); 1497 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1498 CeedCheck(rstr_type == CEED_RESTRICTION_POINTS, ceed, CEED_ERROR_INCOMPATIBLE, 1499 "Cannot compute max points for a CeedElemRestriction that does not use points"); 1500 1501 CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem)); 1502 *max_points = 0; 1503 for (CeedInt e = 0; e < num_elem; e++) { 1504 CeedInt num_points; 1505 1506 CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr, e, &num_points)); 1507 *max_points = CeedIntMax(num_points, *max_points); 1508 } 1509 return CEED_ERROR_SUCCESS; 1510 } 1511 1512 /** 1513 @brief Get the size of the l-vector for a `CeedElemRestriction` 1514 1515 @param[in] rstr `CeedElemRestriction` 1516 @param[out] l_size Variable to store l-vector size 1517 1518 @return An error code: 0 - success, otherwise - failure 1519 1520 @ref Advanced 1521 **/ 1522 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 1523 *l_size = rstr->l_size; 1524 return CEED_ERROR_SUCCESS; 1525 } 1526 1527 /** 1528 @brief Get the size of the e-vector for a `CeedElemRestriction` 1529 1530 @param[in] rstr `CeedElemRestriction` 1531 @param[out] e_size Variable to store e-vector size 1532 1533 @return An error code: 0 - success, otherwise - failure 1534 1535 @ref Advanced 1536 **/ 1537 int CeedElemRestrictionGetEVectorSize(CeedElemRestriction rstr, CeedSize *e_size) { 1538 *e_size = rstr->e_size; 1539 return CEED_ERROR_SUCCESS; 1540 } 1541 1542 /** 1543 @brief Get the number of components in the elements of a `CeedElemRestriction` 1544 1545 @param[in] rstr `CeedElemRestriction` 1546 @param[out] num_comp Variable to store number of components 1547 1548 @return An error code: 0 - success, otherwise - failure 1549 1550 @ref Advanced 1551 **/ 1552 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 1553 *num_comp = rstr->num_comp; 1554 return CEED_ERROR_SUCCESS; 1555 } 1556 1557 /** 1558 @brief Get the number of blocks in a `CeedElemRestriction` 1559 1560 @param[in] rstr `CeedElemRestriction` 1561 @param[out] num_block Variable to store number of blocks 1562 1563 @return An error code: 0 - success, otherwise - failure 1564 1565 @ref Advanced 1566 **/ 1567 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 1568 *num_block = rstr->num_block; 1569 return CEED_ERROR_SUCCESS; 1570 } 1571 1572 /** 1573 @brief Get the size of blocks in the `CeedElemRestriction` 1574 1575 @param[in] rstr `CeedElemRestriction` 1576 @param[out] block_size Variable to store size of blocks 1577 1578 @return An error code: 0 - success, otherwise - failure 1579 1580 @ref Advanced 1581 **/ 1582 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *block_size) { 1583 *block_size = rstr->block_size; 1584 return CEED_ERROR_SUCCESS; 1585 } 1586 1587 /** 1588 @brief Get the multiplicity of nodes in a `CeedElemRestriction` 1589 1590 @param[in] rstr `CeedElemRestriction` 1591 @param[out] mult Vector to store multiplicity (of size `l_size`) 1592 1593 @return An error code: 0 - success, otherwise - failure 1594 1595 @ref User 1596 **/ 1597 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 1598 CeedVector e_vec; 1599 1600 // Create e_vec to hold intermediate computation in E^T (E 1) 1601 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 1602 1603 // Compute e_vec = E * 1 1604 CeedCall(CeedVectorSetValue(mult, 1.0)); 1605 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 1606 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 1607 CeedCall(CeedVectorSetValue(mult, 0.0)); 1608 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 1609 // Cleanup 1610 CeedCall(CeedVectorDestroy(&e_vec)); 1611 return CEED_ERROR_SUCCESS; 1612 } 1613 1614 /** 1615 @brief View a `CeedElemRestriction` 1616 1617 @param[in] rstr `CeedElemRestriction` to view 1618 @param[in] stream Stream to write; typically `stdout` or a file 1619 1620 @return Error code: 0 - success, otherwise - failure 1621 1622 @ref User 1623 **/ 1624 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 1625 CeedRestrictionType rstr_type; 1626 1627 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 1628 if (rstr_type == CEED_RESTRICTION_POINTS) { 1629 CeedInt max_points; 1630 1631 CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr, &max_points)); 1632 fprintf(stream, 1633 "CeedElemRestriction at points from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with a maximum of %" CeedInt_FMT 1634 " points on an element\n", 1635 rstr->l_size, rstr->num_comp, rstr->num_elem, max_points); 1636 } else { 1637 char strides_str[500]; 1638 1639 if (rstr->strides) { 1640 sprintf(strides_str, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 1641 } else { 1642 sprintf(strides_str, "%" CeedInt_FMT, rstr->comp_stride); 1643 } 1644 fprintf(stream, 1645 "%sCeedElemRestriction from (%" CeedSize_FMT ", %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT 1646 " nodes each and %s %s\n", 1647 rstr->block_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 1648 rstr->strides ? "strides" : "component stride", strides_str); 1649 } 1650 return CEED_ERROR_SUCCESS; 1651 } 1652 1653 /** 1654 @brief Destroy a `CeedElemRestriction` 1655 1656 @param[in,out] rstr `CeedElemRestriction` to destroy 1657 1658 @return An error code: 0 - success, otherwise - failure 1659 1660 @ref User 1661 **/ 1662 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 1663 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 1664 *rstr = NULL; 1665 return CEED_ERROR_SUCCESS; 1666 } 1667 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 1668 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 1669 1670 // Only destroy backend data once between rstr and unsigned copy 1671 if ((*rstr)->rstr_base) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_base)); 1672 else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 1673 1674 CeedCall(CeedFree(&(*rstr)->strides)); 1675 CeedCall(CeedDestroy(&(*rstr)->ceed)); 1676 CeedCall(CeedFree(rstr)); 1677 return CEED_ERROR_SUCCESS; 1678 } 1679 1680 /// @} 1681