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