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