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 391 bool has_borrowed_array_of_type = true; 392 ierr = CeedVectorHasBorrowedArrayOfType(vec, mem_type, 393 &has_borrowed_array_of_type); 394 CeedChk(ierr); 395 if (!has_borrowed_array_of_type) 396 // LCOV_EXCL_START 397 return CeedError(vec->ceed, CEED_ERROR_BACKEND, 398 "CeedVector has no borrowed %s array, " 399 "must set array with CeedVectorSetArray", CeedMemTypes[mem_type]); 400 // LCOV_EXCL_STOP 401 402 bool has_valid_array = true; 403 ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr); 404 if (!has_valid_array) 405 // LCOV_EXCL_START 406 return CeedError(vec->ceed, CEED_ERROR_BACKEND, 407 "CeedVector has no valid data to take, " 408 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 409 // LCOV_EXCL_STOP 410 411 CeedScalar *temp_array = NULL; 412 ierr = vec->TakeArray(vec, mem_type, &temp_array); CeedChk(ierr); 413 if (array) (*array) = temp_array; 414 return CEED_ERROR_SUCCESS; 415 } 416 417 /** 418 @brief Get read/write access to a CeedVector via the specified memory type. 419 Restore access with @ref CeedVectorRestoreArray(). 420 421 @param vec CeedVector to access 422 @param mem_type Memory type on which to access the array. If the backend 423 uses a different memory type, this will perform a copy. 424 @param[out] array Array on memory type mem_type 425 426 @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide 427 access to array pointers in the desired memory space. Pairing get/restore 428 allows the Vector to track access, thus knowing if norms or other 429 operations may need to be recomputed. 430 431 @return An error code: 0 - success, otherwise - failure 432 433 @ref User 434 **/ 435 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type, 436 CeedScalar **array) { 437 int ierr; 438 439 if (!vec->GetArray) 440 // LCOV_EXCL_START 441 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 442 "Backend does not support GetArray"); 443 // LCOV_EXCL_STOP 444 445 if (vec->state % 2 == 1) 446 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 447 "Cannot grant CeedVector array access, the " 448 "access lock is already in use"); 449 450 if (vec->num_readers > 0) 451 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 452 "Cannot grant CeedVector array access, a " 453 "process has read access"); 454 455 bool has_valid_array = true; 456 ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr); 457 if (!has_valid_array) 458 // LCOV_EXCL_START 459 return CeedError(vec->ceed, CEED_ERROR_BACKEND, 460 "CeedVector has no valid data to read, " 461 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 462 // LCOV_EXCL_STOP 463 464 ierr = vec->GetArray(vec, mem_type, array); CeedChk(ierr); 465 vec->state += 1; 466 return CEED_ERROR_SUCCESS; 467 } 468 469 /** 470 @brief Get read-only access to a CeedVector via the specified memory type. 471 Restore access with @ref CeedVectorRestoreArrayRead(). 472 473 @param vec CeedVector to access 474 @param mem_type Memory type on which to access the array. If the backend 475 uses a different memory type, this will perform a copy 476 (possibly cached). 477 @param[out] array Array on memory type mem_type 478 479 @return An error code: 0 - success, otherwise - failure 480 481 @ref User 482 **/ 483 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type, 484 const CeedScalar **array) { 485 int ierr; 486 487 if (!vec->GetArrayRead) 488 // LCOV_EXCL_START 489 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 490 "Backend does not support GetArrayRead"); 491 // LCOV_EXCL_STOP 492 493 if (vec->state % 2 == 1) 494 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 495 "Cannot grant CeedVector read-only array " 496 "access, the access lock is already in use"); 497 498 bool has_valid_array = true; 499 ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr); 500 if (!has_valid_array) 501 // LCOV_EXCL_START 502 return CeedError(vec->ceed, CEED_ERROR_BACKEND, 503 "CeedVector has no valid data to read, " 504 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 505 // LCOV_EXCL_STOP 506 507 ierr = vec->GetArrayRead(vec, mem_type, array); CeedChk(ierr); 508 vec->num_readers++; 509 return CEED_ERROR_SUCCESS; 510 } 511 512 /** 513 @brief Get write access to a CeedVector via the specified memory type. 514 Restore access with @ref CeedVectorRestoreArray(). All old 515 values should be assumed to be invalid. 516 517 @param vec CeedVector to access 518 @param mem_type Memory type on which to access the array. 519 @param[out] array Array on memory type mem_type 520 521 @return An error code: 0 - success, otherwise - failure 522 523 @ref User 524 **/ 525 int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type, 526 CeedScalar **array) { 527 int ierr; 528 529 if (!vec->GetArrayWrite) 530 // LCOV_EXCL_START 531 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 532 "Backend does not support GetArrayWrite"); 533 // LCOV_EXCL_STOP 534 535 if (vec->state % 2 == 1) 536 // LCOV_EXCL_START 537 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 538 "Cannot grant CeedVector array access, the " 539 "access lock is already in use"); 540 // LCOV_EXCL_STOP 541 542 if (vec->num_readers > 0) 543 // LCOV_EXCL_START 544 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 545 "Cannot grant CeedVector array access, a " 546 "process has read access"); 547 // LCOV_EXCL_STOP 548 549 ierr = vec->GetArrayWrite(vec, mem_type, array); CeedChk(ierr); 550 vec->state += 1; 551 return CEED_ERROR_SUCCESS; 552 } 553 554 /** 555 @brief Restore an array obtained using @ref CeedVectorGetArray() 556 557 @param vec CeedVector to restore 558 @param array Array of vector data 559 560 @return An error code: 0 - success, otherwise - failure 561 562 @ref User 563 **/ 564 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 565 int ierr; 566 567 if (!vec->RestoreArray) 568 // LCOV_EXCL_START 569 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 570 "Backend does not support RestoreArray"); 571 // LCOV_EXCL_STOP 572 573 if (vec->state % 2 != 1) 574 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 575 "Cannot restore CeedVector array access, " 576 "access was not granted"); 577 578 ierr = vec->RestoreArray(vec); CeedChk(ierr); 579 *array = NULL; 580 vec->state += 1; 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->RestoreArrayRead) 598 // LCOV_EXCL_START 599 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 600 "Backend does not support RestoreArrayRead"); 601 // LCOV_EXCL_STOP 602 603 if (vec->num_readers == 0) 604 // LCOV_EXCL_START 605 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 606 "Cannot restore CeedVector array read access, " 607 "access was not granted"); 608 // LCOV_EXCL_STOP 609 610 ierr = vec->RestoreArrayRead(vec); CeedChk(ierr); 611 *array = NULL; 612 vec->num_readers--; 613 return CEED_ERROR_SUCCESS; 614 } 615 616 /** 617 @brief Get the norm of a CeedVector. 618 619 Note: This operation is local to the CeedVector. This function will likely 620 not provide the desired results for the norm of the libCEED portion 621 of a parallel vector or a CeedVector with duplicated or hanging nodes. 622 623 @param vec CeedVector to retrieve maximum value 624 @param norm_type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 625 @param[out] norm Variable to store norm value 626 627 @return An error code: 0 - success, otherwise - failure 628 629 @ref User 630 **/ 631 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) { 632 int ierr; 633 634 bool has_valid_array = true; 635 ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr); 636 if (!has_valid_array) 637 // LCOV_EXCL_START 638 return CeedError(vec->ceed, CEED_ERROR_BACKEND, 639 "CeedVector has no valid data to compute norm, " 640 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 641 // LCOV_EXCL_STOP 642 643 // Backend impl for GPU, if added 644 if (vec->Norm) { 645 ierr = vec->Norm(vec, norm_type, norm); CeedChk(ierr); 646 return CEED_ERROR_SUCCESS; 647 } 648 649 const CeedScalar *array; 650 ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 651 652 *norm = 0.; 653 switch (norm_type) { 654 case CEED_NORM_1: 655 for (int i=0; i<vec->length; i++) { 656 *norm += fabs(array[i]); 657 } 658 break; 659 case CEED_NORM_2: 660 for (int i=0; i<vec->length; i++) { 661 *norm += fabs(array[i])*fabs(array[i]); 662 } 663 break; 664 case CEED_NORM_MAX: 665 for (int i=0; i<vec->length; i++) { 666 const CeedScalar abs_v_i = fabs(array[i]); 667 *norm = *norm > abs_v_i ? *norm : abs_v_i; 668 } 669 } 670 if (norm_type == CEED_NORM_2) 671 *norm = sqrt(*norm); 672 673 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 674 return CEED_ERROR_SUCCESS; 675 } 676 677 /** 678 @brief Compute x = alpha x 679 680 @param[in,out] x vector for scaling 681 @param[in] alpha scaling factor 682 683 @return An error code: 0 - success, otherwise - failure 684 685 @ref User 686 **/ 687 int CeedVectorScale(CeedVector x, CeedScalar alpha) { 688 int ierr; 689 CeedScalar *x_array; 690 CeedInt n_x; 691 692 bool has_valid_array = true; 693 ierr = CeedVectorHasValidArray(x, &has_valid_array); CeedChk(ierr); 694 if (!has_valid_array) 695 // LCOV_EXCL_START 696 return CeedError(x->ceed, CEED_ERROR_BACKEND, 697 "CeedVector has no valid data to scale, " 698 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 699 // LCOV_EXCL_STOP 700 701 ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr); 702 703 // Backend implementation 704 if (x->Scale) 705 return x->Scale(x, alpha); 706 707 // Default implementation 708 ierr = CeedVectorGetArrayWrite(x, CEED_MEM_HOST, &x_array); CeedChk(ierr); 709 for (CeedInt i=0; i<n_x; i++) 710 x_array[i] *= alpha; 711 ierr = CeedVectorRestoreArray(x, &x_array); CeedChk(ierr); 712 713 return CEED_ERROR_SUCCESS; 714 } 715 716 /** 717 @brief Compute y = alpha x + y 718 719 @param[in,out] y target vector for sum 720 @param[in] alpha scaling factor 721 @param[in] x second vector, must be different than y 722 723 @return An error code: 0 - success, otherwise - failure 724 725 @ref User 726 **/ 727 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) { 728 int ierr; 729 CeedScalar *y_array; 730 CeedScalar const *x_array; 731 CeedInt n_x, n_y; 732 733 ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr); 734 ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr); 735 if (n_x != n_y) 736 // LCOV_EXCL_START 737 return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED, 738 "Cannot add vector of different lengths"); 739 // LCOV_EXCL_STOP 740 if (x == y) 741 // LCOV_EXCL_START 742 return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED, 743 "Cannot use same vector for x and y in CeedVectorAXPY"); 744 // LCOV_EXCL_STOP 745 746 bool has_valid_array_x = true, has_valid_array_y = true; 747 ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr); 748 if (!has_valid_array_x) 749 // LCOV_EXCL_START 750 return CeedError(x->ceed, CEED_ERROR_BACKEND, 751 "CeedVector x has no valid data, " 752 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 753 // LCOV_EXCL_STOP 754 ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr); 755 if (!has_valid_array_y) 756 // LCOV_EXCL_START 757 return CeedError(y->ceed, CEED_ERROR_BACKEND, 758 "CeedVector y has no valid data, " 759 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 760 // LCOV_EXCL_STOP 761 762 Ceed ceed_parent_x, ceed_parent_y; 763 ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr); 764 ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr); 765 if (ceed_parent_x != ceed_parent_y) 766 // LCOV_EXCL_START 767 return CeedError(y->ceed, CEED_ERROR_INCOMPATIBLE, 768 "Vectors x and y must be created by the same Ceed context"); 769 // LCOV_EXCL_STOP 770 771 // Backend implementation 772 if (y->AXPY) { 773 ierr = y->AXPY(y, alpha, x); CeedChk(ierr); 774 return CEED_ERROR_SUCCESS; 775 } 776 777 // Default implementation 778 ierr = CeedVectorGetArrayWrite(y, CEED_MEM_HOST, &y_array); CeedChk(ierr); 779 ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr); 780 781 for (CeedInt i=0; i<n_y; i++) 782 y_array[i] += alpha * x_array[i]; 783 784 ierr = CeedVectorRestoreArray(y, &y_array); CeedChk(ierr); 785 ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr); 786 787 return CEED_ERROR_SUCCESS; 788 } 789 790 /** 791 @brief Compute the pointwise multiplication w = x .* y. Any 792 subset of x, y, and w may be the same vector. 793 794 @param[out] w target vector for the product 795 @param[in] x first vector for product 796 @param[in] y second vector for the product 797 798 @return An error code: 0 - success, otherwise - failure 799 800 @ ref User 801 **/ 802 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) { 803 int ierr; 804 CeedScalar *w_array; 805 CeedScalar const *x_array, *y_array; 806 CeedInt n_w, n_x, n_y; 807 808 ierr = CeedVectorGetLength(w, &n_w); CeedChk(ierr); 809 ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr); 810 ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr); 811 if (n_w != n_x || n_w != n_y) 812 // LCOV_EXCL_START 813 return CeedError(w->ceed, CEED_ERROR_UNSUPPORTED, 814 "Cannot multiply vectors of different lengths"); 815 // LCOV_EXCL_STOP 816 817 Ceed ceed_parent_w, ceed_parent_x, ceed_parent_y; 818 ierr = CeedGetParent(w->ceed, &ceed_parent_w); CeedChk(ierr); 819 ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr); 820 ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr); 821 if ((ceed_parent_w != ceed_parent_x) || 822 (ceed_parent_w != ceed_parent_y)) 823 // LCOV_EXCL_START 824 return CeedError(w->ceed, CEED_ERROR_INCOMPATIBLE, 825 "Vectors w, x, and y must be created by the same Ceed context"); 826 // LCOV_EXCL_STOP 827 828 bool has_valid_array_x = true, has_valid_array_y = true; 829 ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr); 830 if (!has_valid_array_x) 831 // LCOV_EXCL_START 832 return CeedError(x->ceed, CEED_ERROR_BACKEND, 833 "CeedVector x has no valid data, " 834 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 835 // LCOV_EXCL_STOP 836 ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr); 837 if (!has_valid_array_y) 838 // LCOV_EXCL_START 839 return CeedError(y->ceed, CEED_ERROR_BACKEND, 840 "CeedVector y has no valid data, " 841 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 842 // LCOV_EXCL_STOP 843 844 // Backend implementation 845 if (w->PointwiseMult) { 846 ierr = w->PointwiseMult(w, x, y); CeedChk(ierr); 847 return CEED_ERROR_SUCCESS; 848 } 849 850 // Default implementation 851 ierr = CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array); CeedChk(ierr); 852 if (x != w) { 853 ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr); 854 } else { 855 x_array = w_array; 856 } 857 if (y != w && y != x) { 858 ierr = CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array); CeedChk(ierr); 859 } else if (y != x) { 860 y_array = w_array; 861 } else { 862 y_array = x_array; 863 } 864 865 for (CeedInt i=0; i<n_w; i++) 866 w_array[i] = x_array[i] * y_array[i]; 867 868 if (y != w && y != x) { 869 ierr = CeedVectorRestoreArrayRead(y, &y_array); CeedChk(ierr); 870 } 871 if (x != w) { 872 ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr); 873 } 874 ierr = CeedVectorRestoreArray(w, &w_array); CeedChk(ierr); 875 return CEED_ERROR_SUCCESS; 876 } 877 878 /** 879 @brief Take the reciprocal of a CeedVector. 880 881 @param vec CeedVector to take reciprocal 882 883 @return An error code: 0 - success, otherwise - failure 884 885 @ref User 886 **/ 887 int CeedVectorReciprocal(CeedVector vec) { 888 int ierr; 889 890 bool has_valid_array = true; 891 ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr); 892 if (!has_valid_array) 893 // LCOV_EXCL_START 894 return CeedError(vec->ceed, CEED_ERROR_BACKEND, 895 "CeedVector has no valid data to compute reciprocal, " 896 "must set data with CeedVectorSetValue or CeedVectorSetArray"); 897 // LCOV_EXCL_STOP 898 899 // Check if vector data set 900 if (!vec->state) 901 // LCOV_EXCL_START 902 return CeedError(vec->ceed, CEED_ERROR_INCOMPLETE, 903 "CeedVector must have data set to take reciprocal"); 904 // LCOV_EXCL_STOP 905 906 // Backend impl for GPU, if added 907 if (vec->Reciprocal) { 908 ierr = vec->Reciprocal(vec); CeedChk(ierr); 909 return CEED_ERROR_SUCCESS; 910 } 911 912 CeedInt len; 913 ierr = CeedVectorGetLength(vec, &len); CeedChk(ierr); 914 CeedScalar *array; 915 ierr = CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 916 for (CeedInt i=0; i<len; i++) 917 if (fabs(array[i]) > CEED_EPSILON) 918 array[i] = 1./array[i]; 919 920 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 921 return CEED_ERROR_SUCCESS; 922 } 923 924 /** 925 @brief View a CeedVector 926 927 @param[in] vec CeedVector to view 928 @param[in] fp_fmt Printing format 929 @param[in] stream Filestream to write to 930 931 @return An error code: 0 - success, otherwise - failure 932 933 @ref User 934 **/ 935 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) { 936 const CeedScalar *x; 937 938 int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr); 939 940 char fmt[1024]; 941 fprintf(stream, "CeedVector length %ld\n", (long)vec->length); 942 snprintf(fmt, sizeof fmt, " %s\n", fp_fmt ? fp_fmt : "%g"); 943 for (CeedInt i=0; i<vec->length; i++) 944 fprintf(stream, fmt, x[i]); 945 946 ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr); 947 return CEED_ERROR_SUCCESS; 948 } 949 950 /** 951 @brief Get the Ceed associated with a CeedVector 952 953 @param vec CeedVector to retrieve state 954 @param[out] ceed Variable to store ceed 955 956 @return An error code: 0 - success, otherwise - failure 957 958 @ref Advanced 959 **/ 960 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) { 961 *ceed = vec->ceed; 962 return CEED_ERROR_SUCCESS; 963 } 964 965 /** 966 @brief Get the length of a CeedVector 967 968 @param vec CeedVector to retrieve length 969 @param[out] length Variable to store length 970 971 @return An error code: 0 - success, otherwise - failure 972 973 @ref User 974 **/ 975 int CeedVectorGetLength(CeedVector vec, CeedInt *length) { 976 *length = vec->length; 977 return CEED_ERROR_SUCCESS; 978 } 979 980 /** 981 @brief Destroy a CeedVector 982 983 @param vec CeedVector to destroy 984 985 @return An error code: 0 - success, otherwise - failure 986 987 @ref User 988 **/ 989 int CeedVectorDestroy(CeedVector *vec) { 990 int ierr; 991 992 if (!*vec || --(*vec)->ref_count > 0) return CEED_ERROR_SUCCESS; 993 994 if (((*vec)->state % 2) == 1) 995 return CeedError((*vec)->ceed, CEED_ERROR_ACCESS, 996 "Cannot destroy CeedVector, the writable access " 997 "lock is in use"); 998 999 if ((*vec)->num_readers > 0) 1000 // LCOV_EXCL_START 1001 return CeedError((*vec)->ceed, CEED_ERROR_ACCESS, 1002 "Cannot destroy CeedVector, a process has " 1003 "read access"); 1004 // LCOV_EXCL_STOP 1005 1006 if ((*vec)->Destroy) { 1007 ierr = (*vec)->Destroy(*vec); CeedChk(ierr); 1008 } 1009 1010 ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr); 1011 ierr = CeedFree(vec); CeedChk(ierr); 1012 return CEED_ERROR_SUCCESS; 1013 } 1014 1015 /// @} 1016