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