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