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 restriction 26 27 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 28 @param[out] blk_offsets Array of permuted and padded array values of shape [@a num_blk, @a elem_size, @a blk_size]. 29 @param[in] num_blk Number of blocks 30 @param[in] num_elem Number of elements 31 @param[in] blk_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 *blk_offsets, CeedInt num_blk, CeedInt num_elem, CeedInt blk_size, CeedInt elem_size) { 39 for (CeedInt e = 0; e < num_blk * blk_size; e += blk_size) { 40 for (CeedInt j = 0; j < blk_size; j++) { 41 for (CeedInt k = 0; k < elem_size; k++) { 42 blk_offsets[e * elem_size + k * blk_size + j] = offsets[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 43 } 44 } 45 } 46 return CEED_ERROR_SUCCESS; 47 } 48 49 /** 50 @brief Permute and pad orientations for a blocked restriction 51 52 @param[in] orients Array of shape [@a num_elem, @a elem_size]. 53 @param[out] blk_orients Array of permuted and padded array values of shape [@a num_blk, @a elem_size, @a blk_size]. 54 @param[in] num_blk Number of blocks 55 @param[in] num_elem Number of elements 56 @param[in] blk_size Number of elements in a block 57 @param[in] elem_size Size of each element 58 59 @return An error code: 0 - success, otherwise - failure 60 61 @ref Utility 62 **/ 63 int CeedPermutePadOrients(const bool *orients, bool *blk_orients, CeedInt num_blk, CeedInt num_elem, CeedInt blk_size, CeedInt elem_size) { 64 for (CeedInt e = 0; e < num_blk * blk_size; e += blk_size) { 65 for (CeedInt j = 0; j < blk_size; j++) { 66 for (CeedInt k = 0; k < elem_size; k++) { 67 blk_orients[e * elem_size + k * blk_size + j] = orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 68 } 69 } 70 } 71 return CEED_ERROR_SUCCESS; 72 } 73 74 /** 75 @brief Permute and pad curl-conforming orientations for a blocked restriction 76 77 @param[in] curl_orients Array of shape [@a num_elem, @a 3 * elem_size]. 78 @param[out] blk_curl_orients Array of permuted and padded array values of shape [@a num_blk, @a elem_size, @a blk_size]. 79 @param[in] num_blk Number of blocks 80 @param[in] num_elem Number of elements 81 @param[in] blk_size Number of elements in a block 82 @param[in] elem_size Size of each element 83 84 @return An error code: 0 - success, otherwise - failure 85 86 @ref Utility 87 **/ 88 int CeedPermutePadCurlOrients(const CeedInt8 *curl_orients, CeedInt8 *blk_curl_orients, CeedInt num_blk, CeedInt num_elem, CeedInt blk_size, 89 CeedInt elem_size) { 90 for (CeedInt e = 0; e < num_blk * blk_size; e += blk_size) { 91 for (CeedInt j = 0; j < blk_size; j++) { 92 for (CeedInt k = 0; k < elem_size; k++) { 93 blk_curl_orients[e * elem_size + k * blk_size + j] = curl_orients[CeedIntMin(e + j, num_elem - 1) * elem_size + k]; 94 } 95 } 96 } 97 return CEED_ERROR_SUCCESS; 98 } 99 100 /// @} 101 102 /// ---------------------------------------------------------------------------- 103 /// CeedElemRestriction Backend API 104 /// ---------------------------------------------------------------------------- 105 /// @addtogroup CeedElemRestrictionBackend 106 /// @{ 107 108 /** 109 @brief Get the type of a CeedElemRestriction 110 111 @param[in] rstr CeedElemRestriction 112 @param[out] rstr_type Variable to store restriction type 113 114 @return An error code: 0 - success, otherwise - failure 115 116 @ref Backend 117 **/ 118 int CeedElemRestrictionGetType(CeedElemRestriction rstr, CeedRestrictionType *rstr_type) { 119 *rstr_type = rstr->rstr_type; 120 return CEED_ERROR_SUCCESS; 121 } 122 123 /** 124 @brief Get the strided status of a CeedElemRestriction 125 126 @param[in] rstr CeedElemRestriction 127 @param[out] is_strided Variable to store strided status, 1 if strided else 0 128 **/ 129 int CeedElemRestrictionIsStrided(CeedElemRestriction rstr, bool *is_strided) { 130 *is_strided = (rstr->rstr_type == CEED_RESTRICTION_STRIDED); 131 return CEED_ERROR_SUCCESS; 132 } 133 134 /** 135 @brief Get the strides of a strided CeedElemRestriction 136 137 @param[in] rstr CeedElemRestriction 138 @param[out] strides Variable to store strides array 139 140 @return An error code: 0 - success, otherwise - failure 141 142 @ref Backend 143 **/ 144 int CeedElemRestrictionGetStrides(CeedElemRestriction rstr, CeedInt (*strides)[3]) { 145 CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no stride data"); 146 for (CeedInt i = 0; i < 3; i++) (*strides)[i] = rstr->strides[i]; 147 return CEED_ERROR_SUCCESS; 148 } 149 150 /** 151 @brief Get the backend stride status of a CeedElemRestriction 152 153 @param[in] rstr CeedElemRestriction 154 @param[out] has_backend_strides Variable to store stride status 155 156 @return An error code: 0 - success, otherwise - failure 157 158 @ref Backend 159 **/ 160 int CeedElemRestrictionHasBackendStrides(CeedElemRestriction rstr, bool *has_backend_strides) { 161 CeedCheck(rstr->strides, rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no stride data"); 162 *has_backend_strides = ((rstr->strides[0] == CEED_STRIDES_BACKEND[0]) && (rstr->strides[1] == CEED_STRIDES_BACKEND[1]) && 163 (rstr->strides[2] == CEED_STRIDES_BACKEND[2])); 164 return CEED_ERROR_SUCCESS; 165 } 166 167 /** 168 @brief Get read-only access to a CeedElemRestriction offsets array by memtype 169 170 @param[in] rstr CeedElemRestriction to retrieve offsets 171 @param[in] mem_type Memory type on which to access the array. 172 If the backend uses a different memory type, this will perform a copy (possibly cached). 173 @param[out] offsets Array on memory type mem_type 174 175 @return An error code: 0 - success, otherwise - failure 176 177 @ref User 178 **/ 179 int CeedElemRestrictionGetOffsets(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt **offsets) { 180 if (rstr->rstr_base) { 181 CeedCall(CeedElemRestrictionGetOffsets(rstr->rstr_base, mem_type, offsets)); 182 } else { 183 CeedCheck(rstr->GetOffsets, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetOffsets"); 184 CeedCall(rstr->GetOffsets(rstr, mem_type, offsets)); 185 rstr->num_readers++; 186 } 187 return CEED_ERROR_SUCCESS; 188 } 189 190 /** 191 @brief Restore an offsets array obtained using CeedElemRestrictionGetOffsets() 192 193 @param[in] rstr CeedElemRestriction to restore 194 @param[in] offsets Array of offset data 195 196 @return An error code: 0 - success, otherwise - failure 197 198 @ref User 199 **/ 200 int CeedElemRestrictionRestoreOffsets(CeedElemRestriction rstr, const CeedInt **offsets) { 201 if (rstr->rstr_base) { 202 CeedCall(CeedElemRestrictionRestoreOffsets(rstr->rstr_base, offsets)); 203 } else { 204 *offsets = NULL; 205 rstr->num_readers--; 206 } 207 return CEED_ERROR_SUCCESS; 208 } 209 210 /** 211 @brief Get read-only access to a CeedElemRestriction orientations array by memtype 212 213 @param[in] rstr CeedElemRestriction to retrieve orientations 214 @param[in] mem_type Memory type on which to access the array. 215 If the backend uses a different memory type, this will perform a copy (possibly cached). 216 @param[out] orients Array on memory type mem_type 217 218 @return An error code: 0 - success, otherwise - failure 219 220 @ref User 221 **/ 222 int CeedElemRestrictionGetOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const bool **orients) { 223 CeedCheck(rstr->GetOrientations, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetOrientations"); 224 CeedCall(rstr->GetOrientations(rstr, mem_type, orients)); 225 rstr->num_readers++; 226 return CEED_ERROR_SUCCESS; 227 } 228 229 /** 230 @brief Restore an orientations array obtained using CeedElemRestrictionGetOrientations() 231 232 @param[in] rstr CeedElemRestriction to restore 233 @param[in] orients Array of orientation data 234 235 @return An error code: 0 - success, otherwise - failure 236 237 @ref User 238 **/ 239 int CeedElemRestrictionRestoreOrientations(CeedElemRestriction rstr, const bool **orients) { 240 *orients = NULL; 241 rstr->num_readers--; 242 return CEED_ERROR_SUCCESS; 243 } 244 245 /** 246 @brief Get read-only access to a CeedElemRestriction curl-conforming orientations array by memtype 247 248 @param[in] rstr CeedElemRestriction to retrieve curl-conforming orientations 249 @param[in] mem_type Memory type on which to access the array. 250 If the backend uses a different memory type, this will perform a copy (possibly cached). 251 @param[out] curl_orients Array on memory type mem_type 252 253 @return An error code: 0 - success, otherwise - failure 254 255 @ref User 256 **/ 257 int CeedElemRestrictionGetCurlOrientations(CeedElemRestriction rstr, CeedMemType mem_type, const CeedInt8 **curl_orients) { 258 CeedCheck(rstr->GetCurlOrientations, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetCurlOrientations"); 259 CeedCall(rstr->GetCurlOrientations(rstr, mem_type, curl_orients)); 260 rstr->num_readers++; 261 return CEED_ERROR_SUCCESS; 262 } 263 264 /** 265 @brief Restore an orientations array obtained using CeedElemRestrictionGetCurlOrientations() 266 267 @param[in] rstr CeedElemRestriction to restore 268 @param[in] curl_orients Array of orientation data 269 270 @return An error code: 0 - success, otherwise - failure 271 272 @ref User 273 **/ 274 int CeedElemRestrictionRestoreCurlOrientations(CeedElemRestriction rstr, const CeedInt8 **curl_orients) { 275 *curl_orients = NULL; 276 rstr->num_readers--; 277 return CEED_ERROR_SUCCESS; 278 } 279 280 /** 281 282 @brief Get the E-vector layout of a CeedElemRestriction 283 284 @param[in] rstr CeedElemRestriction 285 @param[out] layout Variable to store layout array, stored as [nodes, components, elements]. 286 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] 287 288 @return An error code: 0 - success, otherwise - failure 289 290 @ref Backend 291 **/ 292 int CeedElemRestrictionGetELayout(CeedElemRestriction rstr, CeedInt (*layout)[3]) { 293 CeedCheck(rstr->layout[0], rstr->ceed, CEED_ERROR_MINOR, "ElemRestriction has no layout data"); 294 for (CeedInt i = 0; i < 3; i++) (*layout)[i] = rstr->layout[i]; 295 return CEED_ERROR_SUCCESS; 296 } 297 298 /** 299 300 @brief Set the E-vector layout of a CeedElemRestriction 301 302 @param[in] rstr CeedElemRestriction 303 @param[in] layout Variable to containing layout array, stored as [nodes, components, elements]. 304 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] 305 306 @return An error code: 0 - success, otherwise - failure 307 308 @ref Backend 309 **/ 310 int CeedElemRestrictionSetELayout(CeedElemRestriction rstr, CeedInt layout[3]) { 311 for (CeedInt i = 0; i < 3; i++) rstr->layout[i] = layout[i]; 312 return CEED_ERROR_SUCCESS; 313 } 314 315 /** 316 @brief Get the backend data of a CeedElemRestriction 317 318 @param[in] rstr CeedElemRestriction 319 @param[out] data Variable to store data 320 321 @return An error code: 0 - success, otherwise - failure 322 323 @ref Backend 324 **/ 325 int CeedElemRestrictionGetData(CeedElemRestriction rstr, void *data) { 326 *(void **)data = rstr->data; 327 return CEED_ERROR_SUCCESS; 328 } 329 330 /** 331 @brief Set the backend data of a CeedElemRestriction 332 333 @param[in,out] rstr CeedElemRestriction 334 @param[in] data Data to set 335 336 @return An error code: 0 - success, otherwise - failure 337 338 @ref Backend 339 **/ 340 int CeedElemRestrictionSetData(CeedElemRestriction rstr, void *data) { 341 rstr->data = data; 342 return CEED_ERROR_SUCCESS; 343 } 344 345 /** 346 @brief Increment the reference counter for a CeedElemRestriction 347 348 @param[in,out] rstr ElemRestriction to increment the reference counter 349 350 @return An error code: 0 - success, otherwise - failure 351 352 @ref Backend 353 **/ 354 int CeedElemRestrictionReference(CeedElemRestriction rstr) { 355 rstr->ref_count++; 356 return CEED_ERROR_SUCCESS; 357 } 358 359 /** 360 @brief Estimate number of FLOPs required to apply CeedElemRestriction in t_mode 361 362 @param[in] rstr ElemRestriction to estimate FLOPs for 363 @param[in] t_mode Apply restriction or transpose 364 @param[out] flops Address of variable to hold FLOPs estimate 365 366 @ref Backend 367 **/ 368 int CeedElemRestrictionGetFlopsEstimate(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedSize *flops) { 369 CeedInt e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp, scale = 0; 370 CeedRestrictionType rstr_type; 371 CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type)); 372 if (t_mode == CEED_TRANSPOSE) { 373 switch (rstr_type) { 374 case CEED_RESTRICTION_STRIDED: 375 case CEED_RESTRICTION_STANDARD: 376 scale = 1; 377 break; 378 case CEED_RESTRICTION_ORIENTED: 379 scale = 2; 380 break; 381 case CEED_RESTRICTION_CURL_ORIENTED: 382 scale = 6; 383 break; 384 } 385 } else { 386 switch (rstr_type) { 387 case CEED_RESTRICTION_STRIDED: 388 case CEED_RESTRICTION_STANDARD: 389 scale = 0; 390 break; 391 case CEED_RESTRICTION_ORIENTED: 392 scale = 1; 393 break; 394 case CEED_RESTRICTION_CURL_ORIENTED: 395 scale = 5; 396 break; 397 } 398 } 399 *flops = e_size * scale; 400 401 return CEED_ERROR_SUCCESS; 402 } 403 404 /// @} 405 406 /// @cond DOXYGEN_SKIP 407 static struct CeedElemRestriction_private ceed_elemrestriction_none; 408 /// @endcond 409 410 /// ---------------------------------------------------------------------------- 411 /// CeedElemRestriction Public API 412 /// ---------------------------------------------------------------------------- 413 /// @addtogroup CeedElemRestrictionUser 414 /// @{ 415 416 /// Indicate that the stride is determined by the backend 417 const CeedInt CEED_STRIDES_BACKEND[3] = {0}; 418 419 /// Indicate that no CeedElemRestriction is provided by the user 420 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none; 421 422 /** 423 @brief Create a CeedElemRestriction 424 425 @param[in] ceed Ceed object where the CeedElemRestriction will be created 426 @param[in] num_elem Number of elements described in the @a offsets array 427 @param[in] elem_size Size (number of "nodes") per element 428 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 429 @param[in] comp_stride Stride between components for the same L-vector "node". 430 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. 431 @param[in] l_size The size of the L-vector. 432 This vector may be larger than the elements and fields given by this restriction. 433 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 434 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 435 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 436 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 437 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 438 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 439 440 @return An error code: 0 - success, otherwise - failure 441 442 @ref User 443 **/ 444 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 445 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 446 if (!ceed->ElemRestrictionCreate) { 447 Ceed delegate; 448 449 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 450 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate"); 451 CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 452 return CEED_ERROR_SUCCESS; 453 } 454 455 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 456 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 457 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 458 459 CeedCall(CeedCalloc(1, rstr)); 460 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 461 (*rstr)->ref_count = 1; 462 (*rstr)->num_elem = num_elem; 463 (*rstr)->elem_size = elem_size; 464 (*rstr)->num_comp = num_comp; 465 (*rstr)->comp_stride = comp_stride; 466 (*rstr)->l_size = l_size; 467 (*rstr)->num_blk = num_elem; 468 (*rstr)->blk_size = 1; 469 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 470 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 471 return CEED_ERROR_SUCCESS; 472 } 473 474 /** 475 @brief Create a CeedElemRestriction with orientation signs 476 477 @param[in] ceed Ceed object where the CeedElemRestriction will be created 478 @param[in] num_elem Number of elements described in the @a offsets array 479 @param[in] elem_size Size (number of "nodes") per element 480 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 481 @param[in] comp_stride Stride between components for the same L-vector "node". 482 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. 483 @param[in] l_size The size of the L-vector. 484 This vector may be larger than the elements and fields given by this restriction. 485 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 486 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 487 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 488 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 489 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 490 @param[in] orients Array of shape [@a num_elem, @a elem_size] with bool false for positively oriented and true to flip the orientation. 491 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 492 493 @return An error code: 0 - success, otherwise - failure 494 495 @ref User 496 **/ 497 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 498 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orients, 499 CeedElemRestriction *rstr) { 500 if (!ceed->ElemRestrictionCreate) { 501 Ceed delegate; 502 503 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 504 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate"); 505 CeedCall( 506 CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orients, rstr)); 507 return CEED_ERROR_SUCCESS; 508 } 509 510 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 511 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 512 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 513 514 CeedCall(CeedCalloc(1, rstr)); 515 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 516 (*rstr)->ref_count = 1; 517 (*rstr)->num_elem = num_elem; 518 (*rstr)->elem_size = elem_size; 519 (*rstr)->num_comp = num_comp; 520 (*rstr)->comp_stride = comp_stride; 521 (*rstr)->l_size = l_size; 522 (*rstr)->num_blk = num_elem; 523 (*rstr)->blk_size = 1; 524 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 525 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, orients, NULL, *rstr)); 526 return CEED_ERROR_SUCCESS; 527 } 528 529 /** 530 @brief Create a CeedElemRestriction with a general tridiagonal transformation matrix for curl-conforming elements 531 532 @param[in] ceed Ceed object where the CeedElemRestriction will be created 533 @param[in] num_elem Number of elements described in the @a offsets array 534 @param[in] elem_size Size (number of "nodes") per element 535 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 536 @param[in] comp_stride Stride between components for the same L-vector "node". 537 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. 538 @param[in] l_size The size of the L-vector. 539 This vector may be larger than the elements and fields given by this restriction. 540 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 541 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 542 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 543 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, 544 where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 545 @param[in] curl_orients Array of shape [@a num_elem, @a 3 * elem_size] representing a row-major tridiagonal matrix (curl_orients[i * 3 * elem_size] 546 = curl_orients[(i + 1) * 3 * elem_size - 1] = 0, where 0 <= i < @a num_elem) which is applied to the element unknowns upon restriction. This 547 orientation matrix allows for pairs of face degrees of freedom on elements for H(curl) spaces to be coupled in the element restriction operation, 548 which is a way to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456). 549 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 550 551 @return An error code: 0 - success, otherwise - failure 552 553 @ref User 554 **/ 555 int CeedElemRestrictionCreateCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 556 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const CeedInt8 *curl_orients, 557 CeedElemRestriction *rstr) { 558 if (!ceed->ElemRestrictionCreate) { 559 Ceed delegate; 560 561 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 562 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate"); 563 CeedCall(CeedElemRestrictionCreateCurlOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 564 curl_orients, rstr)); 565 return CEED_ERROR_SUCCESS; 566 } 567 568 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 569 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 570 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 571 572 CeedCall(CeedCalloc(1, rstr)); 573 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 574 (*rstr)->ref_count = 1; 575 (*rstr)->num_elem = num_elem; 576 (*rstr)->elem_size = elem_size; 577 (*rstr)->num_comp = num_comp; 578 (*rstr)->comp_stride = comp_stride; 579 (*rstr)->l_size = l_size; 580 (*rstr)->num_blk = num_elem; 581 (*rstr)->blk_size = 1; 582 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 583 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, curl_orients, *rstr)); 584 return CEED_ERROR_SUCCESS; 585 } 586 587 /** 588 @brief Create a strided CeedElemRestriction 589 590 @param[in] ceed Ceed object where the CeedElemRestriction will be created 591 @param[in] num_elem Number of elements described by the restriction 592 @param[in] elem_size Size (number of "nodes") per element 593 @param[in] num_comp Number of field components per interpolation "node" (1 for scalar fields) 594 @param[in] l_size The size of the L-vector. 595 This vector may be larger than the elements and fields given by this restriction. 596 @param[in] strides Array for strides between [nodes, components, elements]. 597 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]. 598 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 599 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 600 601 @return An error code: 0 - success, otherwise - failure 602 603 @ref User 604 **/ 605 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3], 606 CeedElemRestriction *rstr) { 607 if (!ceed->ElemRestrictionCreate) { 608 Ceed delegate; 609 610 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 611 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate"); 612 CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr)); 613 return CEED_ERROR_SUCCESS; 614 } 615 616 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 617 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 618 619 CeedCall(CeedCalloc(1, rstr)); 620 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 621 (*rstr)->ref_count = 1; 622 (*rstr)->num_elem = num_elem; 623 (*rstr)->elem_size = elem_size; 624 (*rstr)->num_comp = num_comp; 625 (*rstr)->l_size = l_size; 626 (*rstr)->num_blk = num_elem; 627 (*rstr)->blk_size = 1; 628 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 629 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 630 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 631 CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 632 return CEED_ERROR_SUCCESS; 633 } 634 635 /** 636 @brief Create a blocked CeedElemRestriction, typically only called by backends 637 638 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 639 @param[in] num_elem Number of elements described in the @a offsets array. 640 @param[in] elem_size Size (number of unknowns) per element 641 @param[in] blk_size Number of elements in a block 642 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 643 @param[in] comp_stride Stride between components for the same L-vector "node". 644 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. 645 @param[in] l_size The size of the L-vector. 646 This vector may be larger than the elements and fields given by this restriction. 647 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 648 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 649 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 650 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 651 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. The backend will permute and pad this array to the desired ordering for 652 the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 653 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 654 655 @return An error code: 0 - success, otherwise - failure 656 657 @ref Backend 658 **/ 659 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride, 660 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 661 CeedElemRestriction *rstr) { 662 CeedInt *blk_offsets; 663 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 664 665 if (!ceed->ElemRestrictionCreateBlocked) { 666 Ceed delegate; 667 668 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 669 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 670 CeedCall( 671 CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 672 return CEED_ERROR_SUCCESS; 673 } 674 675 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 676 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 677 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 678 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 679 680 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 681 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 682 683 CeedCall(CeedCalloc(1, rstr)); 684 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 685 (*rstr)->ref_count = 1; 686 (*rstr)->num_elem = num_elem; 687 (*rstr)->elem_size = elem_size; 688 (*rstr)->num_comp = num_comp; 689 (*rstr)->comp_stride = comp_stride; 690 (*rstr)->l_size = l_size; 691 (*rstr)->num_blk = num_blk; 692 (*rstr)->blk_size = blk_size; 693 (*rstr)->rstr_type = CEED_RESTRICTION_STANDARD; 694 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, NULL, NULL, *rstr)); 695 if (copy_mode == CEED_OWN_POINTER) { 696 CeedCall(CeedFree(&offsets)); 697 } 698 return CEED_ERROR_SUCCESS; 699 } 700 701 /** 702 @brief Create a blocked oriented CeedElemRestriction, typically only called by backends 703 704 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 705 @param[in] num_elem Number of elements described in the @a offsets array. 706 @param[in] elem_size Size (number of unknowns) per element 707 @param[in] blk_size Number of elements in a block 708 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 709 @param[in] comp_stride Stride between components for the same L-vector "node". 710 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. 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] mem_type Memory type of the @a offsets array, see CeedMemType 714 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 715 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 716 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 717 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. The backend will permute and pad this array to the desired ordering for 718 the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 719 @param[in] orients Array of shape [@a num_elem, @a elem_size] with bool false for positively oriented and true to flip the orientation. 720 Will also be permuted and padded similarly to @a offsets. 721 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 722 723 @return An error code: 0 - success, otherwise - failure 724 725 @ref Backend 726 **/ 727 int CeedElemRestrictionCreateBlockedOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride, 728 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 729 const bool *orients, CeedElemRestriction *rstr) { 730 CeedInt *blk_offsets; 731 bool *blk_orients; 732 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 733 734 if (!ceed->ElemRestrictionCreateBlocked) { 735 Ceed delegate; 736 737 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 738 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 739 CeedCall(CeedElemRestrictionCreateBlockedOriented(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, 740 offsets, orients, rstr)); 741 return CEED_ERROR_SUCCESS; 742 } 743 744 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 745 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 746 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 747 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 748 749 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 750 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_orients)); 751 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 752 CeedCall(CeedPermutePadOrients(orients, blk_orients, num_blk, num_elem, blk_size, elem_size)); 753 754 CeedCall(CeedCalloc(1, rstr)); 755 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 756 (*rstr)->ref_count = 1; 757 (*rstr)->num_elem = num_elem; 758 (*rstr)->elem_size = elem_size; 759 (*rstr)->num_comp = num_comp; 760 (*rstr)->comp_stride = comp_stride; 761 (*rstr)->l_size = l_size; 762 (*rstr)->num_blk = num_blk; 763 (*rstr)->blk_size = blk_size; 764 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 765 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, (const bool *)blk_orients, NULL, *rstr)); 766 if (copy_mode == CEED_OWN_POINTER) { 767 CeedCall(CeedFree(&offsets)); 768 } 769 return CEED_ERROR_SUCCESS; 770 } 771 772 /** 773 @brief Create a blocked curl-oriented CeedElemRestriction, typically only called by backends 774 775 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 776 @param[in] num_elem Number of elements described in the @a offsets array. 777 @param[in] elem_size Size (number of unknowns) per element 778 @param[in] blk_size Number of elements in a block 779 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 780 @param[in] comp_stride Stride between components for the same L-vector "node". 781 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. 782 @param[in] l_size The size of the L-vector. 783 This vector may be larger than the elements and fields given by this restriction. 784 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 785 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 786 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 787 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, 788 where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. The backend will permute and pad this array to the desired ordering 789 for the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 790 @param[in] curl_orients Array of shape [@a num_elem, @a 3 * elem_size] representing a row-major tridiagonal matrix (curl_orients[i * 3 * elem_size] 791 = curl_orients[(i + 1) * 3 * elem_size - 1] = 0, where 0 <= i < @a num_elem) which is applied to the element unknowns upon restriction. This 792 orientation matrix allows for pairs of face degrees of freedom on elements for H(curl) spaces to be coupled in the element restriction operation, 793 which is a way to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456). Will also be permuted and padded 794 similarly to @a offsets. 795 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 796 797 @return An error code: 0 - success, otherwise - failure 798 799 @ref Backend 800 **/ 801 int CeedElemRestrictionCreateBlockedCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, 802 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 803 const CeedInt *offsets, const CeedInt8 *curl_orients, CeedElemRestriction *rstr) { 804 CeedInt *blk_offsets; 805 CeedInt8 *blk_curl_orients; 806 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 807 808 if (!ceed->ElemRestrictionCreateBlocked) { 809 Ceed delegate; 810 811 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 812 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 813 CeedCall(CeedElemRestrictionCreateBlockedCurlOriented(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, 814 offsets, curl_orients, rstr)); 815 return CEED_ERROR_SUCCESS; 816 } 817 818 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 819 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 820 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 821 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 822 823 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 824 CeedCall(CeedCalloc(num_blk * blk_size * 3 * elem_size, &blk_curl_orients)); 825 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 826 CeedCall(CeedPermutePadCurlOrients(curl_orients, blk_curl_orients, num_blk, num_elem, blk_size, 3 * elem_size)); 827 828 CeedCall(CeedCalloc(1, rstr)); 829 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 830 (*rstr)->ref_count = 1; 831 (*rstr)->num_elem = num_elem; 832 (*rstr)->elem_size = elem_size; 833 (*rstr)->num_comp = num_comp; 834 (*rstr)->comp_stride = comp_stride; 835 (*rstr)->l_size = l_size; 836 (*rstr)->num_blk = num_blk; 837 (*rstr)->blk_size = blk_size; 838 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 839 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, NULL, (const CeedInt8 *)blk_curl_orients, 840 *rstr)); 841 if (copy_mode == CEED_OWN_POINTER) { 842 CeedCall(CeedFree(&offsets)); 843 } 844 return CEED_ERROR_SUCCESS; 845 } 846 847 /** 848 @brief Create a blocked strided CeedElemRestriction, typically only called by backends 849 850 @param[in] ceed Ceed object where the CeedElemRestriction will be created 851 @param[in] num_elem Number of elements described by the restriction 852 @param[in] elem_size Size (number of "nodes") per element 853 @param[in] blk_size Number of elements in a block 854 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 855 @param[in] l_size The size of the L-vector. 856 This vector may be larger than the elements and fields given by this restriction. 857 @param[in] strides Array for strides between [nodes, components, elements]. 858 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]. 859 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 860 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 861 862 @return An error code: 0 - success, otherwise - failure 863 864 @ref User 865 **/ 866 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedSize l_size, 867 const CeedInt strides[3], CeedElemRestriction *rstr) { 868 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 869 870 if (!ceed->ElemRestrictionCreateBlocked) { 871 Ceed delegate; 872 873 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 874 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 875 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, blk_size, num_comp, l_size, strides, rstr)); 876 return CEED_ERROR_SUCCESS; 877 } 878 879 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 880 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 881 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 882 883 CeedCall(CeedCalloc(1, rstr)); 884 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 885 (*rstr)->ref_count = 1; 886 (*rstr)->num_elem = num_elem; 887 (*rstr)->elem_size = elem_size; 888 (*rstr)->num_comp = num_comp; 889 (*rstr)->l_size = l_size; 890 (*rstr)->num_blk = num_blk; 891 (*rstr)->blk_size = blk_size; 892 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 893 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 894 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 895 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 896 return CEED_ERROR_SUCCESS; 897 } 898 899 /** 900 @brief Copy the pointer to a CeedElemRestriction and set `CeedElemRestrictionApply()` implementation to use the unsigned version. 901 902 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 903 904 @param[in] rstr CeedElemRestriction to create unsigned reference to 905 @param[in,out] rstr_unsigned Variable to store unsigned CeedElemRestriction 906 907 @return An error code: 0 - success, otherwise - failure 908 909 @ref User 910 **/ 911 int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) { 912 CeedCall(CeedCalloc(1, rstr_unsigned)); 913 914 // Copy old rstr 915 memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private)); 916 (*rstr_unsigned)->ceed = NULL; 917 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed)); 918 (*rstr_unsigned)->ref_count = 1; 919 (*rstr_unsigned)->strides = NULL; 920 if (rstr->strides) { 921 CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides)); 922 for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i]; 923 } 924 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_base)); 925 926 // Override Apply 927 (*rstr_unsigned)->Apply = rstr->ApplyUnsigned; 928 929 return CEED_ERROR_SUCCESS; 930 } 931 932 /** 933 @brief Copy the pointer to a CeedElemRestriction and set `CeedElemRestrictionApply()` implementation to use the unoriented version. 934 935 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 936 937 @param[in] rstr CeedElemRestriction to create unoriented reference to 938 @param[in,out] rstr_unoriented Variable to store unoriented CeedElemRestriction 939 940 @return An error code: 0 - success, otherwise - failure 941 942 @ref User 943 **/ 944 int CeedElemRestrictionCreateUnorientedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unoriented) { 945 CeedCall(CeedCalloc(1, rstr_unoriented)); 946 947 // Copy old rstr 948 memcpy(*rstr_unoriented, rstr, sizeof(struct CeedElemRestriction_private)); 949 (*rstr_unoriented)->ceed = NULL; 950 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unoriented)->ceed)); 951 (*rstr_unoriented)->ref_count = 1; 952 (*rstr_unoriented)->strides = NULL; 953 if (rstr->strides) { 954 CeedCall(CeedMalloc(3, &(*rstr_unoriented)->strides)); 955 for (CeedInt i = 0; i < 3; i++) (*rstr_unoriented)->strides[i] = rstr->strides[i]; 956 } 957 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unoriented)->rstr_base)); 958 959 // Override Apply 960 (*rstr_unoriented)->Apply = rstr->ApplyUnoriented; 961 962 return CEED_ERROR_SUCCESS; 963 } 964 965 /** 966 @brief Copy the pointer to a CeedElemRestriction. 967 968 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 969 970 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. 971 This CeedElemRestriction will be destroyed if `rstr_copy` is the only reference to this CeedElemRestriction. 972 973 @param[in] rstr CeedElemRestriction to copy reference to 974 @param[in,out] rstr_copy Variable to store copied reference 975 976 @return An error code: 0 - success, otherwise - failure 977 978 @ref User 979 **/ 980 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 981 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 982 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 983 *rstr_copy = rstr; 984 return CEED_ERROR_SUCCESS; 985 } 986 987 /** 988 @brief Create CeedVectors associated with a CeedElemRestriction 989 990 @param[in] rstr CeedElemRestriction 991 @param[out] l_vec The address of the L-vector to be created, or NULL 992 @param[out] e_vec The address of the E-vector to be created, or NULL 993 994 @return An error code: 0 - success, otherwise - failure 995 996 @ref User 997 **/ 998 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 999 CeedSize e_size, l_size; 1000 l_size = rstr->l_size; 1001 e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 1002 if (l_vec) CeedCall(CeedVectorCreate(rstr->ceed, l_size, l_vec)); 1003 if (e_vec) CeedCall(CeedVectorCreate(rstr->ceed, e_size, e_vec)); 1004 return CEED_ERROR_SUCCESS; 1005 } 1006 1007 /** 1008 @brief Restrict an L-vector to an E-vector or apply its transpose 1009 1010 @param[in] rstr CeedElemRestriction 1011 @param[in] t_mode Apply restriction or transpose 1012 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 1013 @param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 1014 Ordering of the e-vector is decided by the backend. 1015 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1016 1017 @return An error code: 0 - success, otherwise - failure 1018 1019 @ref User 1020 **/ 1021 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 1022 CeedInt m, n; 1023 1024 if (t_mode == CEED_NOTRANSPOSE) { 1025 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 1026 n = rstr->l_size; 1027 } else { 1028 m = rstr->l_size; 1029 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 1030 } 1031 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 1032 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 1033 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 1034 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 1035 if (rstr->num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 1036 return CEED_ERROR_SUCCESS; 1037 } 1038 1039 /** 1040 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 1041 1042 @param[in] rstr CeedElemRestriction 1043 @param[in] block Block number to restrict to/from, i.e. block=0 will handle elements [0 : blk_size] and block=3 will handle elements [3*blk_size 1044 : 4*blk_size] 1045 @param[in] t_mode Apply restriction or transpose 1046 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 1047 @param[out] ru Output vector (of shape [@a blk_size * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 1048 Ordering of the e-vector is decided by the backend. 1049 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1050 1051 @return An error code: 0 - success, otherwise - failure 1052 1053 @ref Backend 1054 **/ 1055 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1056 CeedRequest *request) { 1057 CeedInt m, n; 1058 1059 CeedCheck(rstr->ApplyBlock, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionApplyBlock"); 1060 1061 if (t_mode == CEED_NOTRANSPOSE) { 1062 m = rstr->blk_size * rstr->elem_size * rstr->num_comp; 1063 n = rstr->l_size; 1064 } else { 1065 m = rstr->l_size; 1066 n = rstr->blk_size * rstr->elem_size * rstr->num_comp; 1067 } 1068 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 1069 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 1070 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 1071 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 1072 CeedCheck(rstr->blk_size * block <= rstr->num_elem, rstr->ceed, CEED_ERROR_DIMENSION, 1073 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, rstr->blk_size * block, 1074 rstr->num_elem); 1075 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 1076 return CEED_ERROR_SUCCESS; 1077 } 1078 1079 /** 1080 @brief Get the Ceed associated with a CeedElemRestriction 1081 1082 @param[in] rstr CeedElemRestriction 1083 @param[out] ceed Variable to store Ceed 1084 1085 @return An error code: 0 - success, otherwise - failure 1086 1087 @ref Advanced 1088 **/ 1089 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 1090 *ceed = rstr->ceed; 1091 return CEED_ERROR_SUCCESS; 1092 } 1093 1094 /** 1095 @brief Get the L-vector component stride 1096 1097 @param[in] rstr CeedElemRestriction 1098 @param[out] comp_stride Variable to store component stride 1099 1100 @return An error code: 0 - success, otherwise - failure 1101 1102 @ref Advanced 1103 **/ 1104 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 1105 *comp_stride = rstr->comp_stride; 1106 return CEED_ERROR_SUCCESS; 1107 } 1108 1109 /** 1110 @brief Get the total number of elements in the range of a CeedElemRestriction 1111 1112 @param[in] rstr CeedElemRestriction 1113 @param[out] num_elem Variable to store number of elements 1114 1115 @return An error code: 0 - success, otherwise - failure 1116 1117 @ref Advanced 1118 **/ 1119 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 1120 *num_elem = rstr->num_elem; 1121 return CEED_ERROR_SUCCESS; 1122 } 1123 1124 /** 1125 @brief Get the size of elements in the CeedElemRestriction 1126 1127 @param[in] rstr CeedElemRestriction 1128 @param[out] elem_size Variable to store size of elements 1129 1130 @return An error code: 0 - success, otherwise - failure 1131 1132 @ref Advanced 1133 **/ 1134 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 1135 *elem_size = rstr->elem_size; 1136 return CEED_ERROR_SUCCESS; 1137 } 1138 1139 /** 1140 @brief Get the size of the l-vector for a CeedElemRestriction 1141 1142 @param[in] rstr CeedElemRestriction 1143 @param[out] l_size Variable to store number of nodes 1144 1145 @return An error code: 0 - success, otherwise - failure 1146 1147 @ref Advanced 1148 **/ 1149 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 1150 *l_size = rstr->l_size; 1151 return CEED_ERROR_SUCCESS; 1152 } 1153 1154 /** 1155 @brief Get the number of components in the elements of a CeedElemRestriction 1156 1157 @param[in] rstr CeedElemRestriction 1158 @param[out] num_comp Variable to store number of components 1159 1160 @return An error code: 0 - success, otherwise - failure 1161 1162 @ref Advanced 1163 **/ 1164 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 1165 *num_comp = rstr->num_comp; 1166 return CEED_ERROR_SUCCESS; 1167 } 1168 1169 /** 1170 @brief Get the number of blocks in a CeedElemRestriction 1171 1172 @param[in] rstr CeedElemRestriction 1173 @param[out] num_block Variable to store number of blocks 1174 1175 @return An error code: 0 - success, otherwise - failure 1176 1177 @ref Advanced 1178 **/ 1179 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 1180 *num_block = rstr->num_blk; 1181 return CEED_ERROR_SUCCESS; 1182 } 1183 1184 /** 1185 @brief Get the size of blocks in the CeedElemRestriction 1186 1187 @param[in] rstr CeedElemRestriction 1188 @param[out] blk_size Variable to store size of blocks 1189 1190 @return An error code: 0 - success, otherwise - failure 1191 1192 @ref Advanced 1193 **/ 1194 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *blk_size) { 1195 *blk_size = rstr->blk_size; 1196 return CEED_ERROR_SUCCESS; 1197 } 1198 1199 /** 1200 @brief Get the multiplicity of nodes in a CeedElemRestriction 1201 1202 @param[in] rstr CeedElemRestriction 1203 @param[out] mult Vector to store multiplicity (of size l_size) 1204 1205 @return An error code: 0 - success, otherwise - failure 1206 1207 @ref User 1208 **/ 1209 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 1210 CeedVector e_vec; 1211 1212 // Create e_vec to hold intermediate computation in E^T (E 1) 1213 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 1214 1215 // Compute e_vec = E * 1 1216 CeedCall(CeedVectorSetValue(mult, 1.0)); 1217 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 1218 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 1219 CeedCall(CeedVectorSetValue(mult, 0.0)); 1220 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 1221 // Cleanup 1222 CeedCall(CeedVectorDestroy(&e_vec)); 1223 return CEED_ERROR_SUCCESS; 1224 } 1225 1226 /** 1227 @brief View a CeedElemRestriction 1228 1229 @param[in] rstr CeedElemRestriction to view 1230 @param[in] stream Stream to write; typically stdout/stderr or a file 1231 1232 @return Error code: 0 - success, otherwise - failure 1233 1234 @ref User 1235 **/ 1236 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 1237 char stridesstr[500]; 1238 if (rstr->strides) { 1239 sprintf(stridesstr, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 1240 } else { 1241 sprintf(stridesstr, "%" CeedInt_FMT, rstr->comp_stride); 1242 } 1243 1244 fprintf(stream, "%sCeedElemRestriction from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT " nodes each and %s %s\n", 1245 rstr->blk_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 1246 rstr->strides ? "strides" : "component stride", stridesstr); 1247 return CEED_ERROR_SUCCESS; 1248 } 1249 1250 /** 1251 @brief Destroy a CeedElemRestriction 1252 1253 @param[in,out] rstr CeedElemRestriction to destroy 1254 1255 @return An error code: 0 - success, otherwise - failure 1256 1257 @ref User 1258 **/ 1259 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 1260 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 1261 *rstr = NULL; 1262 return CEED_ERROR_SUCCESS; 1263 } 1264 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 1265 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 1266 1267 // Only destroy backend data once between rstr and unsigned copy 1268 if ((*rstr)->rstr_base) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_base)); 1269 else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 1270 1271 CeedCall(CeedFree(&(*rstr)->strides)); 1272 CeedCall(CeedDestroy(&(*rstr)->ceed)); 1273 CeedCall(CeedFree(rstr)); 1274 return CEED_ERROR_SUCCESS; 1275 } 1276 1277 /// @} 1278