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