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