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