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