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