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