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 const bool *orients = NULL; 370 const CeedInt8 *curl_orients = NULL; 371 CeedInt e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp, scale = 0; 372 373 CeedCall(CeedElemRestrictionGetOrientations(rstr, CEED_MEM_HOST, &orients)); 374 CeedCall(CeedElemRestrictionGetCurlOrientations(rstr, CEED_MEM_HOST, &curl_orients)); 375 if (t_mode == CEED_TRANSPOSE) { 376 if (!orients && !curl_orients) { 377 scale = 1; 378 } else if (!curl_orients) { 379 scale = 2; 380 } else { 381 scale = 6; 382 } 383 } else { 384 if (!orients && !curl_orients) { 385 scale = 0; 386 } else if (!curl_orients) { 387 scale = 1; 388 } else { 389 scale = 5; 390 } 391 } 392 CeedCall(CeedElemRestrictionRestoreOrientations(rstr, &orients)); 393 CeedCall(CeedElemRestrictionRestoreCurlOrientations(rstr, &curl_orients)); 394 *flops = e_size * scale; 395 396 return CEED_ERROR_SUCCESS; 397 } 398 399 /// @} 400 401 /// @cond DOXYGEN_SKIP 402 static struct CeedElemRestriction_private ceed_elemrestriction_none; 403 /// @endcond 404 405 /// ---------------------------------------------------------------------------- 406 /// CeedElemRestriction Public API 407 /// ---------------------------------------------------------------------------- 408 /// @addtogroup CeedElemRestrictionUser 409 /// @{ 410 411 /// Indicate that the stride is determined by the backend 412 const CeedInt CEED_STRIDES_BACKEND[3] = {0}; 413 414 /// Indicate that no CeedElemRestriction is provided by the user 415 const CeedElemRestriction CEED_ELEMRESTRICTION_NONE = &ceed_elemrestriction_none; 416 417 /** 418 @brief Create a CeedElemRestriction 419 420 @param[in] ceed Ceed object where the CeedElemRestriction will be created 421 @param[in] num_elem Number of elements described in the @a offsets array 422 @param[in] elem_size Size (number of "nodes") per element 423 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 424 @param[in] comp_stride Stride between components for the same L-vector "node". 425 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. 426 @param[in] l_size The size of the L-vector. 427 This vector may be larger than the elements and fields given by this restriction. 428 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 429 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 430 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 431 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 432 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 433 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 434 435 @return An error code: 0 - success, otherwise - failure 436 437 @ref User 438 **/ 439 int CeedElemRestrictionCreate(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 440 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, CeedElemRestriction *rstr) { 441 if (!ceed->ElemRestrictionCreate) { 442 Ceed delegate; 443 444 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 445 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate"); 446 CeedCall(CeedElemRestrictionCreate(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 447 return CEED_ERROR_SUCCESS; 448 } 449 450 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 451 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 452 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 453 454 CeedCall(CeedCalloc(1, rstr)); 455 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 456 (*rstr)->ref_count = 1; 457 (*rstr)->num_elem = num_elem; 458 (*rstr)->elem_size = elem_size; 459 (*rstr)->num_comp = num_comp; 460 (*rstr)->comp_stride = comp_stride; 461 (*rstr)->l_size = l_size; 462 (*rstr)->num_blk = num_elem; 463 (*rstr)->blk_size = 1; 464 (*rstr)->rstr_type = CEED_RESTRICTION_DEFAULT; 465 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, NULL, *rstr)); 466 return CEED_ERROR_SUCCESS; 467 } 468 469 /** 470 @brief Create a CeedElemRestriction with orientation signs 471 472 @param[in] ceed Ceed object where the CeedElemRestriction will be created 473 @param[in] num_elem Number of elements described in the @a offsets array 474 @param[in] elem_size Size (number of "nodes") per element 475 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 476 @param[in] comp_stride Stride between components for the same L-vector "node". 477 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. 478 @param[in] l_size The size of the L-vector. 479 This vector may be larger than the elements and fields given by this restriction. 480 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 481 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 482 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 483 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 484 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 485 @param[in] orients Array of shape [@a num_elem, @a elem_size] with bool false for positively oriented and true to flip the orientation. 486 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 487 488 @return An error code: 0 - success, otherwise - failure 489 490 @ref User 491 **/ 492 int CeedElemRestrictionCreateOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 493 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const bool *orients, 494 CeedElemRestriction *rstr) { 495 if (!ceed->ElemRestrictionCreate) { 496 Ceed delegate; 497 498 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 499 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate"); 500 CeedCall( 501 CeedElemRestrictionCreateOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, orients, rstr)); 502 return CEED_ERROR_SUCCESS; 503 } 504 505 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 506 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 507 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 508 509 CeedCall(CeedCalloc(1, rstr)); 510 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 511 (*rstr)->ref_count = 1; 512 (*rstr)->num_elem = num_elem; 513 (*rstr)->elem_size = elem_size; 514 (*rstr)->num_comp = num_comp; 515 (*rstr)->comp_stride = comp_stride; 516 (*rstr)->l_size = l_size; 517 (*rstr)->num_blk = num_elem; 518 (*rstr)->blk_size = 1; 519 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 520 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, orients, NULL, *rstr)); 521 return CEED_ERROR_SUCCESS; 522 } 523 524 /** 525 @brief Create a CeedElemRestriction with a general tridiagonal transformation matrix for curl-conforming elements 526 527 @param[in] ceed Ceed object where the CeedElemRestriction will be created 528 @param[in] num_elem Number of elements described in the @a offsets array 529 @param[in] elem_size Size (number of "nodes") per element 530 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 531 @param[in] comp_stride Stride between components for the same L-vector "node". 532 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. 533 @param[in] l_size The size of the L-vector. 534 This vector may be larger than the elements and fields given by this restriction. 535 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 536 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 537 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 538 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, 539 where 0 <= i < @a num_elem. All offsets must be in the range [0, @a l_size - 1]. 540 @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] 541 = 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 542 orientation matrix allows for pairs of face degrees of freedom on elements for H(curl) spaces to be coupled in the element restriction operation, 543 which is a way to resolve face orientation issues for 3D meshes (https://dl.acm.org/doi/pdf/10.1145/3524456). 544 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 545 546 @return An error code: 0 - success, otherwise - failure 547 548 @ref User 549 **/ 550 int CeedElemRestrictionCreateCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedInt comp_stride, CeedSize l_size, 551 CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, const CeedInt8 *curl_orients, 552 CeedElemRestriction *rstr) { 553 if (!ceed->ElemRestrictionCreate) { 554 Ceed delegate; 555 556 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 557 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate"); 558 CeedCall(CeedElemRestrictionCreateCurlOriented(delegate, num_elem, elem_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, 559 curl_orients, rstr)); 560 return CEED_ERROR_SUCCESS; 561 } 562 563 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 564 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 565 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 566 567 CeedCall(CeedCalloc(1, rstr)); 568 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 569 (*rstr)->ref_count = 1; 570 (*rstr)->num_elem = num_elem; 571 (*rstr)->elem_size = elem_size; 572 (*rstr)->num_comp = num_comp; 573 (*rstr)->comp_stride = comp_stride; 574 (*rstr)->l_size = l_size; 575 (*rstr)->num_blk = num_elem; 576 (*rstr)->blk_size = 1; 577 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 578 CeedCall(ceed->ElemRestrictionCreate(mem_type, copy_mode, offsets, NULL, curl_orients, *rstr)); 579 return CEED_ERROR_SUCCESS; 580 } 581 582 /** 583 @brief Create a strided CeedElemRestriction 584 585 @param[in] ceed Ceed object where the CeedElemRestriction will be created 586 @param[in] num_elem Number of elements described by the restriction 587 @param[in] elem_size Size (number of "nodes") per element 588 @param[in] num_comp Number of field components per interpolation "node" (1 for scalar fields) 589 @param[in] l_size The size of the L-vector. 590 This vector may be larger than the elements and fields given by this restriction. 591 @param[in] strides Array for strides between [nodes, components, elements]. 592 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]. 593 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 594 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 595 596 @return An error code: 0 - success, otherwise - failure 597 598 @ref User 599 **/ 600 int CeedElemRestrictionCreateStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt num_comp, CeedSize l_size, const CeedInt strides[3], 601 CeedElemRestriction *rstr) { 602 if (!ceed->ElemRestrictionCreate) { 603 Ceed delegate; 604 605 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 606 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreate"); 607 CeedCall(CeedElemRestrictionCreateStrided(delegate, num_elem, elem_size, num_comp, l_size, strides, rstr)); 608 return CEED_ERROR_SUCCESS; 609 } 610 611 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 612 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 613 614 CeedCall(CeedCalloc(1, rstr)); 615 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 616 (*rstr)->ref_count = 1; 617 (*rstr)->num_elem = num_elem; 618 (*rstr)->elem_size = elem_size; 619 (*rstr)->num_comp = num_comp; 620 (*rstr)->l_size = l_size; 621 (*rstr)->num_blk = num_elem; 622 (*rstr)->blk_size = 1; 623 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 624 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 625 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 626 CeedCall(ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 627 return CEED_ERROR_SUCCESS; 628 } 629 630 /** 631 @brief Create a blocked CeedElemRestriction, typically only called by backends 632 633 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 634 @param[in] num_elem Number of elements described in the @a offsets array. 635 @param[in] elem_size Size (number of unknowns) per element 636 @param[in] blk_size Number of elements in a block 637 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 638 @param[in] comp_stride Stride between components for the same L-vector "node". 639 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. 640 @param[in] l_size The size of the L-vector. 641 This vector may be larger than the elements and fields given by this restriction. 642 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 643 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 644 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 645 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 646 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 647 the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 648 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 649 650 @return An error code: 0 - success, otherwise - failure 651 652 @ref Backend 653 **/ 654 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride, 655 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 656 CeedElemRestriction *rstr) { 657 CeedInt *blk_offsets; 658 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 659 660 if (!ceed->ElemRestrictionCreateBlocked) { 661 Ceed delegate; 662 663 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 664 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 665 CeedCall( 666 CeedElemRestrictionCreateBlocked(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, offsets, rstr)); 667 return CEED_ERROR_SUCCESS; 668 } 669 670 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 671 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 672 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 673 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 674 675 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 676 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 677 678 CeedCall(CeedCalloc(1, rstr)); 679 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 680 (*rstr)->ref_count = 1; 681 (*rstr)->num_elem = num_elem; 682 (*rstr)->elem_size = elem_size; 683 (*rstr)->num_comp = num_comp; 684 (*rstr)->comp_stride = comp_stride; 685 (*rstr)->l_size = l_size; 686 (*rstr)->num_blk = num_blk; 687 (*rstr)->blk_size = blk_size; 688 (*rstr)->rstr_type = CEED_RESTRICTION_DEFAULT; 689 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, NULL, NULL, *rstr)); 690 if (copy_mode == CEED_OWN_POINTER) { 691 CeedCall(CeedFree(&offsets)); 692 } 693 return CEED_ERROR_SUCCESS; 694 } 695 696 /** 697 @brief Create a blocked oriented CeedElemRestriction, typically only called by backends 698 699 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 700 @param[in] num_elem Number of elements described in the @a offsets array. 701 @param[in] elem_size Size (number of unknowns) per element 702 @param[in] blk_size Number of elements in a block 703 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 704 @param[in] comp_stride Stride between components for the same L-vector "node". 705 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. 706 @param[in] l_size The size of the L-vector. 707 This vector may be larger than the elements and fields given by this restriction. 708 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 709 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 710 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 711 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, where 712 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 713 the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 714 @param[in] orients Array of shape [@a num_elem, @a elem_size] with bool false for positively oriented and true to flip the orientation. 715 Will also be permuted and padded similarly to @a offsets. 716 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 717 718 @return An error code: 0 - success, otherwise - failure 719 720 @ref Backend 721 **/ 722 int CeedElemRestrictionCreateBlockedOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedInt comp_stride, 723 CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, const CeedInt *offsets, 724 const bool *orients, CeedElemRestriction *rstr) { 725 CeedInt *blk_offsets; 726 bool *blk_orients; 727 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 728 729 if (!ceed->ElemRestrictionCreateBlocked) { 730 Ceed delegate; 731 732 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 733 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 734 CeedCall(CeedElemRestrictionCreateBlockedOriented(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, 735 offsets, orients, rstr)); 736 return CEED_ERROR_SUCCESS; 737 } 738 739 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 740 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 741 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 742 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 743 744 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 745 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_orients)); 746 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 747 CeedCall(CeedPermutePadOrients(orients, blk_orients, num_blk, num_elem, blk_size, elem_size)); 748 749 CeedCall(CeedCalloc(1, rstr)); 750 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 751 (*rstr)->ref_count = 1; 752 (*rstr)->num_elem = num_elem; 753 (*rstr)->elem_size = elem_size; 754 (*rstr)->num_comp = num_comp; 755 (*rstr)->comp_stride = comp_stride; 756 (*rstr)->l_size = l_size; 757 (*rstr)->num_blk = num_blk; 758 (*rstr)->blk_size = blk_size; 759 (*rstr)->rstr_type = CEED_RESTRICTION_ORIENTED; 760 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, (const bool *)blk_orients, NULL, *rstr)); 761 if (copy_mode == CEED_OWN_POINTER) { 762 CeedCall(CeedFree(&offsets)); 763 } 764 return CEED_ERROR_SUCCESS; 765 } 766 767 /** 768 @brief Create a blocked curl-oriented CeedElemRestriction, typically only called by backends 769 770 @param[in] ceed Ceed object where the CeedElemRestriction will be created. 771 @param[in] num_elem Number of elements described in the @a offsets array. 772 @param[in] elem_size Size (number of unknowns) per element 773 @param[in] blk_size Number of elements in a block 774 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 775 @param[in] comp_stride Stride between components for the same L-vector "node". 776 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. 777 @param[in] l_size The size of the L-vector. 778 This vector may be larger than the elements and fields given by this restriction. 779 @param[in] mem_type Memory type of the @a offsets array, see CeedMemType 780 @param[in] copy_mode Copy mode for the @a offsets array, see CeedCopyMode 781 @param[in] offsets Array of shape [@a num_elem, @a elem_size]. 782 Row i holds the ordered list of the offsets (into the input CeedVector) for the unknowns corresponding to element i, 783 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 784 for the blocksize, which is typically given by the backend. The default reordering is to interlace elements. 785 @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] 786 = 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 787 orientation matrix allows for pairs of face degrees of freedom on elements for H(curl) spaces to be coupled in the element restriction operation, 788 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 789 similarly to @a offsets. 790 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 791 792 @return An error code: 0 - success, otherwise - failure 793 794 @ref Backend 795 **/ 796 int CeedElemRestrictionCreateBlockedCurlOriented(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, 797 CeedInt comp_stride, CeedSize l_size, CeedMemType mem_type, CeedCopyMode copy_mode, 798 const CeedInt *offsets, const CeedInt8 *curl_orients, CeedElemRestriction *rstr) { 799 CeedInt *blk_offsets; 800 CeedInt8 *blk_curl_orients; 801 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 802 803 if (!ceed->ElemRestrictionCreateBlocked) { 804 Ceed delegate; 805 806 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 807 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 808 CeedCall(CeedElemRestrictionCreateBlockedCurlOriented(delegate, num_elem, elem_size, blk_size, num_comp, comp_stride, l_size, mem_type, copy_mode, 809 offsets, curl_orients, rstr)); 810 return CEED_ERROR_SUCCESS; 811 } 812 813 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 814 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 815 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 816 CeedCheck(num_comp == 1 || comp_stride > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction component stride must be at least 1"); 817 818 CeedCall(CeedCalloc(num_blk * blk_size * elem_size, &blk_offsets)); 819 CeedCall(CeedCalloc(num_blk * blk_size * 3 * elem_size, &blk_curl_orients)); 820 CeedCall(CeedPermutePadOffsets(offsets, blk_offsets, num_blk, num_elem, blk_size, elem_size)); 821 CeedCall(CeedPermutePadCurlOrients(curl_orients, blk_curl_orients, num_blk, num_elem, blk_size, 3 * elem_size)); 822 823 CeedCall(CeedCalloc(1, rstr)); 824 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 825 (*rstr)->ref_count = 1; 826 (*rstr)->num_elem = num_elem; 827 (*rstr)->elem_size = elem_size; 828 (*rstr)->num_comp = num_comp; 829 (*rstr)->comp_stride = comp_stride; 830 (*rstr)->l_size = l_size; 831 (*rstr)->num_blk = num_blk; 832 (*rstr)->blk_size = blk_size; 833 (*rstr)->rstr_type = CEED_RESTRICTION_CURL_ORIENTED; 834 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, (const CeedInt *)blk_offsets, NULL, (const CeedInt8 *)blk_curl_orients, 835 *rstr)); 836 if (copy_mode == CEED_OWN_POINTER) { 837 CeedCall(CeedFree(&offsets)); 838 } 839 return CEED_ERROR_SUCCESS; 840 } 841 842 /** 843 @brief Create a blocked strided CeedElemRestriction, typically only called by backends 844 845 @param[in] ceed Ceed object where the CeedElemRestriction will be created 846 @param[in] num_elem Number of elements described by the restriction 847 @param[in] elem_size Size (number of "nodes") per element 848 @param[in] blk_size Number of elements in a block 849 @param[in] num_comp Number of field components per interpolation node (1 for scalar fields) 850 @param[in] l_size The size of the L-vector. 851 This vector may be larger than the elements and fields given by this restriction. 852 @param[in] strides Array for strides between [nodes, components, elements]. 853 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]. 854 @a CEED_STRIDES_BACKEND may be used with vectors created by a Ceed backend. 855 @param[out] rstr Address of the variable where the newly created CeedElemRestriction will be stored 856 857 @return An error code: 0 - success, otherwise - failure 858 859 @ref User 860 **/ 861 int CeedElemRestrictionCreateBlockedStrided(Ceed ceed, CeedInt num_elem, CeedInt elem_size, CeedInt blk_size, CeedInt num_comp, CeedSize l_size, 862 const CeedInt strides[3], CeedElemRestriction *rstr) { 863 CeedInt num_blk = (num_elem / blk_size) + !!(num_elem % blk_size); 864 865 if (!ceed->ElemRestrictionCreateBlocked) { 866 Ceed delegate; 867 868 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction")); 869 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionCreateBlocked"); 870 CeedCall(CeedElemRestrictionCreateBlockedStrided(delegate, num_elem, elem_size, blk_size, num_comp, l_size, strides, rstr)); 871 return CEED_ERROR_SUCCESS; 872 } 873 874 CeedCheck(elem_size > 0, ceed, CEED_ERROR_DIMENSION, "Element size must be at least 1"); 875 CeedCheck(blk_size > 0, ceed, CEED_ERROR_DIMENSION, "Block size must be at least 1"); 876 CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "ElemRestriction must have at least 1 component"); 877 878 CeedCall(CeedCalloc(1, rstr)); 879 CeedCall(CeedReferenceCopy(ceed, &(*rstr)->ceed)); 880 (*rstr)->ref_count = 1; 881 (*rstr)->num_elem = num_elem; 882 (*rstr)->elem_size = elem_size; 883 (*rstr)->num_comp = num_comp; 884 (*rstr)->l_size = l_size; 885 (*rstr)->num_blk = num_blk; 886 (*rstr)->blk_size = blk_size; 887 (*rstr)->rstr_type = CEED_RESTRICTION_STRIDED; 888 CeedCall(CeedMalloc(3, &(*rstr)->strides)); 889 for (CeedInt i = 0; i < 3; i++) (*rstr)->strides[i] = strides[i]; 890 CeedCall(ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER, NULL, NULL, NULL, *rstr)); 891 return CEED_ERROR_SUCCESS; 892 } 893 894 /** 895 @brief Copy the pointer to a CeedElemRestriction and set `CeedElemRestrictionApply()` implementation to use the unsigned version. 896 897 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 898 899 @param[in] rstr CeedElemRestriction to create unsigned reference to 900 @param[in,out] rstr_unsigned Variable to store unsigned CeedElemRestriction 901 902 @return An error code: 0 - success, otherwise - failure 903 904 @ref User 905 **/ 906 int CeedElemRestrictionCreateUnsignedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unsigned) { 907 CeedCall(CeedCalloc(1, rstr_unsigned)); 908 909 // Copy old rstr 910 memcpy(*rstr_unsigned, rstr, sizeof(struct CeedElemRestriction_private)); 911 (*rstr_unsigned)->ceed = NULL; 912 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unsigned)->ceed)); 913 (*rstr_unsigned)->ref_count = 1; 914 (*rstr_unsigned)->strides = NULL; 915 if (rstr->strides) { 916 CeedCall(CeedMalloc(3, &(*rstr_unsigned)->strides)); 917 for (CeedInt i = 0; i < 3; i++) (*rstr_unsigned)->strides[i] = rstr->strides[i]; 918 } 919 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unsigned)->rstr_base)); 920 921 // Override Apply 922 (*rstr_unsigned)->Apply = rstr->ApplyUnsigned; 923 924 return CEED_ERROR_SUCCESS; 925 } 926 927 /** 928 @brief Copy the pointer to a CeedElemRestriction and set `CeedElemRestrictionApply()` implementation to use the unoriented version. 929 930 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 931 932 @param[in] rstr CeedElemRestriction to create unoriented reference to 933 @param[in,out] rstr_unoriented Variable to store unoriented CeedElemRestriction 934 935 @return An error code: 0 - success, otherwise - failure 936 937 @ref User 938 **/ 939 int CeedElemRestrictionCreateUnorientedCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_unoriented) { 940 CeedCall(CeedCalloc(1, rstr_unoriented)); 941 942 // Copy old rstr 943 memcpy(*rstr_unoriented, rstr, sizeof(struct CeedElemRestriction_private)); 944 (*rstr_unoriented)->ceed = NULL; 945 CeedCall(CeedReferenceCopy(rstr->ceed, &(*rstr_unoriented)->ceed)); 946 (*rstr_unoriented)->ref_count = 1; 947 (*rstr_unoriented)->strides = NULL; 948 if (rstr->strides) { 949 CeedCall(CeedMalloc(3, &(*rstr_unoriented)->strides)); 950 for (CeedInt i = 0; i < 3; i++) (*rstr_unoriented)->strides[i] = rstr->strides[i]; 951 } 952 CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*rstr_unoriented)->rstr_base)); 953 954 // Override Apply 955 (*rstr_unoriented)->Apply = rstr->ApplyUnoriented; 956 957 return CEED_ERROR_SUCCESS; 958 } 959 960 /** 961 @brief Copy the pointer to a CeedElemRestriction. 962 963 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 964 965 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. 966 This CeedElemRestriction will be destroyed if `rstr_copy` is the only reference to this CeedElemRestriction. 967 968 @param[in] rstr CeedElemRestriction to copy reference to 969 @param[in,out] rstr_copy Variable to store copied reference 970 971 @return An error code: 0 - success, otherwise - failure 972 973 @ref User 974 **/ 975 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 976 if (rstr != CEED_ELEMRESTRICTION_NONE) CeedCall(CeedElemRestrictionReference(rstr)); 977 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 978 *rstr_copy = rstr; 979 return CEED_ERROR_SUCCESS; 980 } 981 982 /** 983 @brief Create CeedVectors associated with a CeedElemRestriction 984 985 @param[in] rstr CeedElemRestriction 986 @param[out] l_vec The address of the L-vector to be created, or NULL 987 @param[out] e_vec The address of the E-vector to be created, or NULL 988 989 @return An error code: 0 - success, otherwise - failure 990 991 @ref User 992 **/ 993 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 994 CeedSize e_size, l_size; 995 l_size = rstr->l_size; 996 e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 997 if (l_vec) CeedCall(CeedVectorCreate(rstr->ceed, l_size, l_vec)); 998 if (e_vec) CeedCall(CeedVectorCreate(rstr->ceed, e_size, e_vec)); 999 return CEED_ERROR_SUCCESS; 1000 } 1001 1002 /** 1003 @brief Restrict an L-vector to an E-vector or apply its transpose 1004 1005 @param[in] rstr CeedElemRestriction 1006 @param[in] t_mode Apply restriction or transpose 1007 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 1008 @param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 1009 Ordering of the e-vector is decided by the backend. 1010 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1011 1012 @return An error code: 0 - success, otherwise - failure 1013 1014 @ref User 1015 **/ 1016 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 1017 CeedInt m, n; 1018 1019 if (t_mode == CEED_NOTRANSPOSE) { 1020 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 1021 n = rstr->l_size; 1022 } else { 1023 m = rstr->l_size; 1024 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 1025 } 1026 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 1027 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 1028 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 1029 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 1030 if (rstr->num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 1031 return CEED_ERROR_SUCCESS; 1032 } 1033 1034 /** 1035 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 1036 1037 @param[in] rstr CeedElemRestriction 1038 @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 1039 : 4*blk_size] 1040 @param[in] t_mode Apply restriction or transpose 1041 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 1042 @param[out] ru Output vector (of shape [@a blk_size * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 1043 Ordering of the e-vector is decided by the backend. 1044 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 1045 1046 @return An error code: 0 - success, otherwise - failure 1047 1048 @ref Backend 1049 **/ 1050 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 1051 CeedRequest *request) { 1052 CeedInt m, n; 1053 1054 CeedCheck(rstr->ApplyBlock, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionApplyBlock"); 1055 1056 if (t_mode == CEED_NOTRANSPOSE) { 1057 m = rstr->blk_size * rstr->elem_size * rstr->num_comp; 1058 n = rstr->l_size; 1059 } else { 1060 m = rstr->l_size; 1061 n = rstr->blk_size * rstr->elem_size * rstr->num_comp; 1062 } 1063 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 1064 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 1065 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 1066 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 1067 CeedCheck(rstr->blk_size * block <= rstr->num_elem, rstr->ceed, CEED_ERROR_DIMENSION, 1068 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, rstr->blk_size * block, 1069 rstr->num_elem); 1070 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 1071 return CEED_ERROR_SUCCESS; 1072 } 1073 1074 /** 1075 @brief Get the Ceed associated with a CeedElemRestriction 1076 1077 @param[in] rstr CeedElemRestriction 1078 @param[out] ceed Variable to store Ceed 1079 1080 @return An error code: 0 - success, otherwise - failure 1081 1082 @ref Advanced 1083 **/ 1084 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 1085 *ceed = rstr->ceed; 1086 return CEED_ERROR_SUCCESS; 1087 } 1088 1089 /** 1090 @brief Get the L-vector component stride 1091 1092 @param[in] rstr CeedElemRestriction 1093 @param[out] comp_stride Variable to store component stride 1094 1095 @return An error code: 0 - success, otherwise - failure 1096 1097 @ref Advanced 1098 **/ 1099 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 1100 *comp_stride = rstr->comp_stride; 1101 return CEED_ERROR_SUCCESS; 1102 } 1103 1104 /** 1105 @brief Get the total number of elements in the range of a CeedElemRestriction 1106 1107 @param[in] rstr CeedElemRestriction 1108 @param[out] num_elem Variable to store number of elements 1109 1110 @return An error code: 0 - success, otherwise - failure 1111 1112 @ref Advanced 1113 **/ 1114 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 1115 *num_elem = rstr->num_elem; 1116 return CEED_ERROR_SUCCESS; 1117 } 1118 1119 /** 1120 @brief Get the size of elements in the CeedElemRestriction 1121 1122 @param[in] rstr CeedElemRestriction 1123 @param[out] elem_size Variable to store size of elements 1124 1125 @return An error code: 0 - success, otherwise - failure 1126 1127 @ref Advanced 1128 **/ 1129 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 1130 *elem_size = rstr->elem_size; 1131 return CEED_ERROR_SUCCESS; 1132 } 1133 1134 /** 1135 @brief Get the size of the l-vector for a CeedElemRestriction 1136 1137 @param[in] rstr CeedElemRestriction 1138 @param[out] l_size Variable to store number of nodes 1139 1140 @return An error code: 0 - success, otherwise - failure 1141 1142 @ref Advanced 1143 **/ 1144 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 1145 *l_size = rstr->l_size; 1146 return CEED_ERROR_SUCCESS; 1147 } 1148 1149 /** 1150 @brief Get the number of components in the elements of a CeedElemRestriction 1151 1152 @param[in] rstr CeedElemRestriction 1153 @param[out] num_comp Variable to store number of components 1154 1155 @return An error code: 0 - success, otherwise - failure 1156 1157 @ref Advanced 1158 **/ 1159 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 1160 *num_comp = rstr->num_comp; 1161 return CEED_ERROR_SUCCESS; 1162 } 1163 1164 /** 1165 @brief Get the number of blocks in a CeedElemRestriction 1166 1167 @param[in] rstr CeedElemRestriction 1168 @param[out] num_block Variable to store number of blocks 1169 1170 @return An error code: 0 - success, otherwise - failure 1171 1172 @ref Advanced 1173 **/ 1174 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 1175 *num_block = rstr->num_blk; 1176 return CEED_ERROR_SUCCESS; 1177 } 1178 1179 /** 1180 @brief Get the size of blocks in the CeedElemRestriction 1181 1182 @param[in] rstr CeedElemRestriction 1183 @param[out] blk_size Variable to store size of blocks 1184 1185 @return An error code: 0 - success, otherwise - failure 1186 1187 @ref Advanced 1188 **/ 1189 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *blk_size) { 1190 *blk_size = rstr->blk_size; 1191 return CEED_ERROR_SUCCESS; 1192 } 1193 1194 /** 1195 @brief Get the multiplicity of nodes in a CeedElemRestriction 1196 1197 @param[in] rstr CeedElemRestriction 1198 @param[out] mult Vector to store multiplicity (of size l_size) 1199 1200 @return An error code: 0 - success, otherwise - failure 1201 1202 @ref User 1203 **/ 1204 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 1205 CeedVector e_vec; 1206 1207 // Create e_vec to hold intermediate computation in E^T (E 1) 1208 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 1209 1210 // Compute e_vec = E * 1 1211 CeedCall(CeedVectorSetValue(mult, 1.0)); 1212 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 1213 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 1214 CeedCall(CeedVectorSetValue(mult, 0.0)); 1215 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 1216 // Cleanup 1217 CeedCall(CeedVectorDestroy(&e_vec)); 1218 return CEED_ERROR_SUCCESS; 1219 } 1220 1221 /** 1222 @brief View a CeedElemRestriction 1223 1224 @param[in] rstr CeedElemRestriction to view 1225 @param[in] stream Stream to write; typically stdout/stderr or a file 1226 1227 @return Error code: 0 - success, otherwise - failure 1228 1229 @ref User 1230 **/ 1231 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 1232 char stridesstr[500]; 1233 if (rstr->strides) { 1234 sprintf(stridesstr, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 1235 } else { 1236 sprintf(stridesstr, "%" CeedInt_FMT, rstr->comp_stride); 1237 } 1238 1239 fprintf(stream, "%sCeedElemRestriction from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT " nodes each and %s %s\n", 1240 rstr->blk_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 1241 rstr->strides ? "strides" : "component stride", stridesstr); 1242 return CEED_ERROR_SUCCESS; 1243 } 1244 1245 /** 1246 @brief Destroy a CeedElemRestriction 1247 1248 @param[in,out] rstr CeedElemRestriction to destroy 1249 1250 @return An error code: 0 - success, otherwise - failure 1251 1252 @ref User 1253 **/ 1254 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 1255 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 1256 *rstr = NULL; 1257 return CEED_ERROR_SUCCESS; 1258 } 1259 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 1260 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 1261 1262 // Only destroy backend data once between rstr and unsigned copy 1263 if ((*rstr)->rstr_base) CeedCall(CeedElemRestrictionDestroy(&(*rstr)->rstr_base)); 1264 else if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 1265 1266 CeedCall(CeedFree(&(*rstr)->strides)); 1267 CeedCall(CeedDestroy(&(*rstr)->ceed)); 1268 CeedCall(CeedFree(rstr)); 1269 return CEED_ERROR_SUCCESS; 1270 } 1271 1272 /// @} 1273