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 Both pointers should be destroyed with `CeedElemRestrictionDestroy()`. 679 680 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 681 CeedElemRestriction. This CeedElemRestriction will be destroyed if `rstr_copy` is the only reference to this CeedElemRestriction. 682 683 @param[in] rstr CeedElemRestriction to copy reference to 684 @param[in,out] rstr_copy Variable to store copied reference 685 686 @return An error code: 0 - success, otherwise - failure 687 688 @ref User 689 **/ 690 int CeedElemRestrictionReferenceCopy(CeedElemRestriction rstr, CeedElemRestriction *rstr_copy) { 691 CeedCall(CeedElemRestrictionReference(rstr)); 692 CeedCall(CeedElemRestrictionDestroy(rstr_copy)); 693 *rstr_copy = rstr; 694 return CEED_ERROR_SUCCESS; 695 } 696 697 /** 698 @brief Create CeedVectors associated with a CeedElemRestriction 699 700 @param[in] rstr CeedElemRestriction 701 @param[out] l_vec The address of the L-vector to be created, or NULL 702 @param[out] e_vec The address of the E-vector to be created, or NULL 703 704 @return An error code: 0 - success, otherwise - failure 705 706 @ref User 707 **/ 708 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *l_vec, CeedVector *e_vec) { 709 CeedSize e_size, l_size; 710 l_size = rstr->l_size; 711 e_size = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 712 if (l_vec) CeedCall(CeedVectorCreate(rstr->ceed, l_size, l_vec)); 713 if (e_vec) CeedCall(CeedVectorCreate(rstr->ceed, e_size, e_vec)); 714 return CEED_ERROR_SUCCESS; 715 } 716 717 /** 718 @brief Restrict an L-vector to an E-vector or apply its transpose 719 720 @param[in] rstr CeedElemRestriction 721 @param[in] t_mode Apply restriction or transpose 722 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 723 @param[out] ru Output vector (of shape [@a num_elem * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 724 Ordering of the e-vector is decided by the backend. 725 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 726 727 @return An error code: 0 - success, otherwise - failure 728 729 @ref User 730 **/ 731 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, CeedRequest *request) { 732 CeedInt m, n; 733 734 if (t_mode == CEED_NOTRANSPOSE) { 735 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 736 n = rstr->l_size; 737 } else { 738 m = rstr->l_size; 739 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 740 } 741 if (n != u->length) { 742 // LCOV_EXCL_START 743 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 744 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, 745 n); 746 // LCOV_EXCL_STOP 747 } 748 if (m != ru->length) { 749 // LCOV_EXCL_START 750 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 751 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, 752 m, n); 753 // LCOV_EXCL_STOP 754 } 755 if (rstr->num_elem > 0) CeedCall(rstr->Apply(rstr, t_mode, u, ru, request)); 756 return CEED_ERROR_SUCCESS; 757 } 758 759 /** 760 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 761 762 @param[in] rstr CeedElemRestriction 763 @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 764 : 4*blk_size] 765 @param[in] t_mode Apply restriction or transpose 766 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 767 @param[out] ru Output vector (of shape [@a blk_size * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 768 Ordering of the e-vector is decided by the backend. 769 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 770 771 @return An error code: 0 - success, otherwise - failure 772 773 @ref Backend 774 **/ 775 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 776 CeedRequest *request) { 777 CeedInt m, n; 778 779 if (t_mode == CEED_NOTRANSPOSE) { 780 m = rstr->blk_size * rstr->elem_size * rstr->num_comp; 781 n = rstr->l_size; 782 } else { 783 m = rstr->l_size; 784 n = rstr->blk_size * rstr->elem_size * rstr->num_comp; 785 } 786 if (n != u->length) { 787 // LCOV_EXCL_START 788 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 789 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, 790 n); 791 // LCOV_EXCL_STOP 792 } 793 if (m != ru->length) { 794 // LCOV_EXCL_START 795 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 796 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, 797 m, n); 798 // LCOV_EXCL_STOP 799 } 800 if (rstr->blk_size * block > rstr->num_elem) { 801 // LCOV_EXCL_START 802 return CeedError(rstr->ceed, CEED_ERROR_DIMENSION, 803 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, 804 rstr->blk_size * block, rstr->num_elem); 805 // LCOV_EXCL_STOP 806 } 807 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 808 return CEED_ERROR_SUCCESS; 809 } 810 811 /** 812 @brief Get the Ceed associated with a CeedElemRestriction 813 814 @param[in] rstr CeedElemRestriction 815 @param[out] ceed Variable to store Ceed 816 817 @return An error code: 0 - success, otherwise - failure 818 819 @ref Advanced 820 **/ 821 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 822 *ceed = rstr->ceed; 823 return CEED_ERROR_SUCCESS; 824 } 825 826 /** 827 @brief Get the L-vector component stride 828 829 @param[in] rstr CeedElemRestriction 830 @param[out] comp_stride Variable to store component stride 831 832 @return An error code: 0 - success, otherwise - failure 833 834 @ref Advanced 835 **/ 836 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 837 *comp_stride = rstr->comp_stride; 838 return CEED_ERROR_SUCCESS; 839 } 840 841 /** 842 @brief Get the total number of elements in the range of a CeedElemRestriction 843 844 @param[in] rstr CeedElemRestriction 845 @param[out] num_elem Variable to store number of elements 846 847 @return An error code: 0 - success, otherwise - failure 848 849 @ref Advanced 850 **/ 851 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 852 *num_elem = rstr->num_elem; 853 return CEED_ERROR_SUCCESS; 854 } 855 856 /** 857 @brief Get the size of elements in the CeedElemRestriction 858 859 @param[in] rstr CeedElemRestriction 860 @param[out] elem_size Variable to store size of elements 861 862 @return An error code: 0 - success, otherwise - failure 863 864 @ref Advanced 865 **/ 866 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 867 *elem_size = rstr->elem_size; 868 return CEED_ERROR_SUCCESS; 869 } 870 871 /** 872 @brief Get the size of the l-vector for a CeedElemRestriction 873 874 @param[in] rstr CeedElemRestriction 875 @param[out] l_size Variable to store number of nodes 876 877 @return An error code: 0 - success, otherwise - failure 878 879 @ref Advanced 880 **/ 881 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 882 *l_size = rstr->l_size; 883 return CEED_ERROR_SUCCESS; 884 } 885 886 /** 887 @brief Get the number of components in the elements of a CeedElemRestriction 888 889 @param[in] rstr CeedElemRestriction 890 @param[out] num_comp Variable to store number of components 891 892 @return An error code: 0 - success, otherwise - failure 893 894 @ref Advanced 895 **/ 896 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 897 *num_comp = rstr->num_comp; 898 return CEED_ERROR_SUCCESS; 899 } 900 901 /** 902 @brief Get the number of blocks in a CeedElemRestriction 903 904 @param[in] rstr CeedElemRestriction 905 @param[out] num_block Variable to store number of blocks 906 907 @return An error code: 0 - success, otherwise - failure 908 909 @ref Advanced 910 **/ 911 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 912 *num_block = rstr->num_blk; 913 return CEED_ERROR_SUCCESS; 914 } 915 916 /** 917 @brief Get the size of blocks in the CeedElemRestriction 918 919 @param[in] rstr CeedElemRestriction 920 @param[out] blk_size Variable to store size of blocks 921 922 @return An error code: 0 - success, otherwise - failure 923 924 @ref Advanced 925 **/ 926 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *blk_size) { 927 *blk_size = rstr->blk_size; 928 return CEED_ERROR_SUCCESS; 929 } 930 931 /** 932 @brief Get the multiplicity of nodes in a CeedElemRestriction 933 934 @param[in] rstr CeedElemRestriction 935 @param[out] mult Vector to store multiplicity (of size l_size) 936 937 @return An error code: 0 - success, otherwise - failure 938 939 @ref User 940 **/ 941 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 942 CeedVector e_vec; 943 944 // Create e_vec to hold intermediate computation in E^T (E 1) 945 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 946 947 // Compute e_vec = E * 1 948 CeedCall(CeedVectorSetValue(mult, 1.0)); 949 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 950 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 951 CeedCall(CeedVectorSetValue(mult, 0.0)); 952 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 953 // Cleanup 954 CeedCall(CeedVectorDestroy(&e_vec)); 955 return CEED_ERROR_SUCCESS; 956 } 957 958 /** 959 @brief View a CeedElemRestriction 960 961 @param[in] rstr CeedElemRestriction to view 962 @param[in] stream Stream to write; typically stdout/stderr or a file 963 964 @return Error code: 0 - success, otherwise - failure 965 966 @ref User 967 **/ 968 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 969 char stridesstr[500]; 970 if (rstr->strides) { 971 sprintf(stridesstr, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 972 } else { 973 sprintf(stridesstr, "%" CeedInt_FMT, rstr->comp_stride); 974 } 975 976 fprintf(stream, "%sCeedElemRestriction from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT " nodes each and %s %s\n", 977 rstr->blk_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 978 rstr->strides ? "strides" : "component stride", stridesstr); 979 return CEED_ERROR_SUCCESS; 980 } 981 982 /** 983 @brief Destroy a CeedElemRestriction 984 985 @param[in,out] rstr CeedElemRestriction to destroy 986 987 @return An error code: 0 - success, otherwise - failure 988 989 @ref User 990 **/ 991 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 992 if (!*rstr || --(*rstr)->ref_count > 0) { 993 *rstr = NULL; 994 return CEED_ERROR_SUCCESS; 995 } 996 if ((*rstr)->num_readers) { 997 // LCOV_EXCL_START 998 return CeedError((*rstr)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 999 // LCOV_EXCL_STOP 1000 } 1001 if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 1002 CeedCall(CeedFree(&(*rstr)->strides)); 1003 CeedCall(CeedDestroy(&(*rstr)->ceed)); 1004 CeedCall(CeedFree(rstr)); 1005 return CEED_ERROR_SUCCESS; 1006 } 1007 1008 /// @} 1009