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