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