1 // Copyright (c) 2017-2024, 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 <assert.h> 12 #include <math.h> 13 #include <stdbool.h> 14 #include <stdint.h> 15 #include <stdio.h> 16 17 /// @file 18 /// Implementation of public CeedVector interfaces 19 20 /// @cond DOXYGEN_SKIP 21 static struct CeedVector_private ceed_vector_active; 22 static struct CeedVector_private ceed_vector_none; 23 /// @endcond 24 25 /// @addtogroup CeedVectorUser 26 /// @{ 27 28 /// Indicate that vector will be provided as an explicit argument to @ref CeedOperatorApply(). 29 const CeedVector CEED_VECTOR_ACTIVE = &ceed_vector_active; 30 31 /// Indicate that no vector is applicable (i.e., for @ref CEED_EVAL_WEIGHT). 32 const CeedVector CEED_VECTOR_NONE = &ceed_vector_none; 33 34 /// @} 35 36 /// ---------------------------------------------------------------------------- 37 /// CeedVector Backend API 38 /// ---------------------------------------------------------------------------- 39 /// @addtogroup CeedVectorBackend 40 /// @{ 41 42 /** 43 @brief Check for valid data in a `CeedVector` 44 45 @param[in] vec `CeedVector` to check validity 46 @param[out] has_valid_array Variable to store validity 47 48 @return An error code: 0 - success, otherwise - failure 49 50 @ref Backend 51 **/ 52 int CeedVectorHasValidArray(CeedVector vec, bool *has_valid_array) { 53 CeedSize length; 54 55 CeedCheck(vec->HasValidArray, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, "Backend does not support CeedVectorHasValidArray"); 56 CeedCall(CeedVectorGetLength(vec, &length)); 57 if (length == 0) { 58 *has_valid_array = true; 59 return CEED_ERROR_SUCCESS; 60 } 61 CeedCall(vec->HasValidArray(vec, has_valid_array)); 62 return CEED_ERROR_SUCCESS; 63 } 64 65 /** 66 @brief Check for borrowed array of a specific @ref CeedMemType in a `CeedVector` 67 68 @param[in] vec `CeedVector` to check 69 @param[in] mem_type Memory type to check 70 @param[out] has_borrowed_array_of_type Variable to store result 71 72 @return An error code: 0 - success, otherwise - failure 73 74 @ref Backend 75 **/ 76 int CeedVectorHasBorrowedArrayOfType(CeedVector vec, CeedMemType mem_type, bool *has_borrowed_array_of_type) { 77 CeedCheck(vec->HasBorrowedArrayOfType, CeedVectorReturnCeed(vec), CEED_ERROR_UNSUPPORTED, 78 "Backend does not support CeedVectorHasBorrowedArrayOfType"); 79 CeedCall(vec->HasBorrowedArrayOfType(vec, mem_type, has_borrowed_array_of_type)); 80 return CEED_ERROR_SUCCESS; 81 } 82 83 /** 84 @brief Get the state of a `CeedVector` 85 86 @param[in] vec `CeedVector` to retrieve state 87 @param[out] state Variable to store state 88 89 @return An error code: 0 - success, otherwise - failure 90 91 @ref Backend 92 **/ 93 int CeedVectorGetState(CeedVector vec, uint64_t *state) { 94 *state = vec->state; 95 return CEED_ERROR_SUCCESS; 96 } 97 98 /** 99 @brief Get the backend data of a `CeedVector` 100 101 @param[in] vec `CeedVector` to retrieve state 102 @param[out] data Variable to store data 103 104 @return An error code: 0 - success, otherwise - failure 105 106 @ref Backend 107 **/ 108 int CeedVectorGetData(CeedVector vec, void *data) { 109 *(void **)data = vec->data; 110 return CEED_ERROR_SUCCESS; 111 } 112 113 /** 114 @brief Set the backend data of a `CeedVector` 115 116 @param[in,out] vec `CeedVector` to retrieve state 117 @param[in] data Data to set 118 119 @return An error code: 0 - success, otherwise - failure 120 121 @ref Backend 122 **/ 123 int CeedVectorSetData(CeedVector vec, void *data) { 124 vec->data = data; 125 return CEED_ERROR_SUCCESS; 126 } 127 128 /** 129 @brief Increment the reference counter for a `CeedVector` 130 131 @param[in,out] vec `CeedVector` to increment the reference counter 132 133 @return An error code: 0 - success, otherwise - failure 134 135 @ref Backend 136 **/ 137 int CeedVectorReference(CeedVector vec) { 138 vec->ref_count++; 139 return CEED_ERROR_SUCCESS; 140 } 141 142 /// @} 143 144 /// ---------------------------------------------------------------------------- 145 /// CeedVector Public API 146 /// ---------------------------------------------------------------------------- 147 /// @addtogroup CeedVectorUser 148 /// @{ 149 150 /** 151 @brief Create a `CeedVector` of the specified length (does not allocate memory) 152 153 @param[in] ceed `Ceed` object used to create the `CeedVector` 154 @param[in] length Length of vector 155 @param[out] vec Address of the variable where the newly created `CeedVector` will be stored 156 157 @return An error code: 0 - success, otherwise - failure 158 159 @ref User 160 **/ 161 int CeedVectorCreate(Ceed ceed, CeedSize length, CeedVector *vec) { 162 if (!ceed->VectorCreate) { 163 Ceed delegate; 164 165 CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Vector")); 166 CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement VectorCreate"); 167 CeedCall(CeedVectorCreate(delegate, length, vec)); 168 return CEED_ERROR_SUCCESS; 169 } 170 171 CeedCall(CeedCalloc(1, vec)); 172 CeedCall(CeedReferenceCopy(ceed, &(*vec)->ceed)); 173 (*vec)->ref_count = 1; 174 (*vec)->length = length; 175 (*vec)->state = 0; 176 CeedCall(ceed->VectorCreate(length, *vec)); 177 return CEED_ERROR_SUCCESS; 178 } 179 180 /** 181 @brief Copy the pointer to a `CeedVector`. 182 183 Both pointers should be destroyed with @ref CeedVectorDestroy(). 184 185 Note: If the value of `*vec_copy` passed to this function is non-`NULL`, then it is assumed that `*vec_copy` is a pointer to a `CeedVector`. 186 This `CeedVector` will be destroyed if `*vec_copy` is the only reference to this `CeedVector`. 187 188 @param[in] vec `CeedVector` to copy reference to 189 @param[in,out] vec_copy Variable to store copied reference 190 191 @return An error code: 0 - success, otherwise - failure 192 193 @ref User 194 **/ 195 int CeedVectorReferenceCopy(CeedVector vec, CeedVector *vec_copy) { 196 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) CeedCall(CeedVectorReference(vec)); 197 CeedCall(CeedVectorDestroy(vec_copy)); 198 *vec_copy = vec; 199 return CEED_ERROR_SUCCESS; 200 } 201 202 /** 203 @brief Copy a `CeedVector` into a different `CeedVector`. 204 205 Both pointers should be destroyed with @ref CeedVectorDestroy(). 206 207 Note: If `*vec_copy` is non-`NULL`, then it is assumed that `*vec_copy` is a pointer to a `CeedVector`. 208 This `CeedVector` will be destroyed if `*vec_copy` is the only reference to this `CeedVector`. 209 210 @param[in] vec `CeedVector` to copy 211 @param[in,out] vec_copy Variable to store copied `CeedVector` to 212 213 @return An error code: 0 - success, otherwise - failure 214 215 @ref User 216 **/ 217 int CeedVectorCopy(CeedVector vec, CeedVector vec_copy) { 218 Ceed ceed; 219 CeedMemType mem_type, mem_type_copy; 220 CeedScalar *array; 221 222 // Get the preferred memory type 223 CeedCall(CeedVectorGetCeed(vec, &ceed)); 224 CeedCall(CeedGetPreferredMemType(ceed, &mem_type)); 225 226 // Get the preferred memory type 227 CeedCall(CeedVectorGetCeed(vec_copy, &ceed)); 228 CeedCall(CeedGetPreferredMemType(ceed, &mem_type_copy)); 229 230 // Check that both have same memory type 231 if (mem_type != mem_type_copy) mem_type = CEED_MEM_HOST; 232 233 // Copy the values from vec to vec_copy 234 CeedCall(CeedVectorGetArray(vec, mem_type, &array)); 235 CeedCall(CeedVectorSetArray(vec_copy, mem_type, CEED_COPY_VALUES, array)); 236 237 CeedCall(CeedVectorRestoreArray(vec, &array)); 238 return CEED_ERROR_SUCCESS; 239 } 240 241 /** 242 @brief Copy a strided portion of `CeedVector` contents into a different `CeedVector` 243 244 @param[in] vec `CeedVector` to copy 245 @param[in] start First index to copy 246 @param[in] step Stride between indices to copy 247 @param[in,out] vec_copy `CeedVector` to copy values to 248 249 @return An error code: 0 - success, otherwise - failure 250 251 @ref User 252 **/ 253 int CeedVectorCopyStrided(CeedVector vec, CeedSize start, CeedInt step, CeedVector vec_copy) { 254 CeedSize length; 255 const CeedScalar *array; 256 CeedScalar *array_copy; 257 258 // Backend version 259 if (vec->CopyStrided && vec_copy->CopyStrided) { 260 CeedCall(vec->CopyStrided(vec, start, step, vec_copy)); 261 vec_copy->state += 2; 262 return CEED_ERROR_SUCCESS; 263 } 264 265 // Get length 266 { 267 CeedSize length_vec, length_copy; 268 269 CeedCall(CeedVectorGetLength(vec, &length_vec)); 270 CeedCall(CeedVectorGetLength(vec_copy, &length_copy)); 271 length = length_vec > length_copy ? length_vec : length_copy; 272 } 273 274 // Copy 275 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array)); 276 CeedCall(CeedVectorGetArray(vec_copy, CEED_MEM_HOST, &array_copy)); 277 for (CeedSize i = start; i < length; i += step) array_copy[i] = array[i]; 278 279 // Cleanup 280 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 281 CeedCall(CeedVectorRestoreArray(vec_copy, &array_copy)); 282 return CEED_ERROR_SUCCESS; 283 } 284 285 /** 286 @brief Set the array used by a `CeedVector`, freeing any previously allocated array if applicable. 287 288 The backend may copy values to a different @ref CeedMemType, such as during @ref CeedOperatorApply(). 289 See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray(). 290 291 @param[in,out] vec `CeedVector` 292 @param[in] mem_type Memory type of the array being passed 293 @param[in] copy_mode Copy mode for the array 294 @param[in] array Array to be used, or `NULL` with @ref CEED_COPY_VALUES to have the library allocate 295 296 @return An error code: 0 - success, otherwise - failure 297 298 @ref User 299 **/ 300 int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type, CeedCopyMode copy_mode, CeedScalar *array) { 301 CeedSize length; 302 Ceed ceed; 303 304 CeedCall(CeedVectorGetCeed(vec, &ceed)); 305 306 CeedCheck(vec->SetArray, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support VectorSetArray"); 307 CeedCheck(vec->state % 2 == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 308 CeedCheck(vec->num_readers == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 309 310 CeedCall(CeedVectorGetLength(vec, &length)); 311 if (length > 0) CeedCall(vec->SetArray(vec, mem_type, copy_mode, array)); 312 vec->state += 2; 313 return CEED_ERROR_SUCCESS; 314 } 315 316 /** 317 @brief Set the `CeedVector` to a constant value 318 319 @param[in,out] vec `CeedVector` 320 @param[in] value Value to be used 321 322 @return An error code: 0 - success, otherwise - failure 323 324 @ref User 325 **/ 326 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 327 Ceed ceed; 328 329 CeedCall(CeedVectorGetCeed(vec, &ceed)); 330 CeedCheck(vec->state % 2 == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 331 CeedCheck(vec->num_readers == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 332 333 if (vec->SetValue) { 334 CeedCall(vec->SetValue(vec, value)); 335 } else { 336 CeedSize length; 337 CeedScalar *array; 338 339 CeedCall(CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array)); 340 CeedCall(CeedVectorGetLength(vec, &length)); 341 for (CeedSize i = 0; i < length; i++) array[i] = value; 342 CeedCall(CeedVectorRestoreArray(vec, &array)); 343 } 344 vec->state += 2; 345 return CEED_ERROR_SUCCESS; 346 } 347 348 /** 349 @brief Set a portion of a `CeedVector` to a constant value. 350 351 Note: The `CeedVector` must already have valid data set via @ref CeedVectorSetArray() or similar. 352 353 @param[in,out] vec `CeedVector` 354 @param[in] start First index to set 355 @param[in] step Stride between indices to set 356 @param[in] value Value to be used 357 358 @return An error code: 0 - success, otherwise - failure 359 360 @ref User 361 **/ 362 int CeedVectorSetValueStrided(CeedVector vec, CeedSize start, CeedInt step, CeedScalar value) { 363 Ceed ceed; 364 365 CeedCall(CeedVectorGetCeed(vec, &ceed)); 366 CeedCheck(vec->state % 2 == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 367 CeedCheck(vec->num_readers == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 368 369 if (vec->SetValueStrided) { 370 CeedCall(vec->SetValueStrided(vec, start, step, value)); 371 vec_copy->state += 2; 372 } else { 373 CeedSize length; 374 CeedScalar *array; 375 376 CeedCall(CeedVectorGetArray(vec, CEED_MEM_HOST, &array)); 377 CeedCall(CeedVectorGetLength(vec, &length)); 378 for (CeedSize i = start; i < length; i += step) array[i] = value; 379 CeedCall(CeedVectorRestoreArray(vec, &array)); 380 } 381 return CEED_ERROR_SUCCESS; 382 } 383 384 /** 385 @brief Sync the `CeedVector` to a specified `mem_type`. 386 387 This function is used to force synchronization of arrays set with @ref CeedVectorSetArray(). 388 If the requested `mem_type` is already synchronized, this function results in a no-op. 389 390 @param[in,out] vec `CeedVector` 391 @param[in] mem_type @ref CeedMemType to be synced 392 393 @return An error code: 0 - success, otherwise - failure 394 395 @ref User 396 **/ 397 int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) { 398 CeedSize length; 399 400 CeedCheck(vec->state % 2 == 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot sync CeedVector, the access lock is already in use"); 401 402 // Don't sync empty array 403 CeedCall(CeedVectorGetLength(vec, &length)); 404 if (length == 0) return CEED_ERROR_SUCCESS; 405 406 if (vec->SyncArray) { 407 CeedCall(vec->SyncArray(vec, mem_type)); 408 } else { 409 const CeedScalar *array; 410 411 CeedCall(CeedVectorGetArrayRead(vec, mem_type, &array)); 412 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 413 } 414 return CEED_ERROR_SUCCESS; 415 } 416 417 /** 418 @brief Take ownership of the `CeedVector` array set by @ref CeedVectorSetArray() with @ref CEED_USE_POINTER and remove the array from the `CeedVector`. 419 420 The caller is responsible for managing and freeing the array. 421 This function will error if @ref CeedVectorSetArray() was not previously called with @ref CEED_USE_POINTER for the corresponding mem_type. 422 423 @param[in,out] vec `CeedVector` 424 @param[in] mem_type Memory type on which to take the array. 425 If the backend uses a different memory type, this will perform a copy. 426 @param[out] array Array on memory type `mem_type`, or `NULL` if array pointer is not required 427 428 @return An error code: 0 - success, otherwise - failure 429 430 @ref User 431 **/ 432 int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 433 CeedSize length; 434 CeedScalar *temp_array = NULL; 435 Ceed ceed; 436 437 CeedCall(CeedVectorGetCeed(vec, &ceed)); 438 CeedCheck(vec->state % 2 == 0, ceed, CEED_ERROR_ACCESS, "Cannot take CeedVector array, the access lock is already in use"); 439 CeedCheck(vec->num_readers == 0, ceed, CEED_ERROR_ACCESS, "Cannot take CeedVector array, a process has read access"); 440 441 CeedCall(CeedVectorGetLength(vec, &length)); 442 if (length > 0) { 443 bool has_borrowed_array_of_type = true, has_valid_array = true; 444 445 CeedCall(CeedVectorHasBorrowedArrayOfType(vec, mem_type, &has_borrowed_array_of_type)); 446 CeedCheck(has_borrowed_array_of_type, ceed, CEED_ERROR_BACKEND, "CeedVector has no borrowed %s array, must set array with CeedVectorSetArray", 447 CeedMemTypes[mem_type]); 448 449 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 450 CeedCheck(has_valid_array, ceed, CEED_ERROR_BACKEND, 451 "CeedVector has no valid data to take, must set data with CeedVectorSetValue or CeedVectorSetArray"); 452 453 CeedCall(vec->TakeArray(vec, mem_type, &temp_array)); 454 } 455 if (array) (*array) = temp_array; 456 return CEED_ERROR_SUCCESS; 457 } 458 459 /** 460 @brief Get read/write access to a `CeedVector` via the specified memory type. 461 462 Restore access with @ref CeedVectorRestoreArray(). 463 464 @param[in,out] vec `CeedVector` to access 465 @param[in] mem_type Memory type on which to access the array. 466 If the backend uses a different memory type, this will perform a copy. 467 @param[out] array Array on memory type `mem_type` 468 469 @note The @ref CeedVectorGetArray() and @ref CeedVectorRestoreArray() functions provide access to array pointers in the desired memory space. 470 Pairing get/restore allows the `CeedVector` to track access, thus knowing if norms or other operations may need to be recomputed. 471 472 @return An error code: 0 - success, otherwise - failure 473 474 @ref User 475 **/ 476 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 477 CeedSize length; 478 Ceed ceed; 479 480 CeedCall(CeedVectorGetCeed(vec, &ceed)); 481 CeedCheck(vec->GetArray, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetArray"); 482 CeedCheck(vec->state % 2 == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 483 CeedCheck(vec->num_readers == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 484 485 CeedCall(CeedVectorGetLength(vec, &length)); 486 if (length > 0) { 487 bool has_valid_array = true; 488 489 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 490 CeedCheck(has_valid_array, ceed, CEED_ERROR_BACKEND, 491 "CeedVector has no valid data to read, must set data with CeedVectorSetValue or CeedVectorSetArray"); 492 493 CeedCall(vec->GetArray(vec, mem_type, array)); 494 } else { 495 *array = NULL; 496 } 497 vec->state++; 498 return CEED_ERROR_SUCCESS; 499 } 500 501 /** 502 @brief Get read-only access to a `CeedVector` via the specified memory type. 503 504 Restore access with @ref CeedVectorRestoreArrayRead(). 505 506 @param[in] vec `CeedVector` to access 507 @param[in] mem_type Memory type on which to access the array. 508 If the backend uses a different memory type, this will perform a copy (possibly cached). 509 @param[out] array Array on memory type `mem_type` 510 511 @return An error code: 0 - success, otherwise - failure 512 513 @ref User 514 **/ 515 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type, const CeedScalar **array) { 516 CeedSize length; 517 Ceed ceed; 518 519 CeedCall(CeedVectorGetCeed(vec, &ceed)); 520 CeedCheck(vec->GetArrayRead, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetArrayRead"); 521 CeedCheck(vec->state % 2 == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector read-only array access, the access lock is already in use"); 522 523 CeedCall(CeedVectorGetLength(vec, &length)); 524 if (length > 0) { 525 bool has_valid_array = true; 526 527 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 528 CeedCheck(has_valid_array, ceed, CEED_ERROR_BACKEND, 529 "CeedVector has no valid data to read, must set data with CeedVectorSetValue or CeedVectorSetArray"); 530 531 CeedCall(vec->GetArrayRead(vec, mem_type, array)); 532 } else { 533 *array = NULL; 534 } 535 vec->num_readers++; 536 return CEED_ERROR_SUCCESS; 537 } 538 539 /** 540 @brief Get write access to a `CeedVector` via the specified memory type. 541 542 Restore access with @ref CeedVectorRestoreArray(). 543 All old values should be assumed to be invalid. 544 545 @param[in,out] vec `CeedVector` to access 546 @param[in] mem_type Memory type on which to access the array. 547 @param[out] array Array on memory type `mem_type` 548 549 @return An error code: 0 - success, otherwise - failure 550 551 @ref User 552 **/ 553 int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 554 CeedSize length; 555 Ceed ceed; 556 557 CeedCall(CeedVectorGetCeed(vec, &ceed)); 558 CeedCheck(vec->GetArrayWrite, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedVectorGetArrayWrite"); 559 CeedCheck(vec->state % 2 == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 560 CeedCheck(vec->num_readers == 0, ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 561 562 CeedCall(CeedVectorGetLength(vec, &length)); 563 if (length > 0) { 564 CeedCall(vec->GetArrayWrite(vec, mem_type, array)); 565 } else { 566 *array = NULL; 567 } 568 vec->state++; 569 return CEED_ERROR_SUCCESS; 570 } 571 572 /** 573 @brief Restore an array obtained using @ref CeedVectorGetArray() or @ref CeedVectorGetArrayWrite() 574 575 @param[in,out] vec `CeedVector` to restore 576 @param[in,out] array Array of vector data 577 578 @return An error code: 0 - success, otherwise - failure 579 580 @ref User 581 **/ 582 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 583 CeedSize length; 584 585 CeedCheck(vec->state % 2 == 1, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, "Cannot restore CeedVector array access, access was not granted"); 586 CeedCall(CeedVectorGetLength(vec, &length)); 587 if (length > 0 && vec->RestoreArray) CeedCall(vec->RestoreArray(vec)); 588 *array = NULL; 589 vec->state++; 590 return CEED_ERROR_SUCCESS; 591 } 592 593 /** 594 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 595 596 @param[in] vec `CeedVector` to restore 597 @param[in,out] array Array of vector data 598 599 @return An error code: 0 - success, otherwise - failure 600 601 @ref User 602 **/ 603 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 604 CeedSize length; 605 606 CeedCheck(vec->num_readers > 0, CeedVectorReturnCeed(vec), CEED_ERROR_ACCESS, 607 "Cannot restore CeedVector array read access, access was not granted"); 608 vec->num_readers--; 609 CeedCall(CeedVectorGetLength(vec, &length)); 610 if (length > 0 && vec->num_readers == 0 && vec->RestoreArrayRead) CeedCall(vec->RestoreArrayRead(vec)); 611 *array = NULL; 612 return CEED_ERROR_SUCCESS; 613 } 614 615 /** 616 @brief Get the norm of a `CeedVector`. 617 618 Note: This operation is local to the `CeedVector`. 619 This function will likely not provide the desired results for the norm of the libCEED portion of a parallel vector or a `CeedVector` with duplicated or hanging nodes. 620 621 @param[in] vec `CeedVector` to retrieve maximum value 622 @param[in] norm_type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 623 @param[out] norm Variable to store norm value 624 625 @return An error code: 0 - success, otherwise - failure 626 627 @ref User 628 **/ 629 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) { 630 bool has_valid_array = true; 631 CeedSize length; 632 633 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 634 CeedCheck(has_valid_array, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 635 "CeedVector has no valid data to compute norm, must set data with CeedVectorSetValue or CeedVectorSetArray"); 636 637 CeedCall(CeedVectorGetLength(vec, &length)); 638 if (length == 0) { 639 *norm = 0; 640 return CEED_ERROR_SUCCESS; 641 } 642 643 // Backend impl for GPU, if added 644 if (vec->Norm) { 645 CeedCall(vec->Norm(vec, norm_type, norm)); 646 return CEED_ERROR_SUCCESS; 647 } 648 649 const CeedScalar *array; 650 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array)); 651 assert(array); 652 653 *norm = 0.; 654 switch (norm_type) { 655 case CEED_NORM_1: 656 for (CeedSize i = 0; i < length; i++) { 657 *norm += fabs(array[i]); 658 } 659 break; 660 case CEED_NORM_2: 661 for (CeedSize i = 0; i < length; i++) { 662 *norm += fabs(array[i]) * fabs(array[i]); 663 } 664 break; 665 case CEED_NORM_MAX: 666 for (CeedSize i = 0; i < length; i++) { 667 const CeedScalar abs_v_i = fabs(array[i]); 668 *norm = *norm > abs_v_i ? *norm : abs_v_i; 669 } 670 } 671 if (norm_type == CEED_NORM_2) *norm = sqrt(*norm); 672 673 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 674 return CEED_ERROR_SUCCESS; 675 } 676 677 /** 678 @brief Compute `x = alpha x` 679 680 @param[in,out] x `CeedVector` for scaling 681 @param[in] alpha scaling factor 682 683 @return An error code: 0 - success, otherwise - failure 684 685 @ref User 686 **/ 687 int CeedVectorScale(CeedVector x, CeedScalar alpha) { 688 bool has_valid_array = true; 689 CeedSize length; 690 CeedScalar *x_array = NULL; 691 692 CeedCall(CeedVectorHasValidArray(x, &has_valid_array)); 693 CeedCheck(has_valid_array, CeedVectorReturnCeed(x), CEED_ERROR_BACKEND, 694 "CeedVector has no valid data to scale, must set data with CeedVectorSetValue or CeedVectorSetArray"); 695 696 // Return early for empty vector 697 CeedCall(CeedVectorGetLength(x, &length)); 698 if (length == 0) return CEED_ERROR_SUCCESS; 699 700 // Backend implementation 701 if (x->Scale) return x->Scale(x, alpha); 702 703 // Default implementation 704 CeedCall(CeedVectorGetArray(x, CEED_MEM_HOST, &x_array)); 705 assert(x_array); 706 for (CeedSize i = 0; i < length; i++) x_array[i] *= alpha; 707 CeedCall(CeedVectorRestoreArray(x, &x_array)); 708 return CEED_ERROR_SUCCESS; 709 } 710 711 /** 712 @brief Compute `y = alpha x + y` 713 714 @param[in,out] y target `CeedVector` for sum 715 @param[in] alpha scaling factor 716 @param[in] x second `CeedVector`, must be different than ``y` 717 718 @return An error code: 0 - success, otherwise - failure 719 720 @ref User 721 **/ 722 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) { 723 bool has_valid_array_x = true, has_valid_array_y = true; 724 CeedSize length_x, length_y; 725 CeedScalar *y_array = NULL; 726 CeedScalar const *x_array = NULL; 727 Ceed ceed, ceed_parent_x, ceed_parent_y; 728 729 CeedCall(CeedVectorGetCeed(y, &ceed)); 730 CeedCall(CeedVectorGetLength(y, &length_y)); 731 CeedCall(CeedVectorGetLength(x, &length_x)); 732 CeedCheck(length_x == length_y, ceed, CEED_ERROR_UNSUPPORTED, "Cannot add vector of different lengths"); 733 CeedCheck(x != y, ceed, CEED_ERROR_UNSUPPORTED, "Cannot use same vector for x and y in CeedVectorAXPY"); 734 735 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 736 CeedCheck(has_valid_array_x, ceed, CEED_ERROR_BACKEND, 737 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 738 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 739 CeedCheck(has_valid_array_y, ceed, CEED_ERROR_BACKEND, 740 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 741 742 CeedCall(CeedGetParent(x->ceed, &ceed_parent_x)); 743 CeedCall(CeedGetParent(y->ceed, &ceed_parent_y)); 744 CeedCheck(ceed_parent_x == ceed_parent_y, ceed, CEED_ERROR_INCOMPATIBLE, "Vectors x and y must be created by the same Ceed context"); 745 746 // Return early for empty vectors 747 if (length_y == 0) return CEED_ERROR_SUCCESS; 748 749 // Backend implementation 750 if (y->AXPY) { 751 CeedCall(y->AXPY(y, alpha, x)); 752 return CEED_ERROR_SUCCESS; 753 } 754 755 // Default implementation 756 CeedCall(CeedVectorGetArray(y, CEED_MEM_HOST, &y_array)); 757 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 758 759 assert(x_array); 760 assert(y_array); 761 762 for (CeedSize i = 0; i < length_y; i++) y_array[i] += alpha * x_array[i]; 763 764 CeedCall(CeedVectorRestoreArray(y, &y_array)); 765 CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 766 return CEED_ERROR_SUCCESS; 767 } 768 769 /** 770 @brief Compute `y = alpha x + beta y` 771 772 @param[in,out] y target `CeedVector` for sum 773 @param[in] alpha first scaling factor 774 @param[in] beta second scaling factor 775 @param[in] x second `CeedVector`, must be different than `y` 776 777 @return An error code: 0 - success, otherwise - failure 778 779 @ref User 780 **/ 781 int CeedVectorAXPBY(CeedVector y, CeedScalar alpha, CeedScalar beta, CeedVector x) { 782 bool has_valid_array_x = true, has_valid_array_y = true; 783 CeedSize length_x, length_y; 784 CeedScalar *y_array = NULL; 785 CeedScalar const *x_array = NULL; 786 Ceed ceed, ceed_parent_x, ceed_parent_y; 787 788 CeedCall(CeedVectorGetCeed(y, &ceed)); 789 790 CeedCall(CeedVectorGetLength(y, &length_y)); 791 CeedCall(CeedVectorGetLength(x, &length_x)); 792 CeedCheck(length_x == length_y, ceed, CEED_ERROR_UNSUPPORTED, "Cannot add vector of different lengths"); 793 CeedCheck(x != y, ceed, CEED_ERROR_UNSUPPORTED, "Cannot use same vector for x and y in CeedVectorAXPBY"); 794 795 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 796 CeedCheck(has_valid_array_x, ceed, CEED_ERROR_BACKEND, 797 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 798 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 799 CeedCheck(has_valid_array_y, ceed, CEED_ERROR_BACKEND, 800 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 801 802 CeedCall(CeedGetParent(x->ceed, &ceed_parent_x)); 803 CeedCall(CeedGetParent(y->ceed, &ceed_parent_y)); 804 CeedCheck(ceed_parent_x == ceed_parent_y, ceed, CEED_ERROR_INCOMPATIBLE, "Vectors x and y must be created by the same Ceed context"); 805 806 // Return early for empty vectors 807 if (length_y == 0) return CEED_ERROR_SUCCESS; 808 809 // Backend implementation 810 if (y->AXPBY) { 811 CeedCall(y->AXPBY(y, alpha, beta, x)); 812 return CEED_ERROR_SUCCESS; 813 } 814 815 // Default implementation 816 CeedCall(CeedVectorGetArray(y, CEED_MEM_HOST, &y_array)); 817 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 818 819 assert(x_array); 820 assert(y_array); 821 822 for (CeedSize i = 0; i < length_y; i++) y_array[i] = alpha * x_array[i] + beta * y_array[i]; 823 824 CeedCall(CeedVectorRestoreArray(y, &y_array)); 825 CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 826 return CEED_ERROR_SUCCESS; 827 } 828 829 /** 830 @brief Compute the pointwise multiplication \f$w = x .* y\f$. 831 832 Any subset of `x`, `y`, and `w` may be the same `CeedVector`. 833 834 @param[out] w target `CeedVector` for the product 835 @param[in] x first `CeedVector` for product 836 @param[in] y second `CeedVector` for the product 837 838 @return An error code: 0 - success, otherwise - failure 839 840 @ref User 841 **/ 842 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) { 843 bool has_valid_array_x = true, has_valid_array_y = true; 844 CeedScalar *w_array = NULL; 845 CeedScalar const *x_array = NULL, *y_array = NULL; 846 CeedSize length_w, length_x, length_y; 847 Ceed ceed, ceed_parent_w, ceed_parent_x, ceed_parent_y; 848 849 CeedCall(CeedVectorGetCeed(w, &ceed)); 850 CeedCall(CeedVectorGetLength(w, &length_w)); 851 CeedCall(CeedVectorGetLength(x, &length_x)); 852 CeedCall(CeedVectorGetLength(y, &length_y)); 853 CeedCheck(length_w == length_x && length_w == length_y, ceed, CEED_ERROR_UNSUPPORTED, "Cannot multiply vectors of different lengths"); 854 855 CeedCall(CeedGetParent(w->ceed, &ceed_parent_w)); 856 CeedCall(CeedGetParent(x->ceed, &ceed_parent_x)); 857 CeedCall(CeedGetParent(y->ceed, &ceed_parent_y)); 858 CeedCheck(ceed_parent_w == ceed_parent_x && ceed_parent_w == ceed_parent_y, ceed, CEED_ERROR_INCOMPATIBLE, 859 "Vectors w, x, and y must be created by the same Ceed context"); 860 861 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 862 CeedCheck(has_valid_array_x, ceed, CEED_ERROR_BACKEND, 863 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 864 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 865 CeedCheck(has_valid_array_y, ceed, CEED_ERROR_BACKEND, 866 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 867 868 // Return early for empty vectors 869 if (length_w == 0) return CEED_ERROR_SUCCESS; 870 871 // Backend implementation 872 if (w->PointwiseMult) { 873 CeedCall(w->PointwiseMult(w, x, y)); 874 return CEED_ERROR_SUCCESS; 875 } 876 877 // Default implementation 878 if (x == w || y == w) { 879 CeedCall(CeedVectorGetArray(w, CEED_MEM_HOST, &w_array)); 880 } else { 881 CeedCall(CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array)); 882 } 883 if (x != w) { 884 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 885 } else { 886 x_array = w_array; 887 } 888 if (y != w && y != x) { 889 CeedCall(CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array)); 890 } else if (y == x) { 891 y_array = x_array; 892 } else if (y == w) { 893 y_array = w_array; 894 } 895 896 assert(w_array); 897 assert(x_array); 898 assert(y_array); 899 900 for (CeedSize i = 0; i < length_w; i++) w_array[i] = x_array[i] * y_array[i]; 901 902 if (y != w && y != x) CeedCall(CeedVectorRestoreArrayRead(y, &y_array)); 903 if (x != w) CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 904 CeedCall(CeedVectorRestoreArray(w, &w_array)); 905 return CEED_ERROR_SUCCESS; 906 } 907 908 /** 909 @brief Take the reciprocal of a `CeedVector`. 910 911 @param[in,out] vec `CeedVector` to take reciprocal 912 913 @return An error code: 0 - success, otherwise - failure 914 915 @ref User 916 **/ 917 int CeedVectorReciprocal(CeedVector vec) { 918 bool has_valid_array = true; 919 CeedSize length; 920 CeedScalar *array; 921 Ceed ceed; 922 923 CeedCall(CeedVectorGetCeed(vec, &ceed)); 924 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 925 CeedCheck(has_valid_array, ceed, CEED_ERROR_BACKEND, 926 "CeedVector has no valid data to compute reciprocal, must set data with CeedVectorSetValue or CeedVectorSetArray"); 927 928 // Check if vector data set 929 CeedCheck(vec->state > 0, ceed, CEED_ERROR_INCOMPLETE, "CeedVector must have data set to take reciprocal"); 930 931 // Return early for empty vector 932 CeedCall(CeedVectorGetLength(vec, &length)); 933 if (length == 0) return CEED_ERROR_SUCCESS; 934 935 // Backend impl for GPU, if added 936 if (vec->Reciprocal) { 937 CeedCall(vec->Reciprocal(vec)); 938 return CEED_ERROR_SUCCESS; 939 } 940 941 CeedCall(CeedVectorGetArray(vec, CEED_MEM_HOST, &array)); 942 for (CeedSize i = 0; i < length; i++) { 943 if (fabs(array[i]) > CEED_EPSILON) array[i] = 1. / array[i]; 944 } 945 946 CeedCall(CeedVectorRestoreArray(vec, &array)); 947 return CEED_ERROR_SUCCESS; 948 } 949 950 /** 951 @brief View a `CeedVector` 952 953 Note: It is safe to use any unsigned values for `start` or `stop` and any nonzero integer for `step`. 954 Any portion of the provided range that is outside the range of valid indices for the `CeedVector` will be ignored. 955 956 @param[in] vec `CeedVector` to view 957 @param[in] start Index of first `CeedVector` entry to view 958 @param[in] stop Index of last `CeedVector` entry to view 959 @param[in] step Step between `CeedVector` entries to view 960 @param[in] fp_fmt Printing format 961 @param[in] stream Filestream to write to 962 963 @return An error code: 0 - success, otherwise - failure 964 965 @ref User 966 **/ 967 int CeedVectorViewRange(CeedVector vec, CeedSize start, CeedSize stop, CeedInt step, const char *fp_fmt, FILE *stream) { 968 char fmt[1024]; 969 CeedSize length; 970 const CeedScalar *x; 971 972 CeedCheck(step != 0, CeedVectorReturnCeed(vec), CEED_ERROR_MINOR, "View range 'step' must be nonzero"); 973 974 CeedCall(CeedVectorGetLength(vec, &length)); 975 fprintf(stream, "CeedVector length %" CeedSize_FMT "\n", length); 976 if (start != 0 || stop != length || step != 1) { 977 fprintf(stream, " start: %" CeedSize_FMT "\n stop: %" CeedSize_FMT "\n step: %" CeedInt_FMT "\n", start, stop, step); 978 } 979 if (start > length) start = length; 980 if (stop > length) stop = length; 981 982 snprintf(fmt, sizeof fmt, " %s\n", fp_fmt ? fp_fmt : "%g"); 983 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x)); 984 for (CeedSize i = start; step > 0 ? (i < stop) : (i > stop); i += step) fprintf(stream, fmt, x[i]); 985 CeedCall(CeedVectorRestoreArrayRead(vec, &x)); 986 if (stop != length) fprintf(stream, " ...\n"); 987 return CEED_ERROR_SUCCESS; 988 } 989 990 /** 991 @brief View a `CeedVector` 992 993 @param[in] vec `CeedVector` to view 994 @param[in] fp_fmt Printing format 995 @param[in] stream Filestream to write to 996 997 @return An error code: 0 - success, otherwise - failure 998 999 @ref User 1000 **/ 1001 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) { 1002 CeedSize length; 1003 1004 CeedCall(CeedVectorGetLength(vec, &length)); 1005 CeedCall(CeedVectorViewRange(vec, 0, length, 1, fp_fmt, stream)); 1006 return CEED_ERROR_SUCCESS; 1007 } 1008 1009 /** 1010 @brief Get the `Ceed` associated with a `CeedVector` 1011 1012 @param[in] vec `CeedVector` to retrieve state 1013 @param[out] ceed Variable to store `Ceed` 1014 1015 @return An error code: 0 - success, otherwise - failure 1016 1017 @ref Advanced 1018 **/ 1019 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) { 1020 *ceed = CeedVectorReturnCeed(vec); 1021 return CEED_ERROR_SUCCESS; 1022 } 1023 1024 /** 1025 @brief Return the `Ceed` associated with a `CeedVector` 1026 1027 @param[in] vec `CeedVector` to retrieve state 1028 1029 @return `Ceed` associated with the `vec` 1030 1031 @ref Advanced 1032 **/ 1033 Ceed CeedVectorReturnCeed(CeedVector vec) { return vec->ceed; } 1034 1035 /** 1036 @brief Get the length of a `CeedVector` 1037 1038 @param[in] vec `CeedVector` to retrieve length 1039 @param[out] length Variable to store length 1040 1041 @return An error code: 0 - success, otherwise - failure 1042 1043 @ref User 1044 **/ 1045 int CeedVectorGetLength(CeedVector vec, CeedSize *length) { 1046 *length = vec->length; 1047 return CEED_ERROR_SUCCESS; 1048 } 1049 1050 /** 1051 @brief Destroy a `CeedVector` 1052 1053 @param[in,out] vec `CeedVector` to destroy 1054 1055 @return An error code: 0 - success, otherwise - failure 1056 1057 @ref User 1058 **/ 1059 int CeedVectorDestroy(CeedVector *vec) { 1060 if (!*vec || *vec == CEED_VECTOR_ACTIVE || *vec == CEED_VECTOR_NONE || --(*vec)->ref_count > 0) { 1061 *vec = NULL; 1062 return CEED_ERROR_SUCCESS; 1063 } 1064 CeedCheck((*vec)->state % 2 == 0, (*vec)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedVector, the writable access lock is in use"); 1065 CeedCheck((*vec)->num_readers == 0, (*vec)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedVector, a process has read access"); 1066 1067 if ((*vec)->Destroy) CeedCall((*vec)->Destroy(*vec)); 1068 1069 CeedCall(CeedDestroy(&(*vec)->ceed)); 1070 CeedCall(CeedFree(vec)); 1071 return CEED_ERROR_SUCCESS; 1072 } 1073 1074 /// @} 1075