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.h> 11 #include <ceed/backend.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 Both pointers should be destroyed with `CeedVectorDestroy()`. 190 191 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. 192 This CeedVector will be destroyed if `vec_copy` is the only reference to this CeedVector. 193 194 @param[in] vec CeedVector to copy reference to 195 @param[in,out] vec_copy Variable to store copied reference 196 197 @return An error code: 0 - success, otherwise - failure 198 199 @ref User 200 **/ 201 int CeedVectorReferenceCopy(CeedVector vec, CeedVector *vec_copy) { 202 if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) CeedCall(CeedVectorReference(vec)); 203 CeedCall(CeedVectorDestroy(vec_copy)); 204 *vec_copy = vec; 205 return CEED_ERROR_SUCCESS; 206 } 207 208 /** 209 @brief Copy a CeedVector into a different CeedVector. 210 Both pointers should be destroyed with `CeedVectorDestroy()`. 211 Note: If `*vec_copy` is non-NULL, then it is assumed that `*vec_copy` is a pointer to a CeedVector. 212 This CeedVector will be destroyed if `*vec_copy` is the only reference to this CeedVector. 213 214 @param[in] vec CeedVector to copy 215 @param[in,out] vec_copy Variable to store copied CeedVector to 216 217 @return An error code: 0 - success, otherwise - failure 218 219 @ref User 220 **/ 221 int CeedVectorCopy(CeedVector vec, CeedVector vec_copy) { 222 Ceed ceed; 223 CeedMemType mem_type, mem_type_copy; 224 CeedScalar *array; 225 226 // Get the preferred memory type 227 CeedVectorGetCeed(vec, &ceed); 228 CeedGetPreferredMemType(ceed, &mem_type); 229 230 // Get the preferred memory type 231 CeedVectorGetCeed(vec_copy, &ceed); 232 CeedGetPreferredMemType(ceed, &mem_type_copy); 233 234 // Check that both have same memory type 235 if (mem_type != mem_type_copy) mem_type = CEED_MEM_HOST; 236 237 // Copy the values from vec to vec_copy 238 CeedCall(CeedVectorGetArray(vec, mem_type, &array)); 239 CeedCall(CeedVectorSetArray(vec_copy, mem_type, CEED_COPY_VALUES, array)); 240 241 CeedCall(CeedVectorRestoreArray(vec, &array)); 242 return CEED_ERROR_SUCCESS; 243 } 244 245 /** 246 @brief Set the array used by a CeedVector, freeing any previously allocated array if applicable. 247 The backend may copy values to a different memtype, such as during @ref CeedOperatorApply(). 248 See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray(). 249 250 @param[in,out] vec CeedVector 251 @param[in] mem_type Memory type of the array being passed 252 @param[in] copy_mode Copy mode for the array 253 @param[in] array Array to be used, or NULL with @ref CEED_COPY_VALUES to have the library allocate 254 255 @return An error code: 0 - success, otherwise - failure 256 257 @ref User 258 **/ 259 int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type, CeedCopyMode copy_mode, CeedScalar *array) { 260 CeedCheck(vec->SetArray, vec->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support VectorSetArray"); 261 CeedCheck(vec->state % 2 == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 262 CeedCheck(vec->num_readers == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 263 264 CeedCall(vec->SetArray(vec, mem_type, copy_mode, array)); 265 vec->state += 2; 266 return CEED_ERROR_SUCCESS; 267 } 268 269 /** 270 @brief Set the CeedVector to a constant value 271 272 @param[in,out] vec CeedVector 273 @param[in] value Value to be used 274 275 @return An error code: 0 - success, otherwise - failure 276 277 @ref User 278 **/ 279 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 280 CeedCheck(vec->state % 2 == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 281 CeedCheck(vec->num_readers == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 282 283 if (vec->SetValue) { 284 CeedCall(vec->SetValue(vec, value)); 285 } else { 286 CeedScalar *array; 287 CeedCall(CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array)); 288 for (CeedInt i = 0; i < vec->length; i++) array[i] = value; 289 CeedCall(CeedVectorRestoreArray(vec, &array)); 290 } 291 vec->state += 2; 292 return CEED_ERROR_SUCCESS; 293 } 294 295 /** 296 @brief Sync the CeedVector to a specified memtype. 297 This function is used to force synchronization of arrays set with @ref CeedVectorSetArray(). 298 If the requested memtype is already synchronized, this function results in a no-op. 299 300 @param[in,out] vec CeedVector 301 @param[in] mem_type Memtype to be synced 302 303 @return An error code: 0 - success, otherwise - failure 304 305 @ref User 306 **/ 307 int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) { 308 CeedCheck(vec->state % 2 == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot sync CeedVector, the access lock is already in use"); 309 310 if (vec->SyncArray) { 311 CeedCall(vec->SyncArray(vec, mem_type)); 312 } else { 313 const CeedScalar *array; 314 CeedCall(CeedVectorGetArrayRead(vec, mem_type, &array)); 315 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 316 } 317 return CEED_ERROR_SUCCESS; 318 } 319 320 /** 321 @brief Take ownership of the CeedVector array set by @ref CeedVectorSetArray() with @ref CEED_USE_POINTER and remove the array from the CeedVector. 322 The caller is responsible for managing and freeing the array. 323 This function will error if @ref CeedVectorSetArray() was not previously called with @ref CEED_USE_POINTER for the corresponding mem_type. 324 325 @param[in,out] vec CeedVector 326 @param[in] mem_type Memory type on which to take the array. 327 If the backend uses a different memory type, this will perform a copy. 328 @param[out] array Array on memory type mem_type, or NULL if array pointer is not required 329 330 @return An error code: 0 - success, otherwise - failure 331 332 @ref User 333 **/ 334 int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 335 CeedCheck(vec->state % 2 == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot take CeedVector array, the access lock is already in use"); 336 CeedCheck(vec->num_readers == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot take CeedVector array, a process has read access"); 337 338 CeedScalar *temp_array = NULL; 339 if (vec->length > 0) { 340 bool has_borrowed_array_of_type = true; 341 CeedCall(CeedVectorHasBorrowedArrayOfType(vec, mem_type, &has_borrowed_array_of_type)); 342 CeedCheck(has_borrowed_array_of_type, vec->ceed, CEED_ERROR_BACKEND, 343 "CeedVector has no borrowed %s array, must set array with CeedVectorSetArray", CeedMemTypes[mem_type]); 344 345 bool has_valid_array = true; 346 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 347 CeedCheck(has_valid_array, vec->ceed, CEED_ERROR_BACKEND, 348 "CeedVector has no valid data to take, must set data with CeedVectorSetValue or CeedVectorSetArray"); 349 350 CeedCall(vec->TakeArray(vec, mem_type, &temp_array)); 351 } 352 if (array) (*array) = temp_array; 353 return CEED_ERROR_SUCCESS; 354 } 355 356 /** 357 @brief Get read/write access to a CeedVector via the specified memory type. 358 Restore access with @ref CeedVectorRestoreArray(). 359 360 @param[in,out] vec CeedVector to access 361 @param[in] mem_type Memory type on which to access the array. 362 If the backend uses a different memory type, this will perform a copy. 363 @param[out] array Array on memory type mem_type 364 365 @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide access to array pointers in the desired memory space. 366 Pairing get/restore allows the Vector to track access, thus knowing if norms or other operations may need to be recomputed. 367 368 @return An error code: 0 - success, otherwise - failure 369 370 @ref User 371 **/ 372 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 373 CeedCheck(vec->GetArray, vec->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetArray"); 374 CeedCheck(vec->state % 2 == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 375 CeedCheck(vec->num_readers == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 376 377 bool has_valid_array = true; 378 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 379 CeedCheck(has_valid_array, vec->ceed, CEED_ERROR_BACKEND, 380 "CeedVector has no valid data to read, must set data with CeedVectorSetValue or CeedVectorSetArray"); 381 382 CeedCall(vec->GetArray(vec, mem_type, array)); 383 vec->state++; 384 return CEED_ERROR_SUCCESS; 385 } 386 387 /** 388 @brief Get read-only access to a CeedVector via the specified memory type. 389 Restore access with @ref CeedVectorRestoreArrayRead(). 390 391 @param[in] vec CeedVector to access 392 @param[in] mem_type Memory type on which to access the array. 393 If the backend uses a different memory type, this will perform a copy (possibly cached). 394 @param[out] array Array on memory type mem_type 395 396 @return An error code: 0 - success, otherwise - failure 397 398 @ref User 399 **/ 400 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type, const CeedScalar **array) { 401 CeedCheck(vec->GetArrayRead, vec->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetArrayRead"); 402 CeedCheck(vec->state % 2 == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector read-only array access, the access lock is already in use"); 403 404 if (vec->length > 0) { 405 bool has_valid_array = true; 406 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 407 CeedCheck(has_valid_array, vec->ceed, CEED_ERROR_BACKEND, 408 "CeedVector has no valid data to read, must set data with CeedVectorSetValue or CeedVectorSetArray"); 409 410 CeedCall(vec->GetArrayRead(vec, mem_type, array)); 411 } else { 412 *array = NULL; 413 } 414 vec->num_readers++; 415 return CEED_ERROR_SUCCESS; 416 } 417 418 /** 419 @brief Get write access to a CeedVector via the specified memory type. 420 Restore access with @ref CeedVectorRestoreArray(). 421 All old values should be assumed to be invalid. 422 423 @param[in,out] vec CeedVector to access 424 @param[in] mem_type Memory type on which to access the array. 425 @param[out] array Array on memory type mem_type 426 427 @return An error code: 0 - success, otherwise - failure 428 429 @ref User 430 **/ 431 int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 432 CeedCheck(vec->GetArrayWrite, vec->ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support GetArrayWrite"); 433 CeedCheck(vec->state % 2 == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, the access lock is already in use"); 434 CeedCheck(vec->num_readers == 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot grant CeedVector array access, a process has read access"); 435 436 CeedCall(vec->GetArrayWrite(vec, mem_type, array)); 437 vec->state++; 438 return CEED_ERROR_SUCCESS; 439 } 440 441 /** 442 @brief Restore an array obtained using @ref CeedVectorGetArray() or @ref CeedVectorGetArrayWrite() 443 444 @param[in,out] vec CeedVector to restore 445 @param[in,out] array Array of vector data 446 447 @return An error code: 0 - success, otherwise - failure 448 449 @ref User 450 **/ 451 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 452 CeedCheck(vec->state % 2 == 1, vec->ceed, CEED_ERROR_ACCESS, "Cannot restore CeedVector array access, access was not granted"); 453 if (vec->RestoreArray) CeedCall(vec->RestoreArray(vec)); 454 *array = NULL; 455 vec->state++; 456 return CEED_ERROR_SUCCESS; 457 } 458 459 /** 460 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 461 462 @param[in] vec CeedVector to restore 463 @param[in,out] array Array of vector data 464 465 @return An error code: 0 - success, otherwise - failure 466 467 @ref User 468 **/ 469 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 470 CeedCheck(vec->num_readers > 0, vec->ceed, CEED_ERROR_ACCESS, "Cannot restore CeedVector array read access, access was not granted"); 471 472 vec->num_readers--; 473 if (vec->num_readers == 0 && vec->RestoreArrayRead) CeedCall(vec->RestoreArrayRead(vec)); 474 *array = NULL; 475 476 return CEED_ERROR_SUCCESS; 477 } 478 479 /** 480 @brief Get the norm of a CeedVector. 481 482 Note: This operation is local to the CeedVector. 483 This function will likely not provide the desired results for the norm of the libCEED portion of a parallel vector or a CeedVector with 484 duplicated or hanging nodes. 485 486 @param[in] vec CeedVector to retrieve maximum value 487 @param[in] norm_type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 488 @param[out] norm Variable to store norm value 489 490 @return An error code: 0 - success, otherwise - failure 491 492 @ref User 493 **/ 494 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) { 495 bool has_valid_array = true; 496 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 497 CeedCheck(has_valid_array, vec->ceed, CEED_ERROR_BACKEND, 498 "CeedVector has no valid data to compute norm, must set data with CeedVectorSetValue or CeedVectorSetArray"); 499 500 // Backend impl for GPU, if added 501 if (vec->Norm) { 502 CeedCall(vec->Norm(vec, norm_type, norm)); 503 return CEED_ERROR_SUCCESS; 504 } 505 506 const CeedScalar *array; 507 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array)); 508 509 *norm = 0.; 510 switch (norm_type) { 511 case CEED_NORM_1: 512 for (CeedInt i = 0; i < vec->length; i++) { 513 *norm += fabs(array[i]); 514 } 515 break; 516 case CEED_NORM_2: 517 for (CeedInt i = 0; i < vec->length; i++) { 518 *norm += fabs(array[i]) * fabs(array[i]); 519 } 520 break; 521 case CEED_NORM_MAX: 522 for (CeedInt i = 0; i < vec->length; i++) { 523 const CeedScalar abs_v_i = fabs(array[i]); 524 *norm = *norm > abs_v_i ? *norm : abs_v_i; 525 } 526 } 527 if (norm_type == CEED_NORM_2) *norm = sqrt(*norm); 528 529 CeedCall(CeedVectorRestoreArrayRead(vec, &array)); 530 return CEED_ERROR_SUCCESS; 531 } 532 533 /** 534 @brief Compute x = alpha x 535 536 @param[in,out] x vector for scaling 537 @param[in] alpha scaling factor 538 539 @return An error code: 0 - success, otherwise - failure 540 541 @ref User 542 **/ 543 int CeedVectorScale(CeedVector x, CeedScalar alpha) { 544 CeedScalar *x_array = NULL; 545 CeedSize n_x; 546 547 bool has_valid_array = true; 548 CeedCall(CeedVectorHasValidArray(x, &has_valid_array)); 549 CeedCheck(has_valid_array, x->ceed, CEED_ERROR_BACKEND, 550 "CeedVector has no valid data to scale, must set data with CeedVectorSetValue or CeedVectorSetArray"); 551 552 CeedCall(CeedVectorGetLength(x, &n_x)); 553 554 // Backend implementation 555 if (x->Scale) return x->Scale(x, alpha); 556 557 // Default implementation 558 CeedCall(CeedVectorGetArrayWrite(x, CEED_MEM_HOST, &x_array)); 559 for (CeedInt i = 0; i < n_x; i++) x_array[i] *= alpha; 560 CeedCall(CeedVectorRestoreArray(x, &x_array)); 561 562 return CEED_ERROR_SUCCESS; 563 } 564 565 /** 566 @brief Compute y = alpha x + y 567 568 @param[in,out] y target vector for sum 569 @param[in] alpha scaling factor 570 @param[in] x second vector, must be different than y 571 572 @return An error code: 0 - success, otherwise - failure 573 574 @ref User 575 **/ 576 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) { 577 CeedScalar *y_array = NULL; 578 CeedScalar const *x_array = NULL; 579 CeedSize n_x, n_y; 580 581 CeedCall(CeedVectorGetLength(y, &n_y)); 582 CeedCall(CeedVectorGetLength(x, &n_x)); 583 CeedCheck(n_x == n_y, y->ceed, CEED_ERROR_UNSUPPORTED, "Cannot add vector of different lengths"); 584 CeedCheck(x != y, y->ceed, CEED_ERROR_UNSUPPORTED, "Cannot use same vector for x and y in CeedVectorAXPY"); 585 586 bool has_valid_array_x = true, has_valid_array_y = true; 587 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 588 CeedCheck(has_valid_array_x, x->ceed, CEED_ERROR_BACKEND, 589 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 590 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 591 CeedCheck(has_valid_array_y, y->ceed, CEED_ERROR_BACKEND, 592 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 593 594 Ceed ceed_parent_x, ceed_parent_y; 595 CeedCall(CeedGetParent(x->ceed, &ceed_parent_x)); 596 CeedCall(CeedGetParent(y->ceed, &ceed_parent_y)); 597 CeedCheck(ceed_parent_x == ceed_parent_y, y->ceed, CEED_ERROR_INCOMPATIBLE, "Vectors x and y must be created by the same Ceed context"); 598 599 // Backend implementation 600 if (y->AXPY) { 601 CeedCall(y->AXPY(y, alpha, x)); 602 return CEED_ERROR_SUCCESS; 603 } 604 605 // Default implementation 606 CeedCall(CeedVectorGetArrayWrite(y, CEED_MEM_HOST, &y_array)); 607 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 608 609 assert(x_array); 610 assert(y_array); 611 612 for (CeedInt i = 0; i < n_y; i++) y_array[i] += alpha * x_array[i]; 613 614 CeedCall(CeedVectorRestoreArray(y, &y_array)); 615 CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 616 617 return CEED_ERROR_SUCCESS; 618 } 619 620 /** 621 @brief Compute y = alpha x + beta y 622 623 @param[in,out] y target vector for sum 624 @param[in] alpha first scaling factor 625 @param[in] beta second scaling factor 626 @param[in] x second vector, must be different than y 627 628 @return An error code: 0 - success, otherwise - failure 629 630 @ref User 631 **/ 632 int CeedVectorAXPBY(CeedVector y, CeedScalar alpha, CeedScalar beta, CeedVector x) { 633 CeedScalar *y_array = NULL; 634 CeedScalar const *x_array = NULL; 635 CeedSize n_x, n_y; 636 637 CeedCall(CeedVectorGetLength(y, &n_y)); 638 CeedCall(CeedVectorGetLength(x, &n_x)); 639 CeedCheck(n_x == n_y, y->ceed, CEED_ERROR_UNSUPPORTED, "Cannot add vector of different lengths"); 640 CeedCheck(x != y, y->ceed, CEED_ERROR_UNSUPPORTED, "Cannot use same vector for x and y in CeedVectorAXPBY"); 641 642 bool has_valid_array_x = true, has_valid_array_y = true; 643 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 644 CeedCheck(has_valid_array_x, x->ceed, CEED_ERROR_BACKEND, 645 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 646 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 647 CeedCheck(has_valid_array_y, y->ceed, CEED_ERROR_BACKEND, 648 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 649 650 Ceed ceed_parent_x, ceed_parent_y; 651 CeedCall(CeedGetParent(x->ceed, &ceed_parent_x)); 652 CeedCall(CeedGetParent(y->ceed, &ceed_parent_y)); 653 CeedCheck(ceed_parent_x == ceed_parent_y, y->ceed, CEED_ERROR_INCOMPATIBLE, "Vectors x and y must be created by the same Ceed context"); 654 655 // Backend implementation 656 if (y->AXPBY) { 657 CeedCall(y->AXPBY(y, alpha, beta, x)); 658 return CEED_ERROR_SUCCESS; 659 } 660 661 // Default implementation 662 CeedCall(CeedVectorGetArray(y, CEED_MEM_HOST, &y_array)); 663 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 664 665 assert(x_array); 666 assert(y_array); 667 668 for (CeedInt i = 0; i < n_y; i++) y_array[i] += alpha * x_array[i] + beta * y_array[i]; 669 670 CeedCall(CeedVectorRestoreArray(y, &y_array)); 671 CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 672 673 return CEED_ERROR_SUCCESS; 674 } 675 676 /** 677 @brief Compute the pointwise multiplication w = x .* y. 678 Any subset of x, y, and w may be the same vector. 679 680 @param[out] w target vector for the product 681 @param[in] x first vector for product 682 @param[in] y second vector for the product 683 684 @return An error code: 0 - success, otherwise - failure 685 686 @ref User 687 **/ 688 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) { 689 CeedScalar *w_array = NULL; 690 CeedScalar const *x_array = NULL, *y_array = NULL; 691 CeedSize n_w, n_x, n_y; 692 693 CeedCall(CeedVectorGetLength(w, &n_w)); 694 CeedCall(CeedVectorGetLength(x, &n_x)); 695 CeedCall(CeedVectorGetLength(y, &n_y)); 696 CeedCheck(n_w == n_x && n_w == n_y, w->ceed, CEED_ERROR_UNSUPPORTED, "Cannot multiply vectors of different lengths"); 697 698 Ceed ceed_parent_w, ceed_parent_x, ceed_parent_y; 699 CeedCall(CeedGetParent(w->ceed, &ceed_parent_w)); 700 CeedCall(CeedGetParent(x->ceed, &ceed_parent_x)); 701 CeedCall(CeedGetParent(y->ceed, &ceed_parent_y)); 702 CeedCheck(ceed_parent_w == ceed_parent_x && ceed_parent_w == ceed_parent_y, w->ceed, CEED_ERROR_INCOMPATIBLE, 703 "Vectors w, x, and y must be created by the same Ceed context"); 704 705 bool has_valid_array_x = true, has_valid_array_y = true; 706 CeedCall(CeedVectorHasValidArray(x, &has_valid_array_x)); 707 CeedCheck(has_valid_array_x, x->ceed, CEED_ERROR_BACKEND, 708 "CeedVector x has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 709 CeedCall(CeedVectorHasValidArray(y, &has_valid_array_y)); 710 CeedCheck(has_valid_array_y, y->ceed, CEED_ERROR_BACKEND, 711 "CeedVector y has no valid data, must set data with CeedVectorSetValue or CeedVectorSetArray"); 712 713 // Backend implementation 714 if (w->PointwiseMult) { 715 CeedCall(w->PointwiseMult(w, x, y)); 716 return CEED_ERROR_SUCCESS; 717 } 718 719 // Default implementation 720 if (x != w) { 721 CeedCall(CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array)); 722 } else { 723 CeedCall(CeedVectorGetArray(w, CEED_MEM_HOST, &w_array)); 724 x_array = w_array; 725 } 726 if (y != w && y != x) { 727 CeedCall(CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array)); 728 } else if (y == x) { 729 y_array = x_array; 730 } else { 731 CeedCall(CeedVectorGetArray(w, CEED_MEM_HOST, &w_array)); 732 y_array = w_array; 733 } 734 if (!w_array) CeedCall(CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array)); 735 736 assert(w_array); 737 assert(x_array); 738 assert(y_array); 739 740 for (CeedInt i = 0; i < n_w; i++) w_array[i] = x_array[i] * y_array[i]; 741 742 if (y != w && y != x) CeedCall(CeedVectorRestoreArrayRead(y, &y_array)); 743 if (x != w) CeedCall(CeedVectorRestoreArrayRead(x, &x_array)); 744 CeedCall(CeedVectorRestoreArray(w, &w_array)); 745 return CEED_ERROR_SUCCESS; 746 } 747 748 /** 749 @brief Take the reciprocal of a CeedVector. 750 751 @param[in,out] vec CeedVector to take reciprocal 752 753 @return An error code: 0 - success, otherwise - failure 754 755 @ref User 756 **/ 757 int CeedVectorReciprocal(CeedVector vec) { 758 bool has_valid_array = true; 759 CeedCall(CeedVectorHasValidArray(vec, &has_valid_array)); 760 761 CeedCheck(has_valid_array, vec->ceed, CEED_ERROR_BACKEND, 762 "CeedVector has no valid data to compute reciprocal, must set data with CeedVectorSetValue or CeedVectorSetArray"); 763 764 // Check if vector data set 765 CeedCheck(vec->state > 0, vec->ceed, CEED_ERROR_INCOMPLETE, "CeedVector must have data set to take reciprocal"); 766 767 // Backend impl for GPU, if added 768 if (vec->Reciprocal) { 769 CeedCall(vec->Reciprocal(vec)); 770 return CEED_ERROR_SUCCESS; 771 } 772 773 CeedSize len; 774 CeedCall(CeedVectorGetLength(vec, &len)); 775 CeedScalar *array; 776 CeedCall(CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array)); 777 for (CeedInt i = 0; i < len; i++) { 778 if (fabs(array[i]) > CEED_EPSILON) array[i] = 1. / array[i]; 779 } 780 781 CeedCall(CeedVectorRestoreArray(vec, &array)); 782 return CEED_ERROR_SUCCESS; 783 } 784 785 /** 786 @brief View a CeedVector 787 788 Note: It is safe to use any unsigned values for `start` or `stop` and any nonzero integer for `step`. 789 Any portion of the provided range that is outside the range of valid indices for the CeedVector will be ignored. 790 791 @param[in] vec CeedVector to view 792 @param[in] start Index of first CeedVector entry to view 793 @param[in] stop Index of last CeedVector entry to view 794 @param[in] step Step between CeedVector entries to view 795 @param[in] fp_fmt Printing format 796 @param[in] stream Filestream to write to 797 798 @return An error code: 0 - success, otherwise - failure 799 800 @ref User 801 **/ 802 int CeedVectorViewRange(CeedVector vec, CeedSize start, CeedSize stop, CeedInt step, const char *fp_fmt, FILE *stream) { 803 const CeedScalar *x; 804 char fmt[1024]; 805 806 CeedCheck(step != 0, vec->ceed, CEED_ERROR_MINOR, "View range 'step' must be nonzero"); 807 808 fprintf(stream, "CeedVector length %ld\n", (long)vec->length); 809 if (start != 0 || stop != vec->length || step != 1) { 810 fprintf(stream, " start: %ld\n stop: %ld\n step: %" CeedInt_FMT "\n", (long)start, (long)stop, step); 811 } 812 if (start > vec->length) start = vec->length; 813 if (stop > vec->length) stop = vec->length; 814 815 snprintf(fmt, sizeof fmt, " %s\n", fp_fmt ? fp_fmt : "%g"); 816 CeedCall(CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x)); 817 for (CeedInt i = start; step > 0 ? (i < stop) : (i > stop); i += step) fprintf(stream, fmt, x[i]); 818 CeedCall(CeedVectorRestoreArrayRead(vec, &x)); 819 if (stop != vec->length) fprintf(stream, " ...\n"); 820 821 return CEED_ERROR_SUCCESS; 822 } 823 824 /** 825 @brief View a CeedVector 826 827 @param[in] vec CeedVector to view 828 @param[in] fp_fmt Printing format 829 @param[in] stream Filestream to write to 830 831 @return An error code: 0 - success, otherwise - failure 832 833 @ref User 834 **/ 835 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) { 836 CeedCall(CeedVectorViewRange(vec, 0, vec->length, 1, fp_fmt, stream)); 837 return CEED_ERROR_SUCCESS; 838 } 839 840 /** 841 @brief Get the Ceed associated with a CeedVector 842 843 @param[in] vec CeedVector to retrieve state 844 @param[out] ceed Variable to store ceed 845 846 @return An error code: 0 - success, otherwise - failure 847 848 @ref Advanced 849 **/ 850 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) { 851 *ceed = vec->ceed; 852 return CEED_ERROR_SUCCESS; 853 } 854 855 /** 856 @brief Get the length of a CeedVector 857 858 @param[in] vec CeedVector to retrieve length 859 @param[out] length Variable to store length 860 861 @return An error code: 0 - success, otherwise - failure 862 863 @ref User 864 **/ 865 int CeedVectorGetLength(CeedVector vec, CeedSize *length) { 866 *length = vec->length; 867 return CEED_ERROR_SUCCESS; 868 } 869 870 /** 871 @brief Destroy a CeedVector 872 873 @param[in,out] vec CeedVector to destroy 874 875 @return An error code: 0 - success, otherwise - failure 876 877 @ref User 878 **/ 879 int CeedVectorDestroy(CeedVector *vec) { 880 if (!*vec || *vec == CEED_VECTOR_ACTIVE || *vec == CEED_VECTOR_NONE || --(*vec)->ref_count > 0) { 881 *vec = NULL; 882 return CEED_ERROR_SUCCESS; 883 } 884 CeedCheck((*vec)->state % 2 == 0, (*vec)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedVector, the writable access lock is in use"); 885 CeedCheck((*vec)->num_readers == 0, (*vec)->ceed, CEED_ERROR_ACCESS, "Cannot destroy CeedVector, a process has read access"); 886 887 if ((*vec)->Destroy) CeedCall((*vec)->Destroy(*vec)); 888 889 CeedCall(CeedDestroy(&(*vec)->ceed)); 890 CeedCall(CeedFree(vec)); 891 return CEED_ERROR_SUCCESS; 892 } 893 894 /// @} 895