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 CeedCheck(rstr->ApplyUnsigned, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionApplyUnsigned"); 653 654 if (t_mode == CEED_NOTRANSPOSE) { 655 m = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 656 n = rstr->l_size; 657 } else { 658 m = rstr->l_size; 659 n = rstr->num_blk * rstr->blk_size * rstr->elem_size * rstr->num_comp; 660 } 661 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 662 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 663 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 664 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 665 if (rstr->num_elem > 0) CeedCall(rstr->ApplyUnsigned(rstr, t_mode, u, ru, request)); 666 return CEED_ERROR_SUCCESS; 667 } 668 669 /** 670 @brief Restrict an L-vector to a block of an E-vector or apply its transpose 671 672 @param[in] rstr CeedElemRestriction 673 @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 674 : 4*blk_size] 675 @param[in] t_mode Apply restriction or transpose 676 @param[in] u Input vector (of size @a l_size when t_mode=@ref CEED_NOTRANSPOSE) 677 @param[out] ru Output vector (of shape [@a blk_size * @a elem_size] when t_mode=@ref CEED_NOTRANSPOSE). 678 Ordering of the e-vector is decided by the backend. 679 @param[in] request Request or @ref CEED_REQUEST_IMMEDIATE 680 681 @return An error code: 0 - success, otherwise - failure 682 683 @ref Backend 684 **/ 685 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block, CeedTransposeMode t_mode, CeedVector u, CeedVector ru, 686 CeedRequest *request) { 687 CeedInt m, n; 688 689 CeedCheck(rstr->ApplyBlock, rstr->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement ElemRestrictionApplyBlock"); 690 691 if (t_mode == CEED_NOTRANSPOSE) { 692 m = rstr->blk_size * rstr->elem_size * rstr->num_comp; 693 n = rstr->l_size; 694 } else { 695 m = rstr->l_size; 696 n = rstr->blk_size * rstr->elem_size * rstr->num_comp; 697 } 698 CeedCheck(n == u->length, rstr->ceed, CEED_ERROR_DIMENSION, 699 "Input vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", u->length, m, n); 700 CeedCheck(m == ru->length, rstr->ceed, CEED_ERROR_DIMENSION, 701 "Output vector size %" CeedInt_FMT " not compatible with element restriction (%" CeedInt_FMT ", %" CeedInt_FMT ")", ru->length, m, n); 702 CeedCheck(rstr->blk_size * block <= rstr->num_elem, rstr->ceed, CEED_ERROR_DIMENSION, 703 "Cannot retrieve block %" CeedInt_FMT ", element %" CeedInt_FMT " > total elements %" CeedInt_FMT "", block, rstr->blk_size * block, 704 rstr->num_elem); 705 CeedCall(rstr->ApplyBlock(rstr, block, t_mode, u, ru, request)); 706 return CEED_ERROR_SUCCESS; 707 } 708 709 /** 710 @brief Get the Ceed associated with a CeedElemRestriction 711 712 @param[in] rstr CeedElemRestriction 713 @param[out] ceed Variable to store Ceed 714 715 @return An error code: 0 - success, otherwise - failure 716 717 @ref Advanced 718 **/ 719 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) { 720 *ceed = rstr->ceed; 721 return CEED_ERROR_SUCCESS; 722 } 723 724 /** 725 @brief Get the L-vector component stride 726 727 @param[in] rstr CeedElemRestriction 728 @param[out] comp_stride Variable to store component stride 729 730 @return An error code: 0 - success, otherwise - failure 731 732 @ref Advanced 733 **/ 734 int CeedElemRestrictionGetCompStride(CeedElemRestriction rstr, CeedInt *comp_stride) { 735 *comp_stride = rstr->comp_stride; 736 return CEED_ERROR_SUCCESS; 737 } 738 739 /** 740 @brief Get the total number of elements in the range of a CeedElemRestriction 741 742 @param[in] rstr CeedElemRestriction 743 @param[out] num_elem Variable to store number of elements 744 745 @return An error code: 0 - success, otherwise - failure 746 747 @ref Advanced 748 **/ 749 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr, CeedInt *num_elem) { 750 *num_elem = rstr->num_elem; 751 return CEED_ERROR_SUCCESS; 752 } 753 754 /** 755 @brief Get the size of elements in the CeedElemRestriction 756 757 @param[in] rstr CeedElemRestriction 758 @param[out] elem_size Variable to store size of elements 759 760 @return An error code: 0 - success, otherwise - failure 761 762 @ref Advanced 763 **/ 764 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr, CeedInt *elem_size) { 765 *elem_size = rstr->elem_size; 766 return CEED_ERROR_SUCCESS; 767 } 768 769 /** 770 @brief Get the size of the l-vector for a CeedElemRestriction 771 772 @param[in] rstr CeedElemRestriction 773 @param[out] l_size Variable to store number of nodes 774 775 @return An error code: 0 - success, otherwise - failure 776 777 @ref Advanced 778 **/ 779 int CeedElemRestrictionGetLVectorSize(CeedElemRestriction rstr, CeedSize *l_size) { 780 *l_size = rstr->l_size; 781 return CEED_ERROR_SUCCESS; 782 } 783 784 /** 785 @brief Get the number of components in the elements of a CeedElemRestriction 786 787 @param[in] rstr CeedElemRestriction 788 @param[out] num_comp Variable to store number of components 789 790 @return An error code: 0 - success, otherwise - failure 791 792 @ref Advanced 793 **/ 794 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr, CeedInt *num_comp) { 795 *num_comp = rstr->num_comp; 796 return CEED_ERROR_SUCCESS; 797 } 798 799 /** 800 @brief Get the number of blocks in a CeedElemRestriction 801 802 @param[in] rstr CeedElemRestriction 803 @param[out] num_block Variable to store number of blocks 804 805 @return An error code: 0 - success, otherwise - failure 806 807 @ref Advanced 808 **/ 809 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr, CeedInt *num_block) { 810 *num_block = rstr->num_blk; 811 return CEED_ERROR_SUCCESS; 812 } 813 814 /** 815 @brief Get the size of blocks in the CeedElemRestriction 816 817 @param[in] rstr CeedElemRestriction 818 @param[out] blk_size Variable to store size of blocks 819 820 @return An error code: 0 - success, otherwise - failure 821 822 @ref Advanced 823 **/ 824 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr, CeedInt *blk_size) { 825 *blk_size = rstr->blk_size; 826 return CEED_ERROR_SUCCESS; 827 } 828 829 /** 830 @brief Get the multiplicity of nodes in a CeedElemRestriction 831 832 @param[in] rstr CeedElemRestriction 833 @param[out] mult Vector to store multiplicity (of size l_size) 834 835 @return An error code: 0 - success, otherwise - failure 836 837 @ref User 838 **/ 839 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr, CeedVector mult) { 840 CeedVector e_vec; 841 842 // Create e_vec to hold intermediate computation in E^T (E 1) 843 CeedCall(CeedElemRestrictionCreateVector(rstr, NULL, &e_vec)); 844 845 // Compute e_vec = E * 1 846 CeedCall(CeedVectorSetValue(mult, 1.0)); 847 CeedCall(CeedElemRestrictionApply(rstr, CEED_NOTRANSPOSE, mult, e_vec, CEED_REQUEST_IMMEDIATE)); 848 // Compute multiplicity, mult = E^T * e_vec = E^T (E 1) 849 CeedCall(CeedVectorSetValue(mult, 0.0)); 850 CeedCall(CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, e_vec, mult, CEED_REQUEST_IMMEDIATE)); 851 // Cleanup 852 CeedCall(CeedVectorDestroy(&e_vec)); 853 return CEED_ERROR_SUCCESS; 854 } 855 856 /** 857 @brief View a CeedElemRestriction 858 859 @param[in] rstr CeedElemRestriction to view 860 @param[in] stream Stream to write; typically stdout/stderr or a file 861 862 @return Error code: 0 - success, otherwise - failure 863 864 @ref User 865 **/ 866 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) { 867 char stridesstr[500]; 868 if (rstr->strides) { 869 sprintf(stridesstr, "[%" CeedInt_FMT ", %" CeedInt_FMT ", %" CeedInt_FMT "]", rstr->strides[0], rstr->strides[1], rstr->strides[2]); 870 } else { 871 sprintf(stridesstr, "%" CeedInt_FMT, rstr->comp_stride); 872 } 873 874 fprintf(stream, "%sCeedElemRestriction from (%td, %" CeedInt_FMT ") to %" CeedInt_FMT " elements with %" CeedInt_FMT " nodes each and %s %s\n", 875 rstr->blk_size > 1 ? "Blocked " : "", rstr->l_size, rstr->num_comp, rstr->num_elem, rstr->elem_size, 876 rstr->strides ? "strides" : "component stride", stridesstr); 877 return CEED_ERROR_SUCCESS; 878 } 879 880 /** 881 @brief Destroy a CeedElemRestriction 882 883 @param[in,out] rstr CeedElemRestriction to destroy 884 885 @return An error code: 0 - success, otherwise - failure 886 887 @ref User 888 **/ 889 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) { 890 if (!*rstr || *rstr == CEED_ELEMRESTRICTION_NONE || --(*rstr)->ref_count > 0) { 891 *rstr = NULL; 892 return CEED_ERROR_SUCCESS; 893 } 894 CeedCheck((*rstr)->num_readers == 0, (*rstr)->ceed, CEED_ERROR_ACCESS, 895 "Cannot destroy CeedElemRestriction, a process has read access to the offset data"); 896 if ((*rstr)->Destroy) CeedCall((*rstr)->Destroy(*rstr)); 897 CeedCall(CeedFree(&(*rstr)->strides)); 898 CeedCall(CeedDestroy(&(*rstr)->ceed)); 899 CeedCall(CeedFree(rstr)); 900 return CEED_ERROR_SUCCESS; 901 } 902 903 /// @} 904