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