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