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