1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at 2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights 3 // reserved. See files LICENSE and NOTICE for details. 4 // 5 // This file is part of CEED, a collection of benchmarks, miniapps, software 6 // libraries and APIs for efficient high-order finite element and spectral 7 // element discretizations for exascale applications. For more information and 8 // source code availability see http://github.com/ceed. 9 // 10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC, 11 // a collaborative effort of two U.S. Department of Energy organizations (Office 12 // of Science and the National Nuclear Security Administration) responsible for 13 // the planning and preparation of a capable exascale ecosystem, including 14 // software, applications, hardware, advanced system engineering and early 15 // testbed platforms, in support of the nation's exascale computing imperative. 16 17 #include <ceed/ceed.h> 18 #include <ceed/backend.h> 19 #include <ceed-impl.h> 20 #include <math.h> 21 #include <stdint.h> 22 #include <stdio.h> 23 24 /// @file 25 /// Implementation of public CeedVector interfaces 26 27 /// @cond DOXYGEN_SKIP 28 static struct CeedVector_private ceed_vector_active; 29 static struct CeedVector_private ceed_vector_none; 30 /// @endcond 31 32 /// @addtogroup CeedVectorUser 33 /// @{ 34 35 /// Indicate that vector will be provided as an explicit argument to 36 /// CeedOperatorApply(). 37 const CeedVector CEED_VECTOR_ACTIVE = &ceed_vector_active; 38 39 /// Indicate that no vector is applicable (i.e., for @ref CEED_EVAL_WEIGHTS). 40 const CeedVector CEED_VECTOR_NONE = &ceed_vector_none; 41 42 /// @} 43 44 /// ---------------------------------------------------------------------------- 45 /// CeedVector Backend API 46 /// ---------------------------------------------------------------------------- 47 /// @addtogroup CeedVectorBackend 48 /// @{ 49 50 /** 51 @brief Get the Ceed associated with a CeedVector 52 53 @param vec CeedVector to retrieve state 54 @param[out] ceed Variable to store ceed 55 56 @return An error code: 0 - success, otherwise - failure 57 58 @ref Backend 59 **/ 60 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) { 61 *ceed = vec->ceed; 62 return CEED_ERROR_SUCCESS; 63 } 64 65 /** 66 @brief Get the state of a CeedVector 67 68 @param vec CeedVector to retrieve state 69 @param[out] state Variable to store state 70 71 @return An error code: 0 - success, otherwise - failure 72 73 @ref Backend 74 **/ 75 int CeedVectorGetState(CeedVector vec, uint64_t *state) { 76 *state = vec->state; 77 return CEED_ERROR_SUCCESS; 78 } 79 80 /** 81 @brief Add a reference to a CeedVector 82 83 @param[out] vec CeedVector to increment reference counter 84 85 @return An error code: 0 - success, otherwise - failure 86 87 @ref Backend 88 **/ 89 int CeedVectorAddReference(CeedVector vec) { 90 vec->ref_count++; 91 return CEED_ERROR_SUCCESS; 92 } 93 94 /** 95 @brief Get the backend data of a CeedVector 96 97 @param vec CeedVector to retrieve state 98 @param[out] data Variable to store data 99 100 @return An error code: 0 - success, otherwise - failure 101 102 @ref Backend 103 **/ 104 int CeedVectorGetData(CeedVector vec, void *data) { 105 *(void **)data = vec->data; 106 return CEED_ERROR_SUCCESS; 107 } 108 109 /** 110 @brief Set the backend data of a CeedVector 111 112 @param[out] vec CeedVector to retrieve state 113 @param data Data to set 114 115 @return An error code: 0 - success, otherwise - failure 116 117 @ref Backend 118 **/ 119 int CeedVectorSetData(CeedVector vec, void *data) { 120 vec->data = data; 121 return CEED_ERROR_SUCCESS; 122 } 123 124 /** 125 @brief Increment the reference counter for a CeedVector 126 127 @param vec CeedVector to increment the reference counter 128 129 @return An error code: 0 - success, otherwise - failure 130 131 @ref Backend 132 **/ 133 int CeedVectorReference(CeedVector vec) { 134 vec->ref_count++; 135 return CEED_ERROR_SUCCESS; 136 } 137 138 /// @} 139 140 /// ---------------------------------------------------------------------------- 141 /// CeedVector Public API 142 /// ---------------------------------------------------------------------------- 143 /// @addtogroup CeedVectorUser 144 /// @{ 145 146 /** 147 @brief Create a CeedVector of the specified length (does not allocate memory) 148 149 @param ceed Ceed object where the CeedVector will be created 150 @param length Length of vector 151 @param[out] vec Address of the variable where the newly created 152 CeedVector will be stored 153 154 @return An error code: 0 - success, otherwise - failure 155 156 @ref User 157 **/ 158 int CeedVectorCreate(Ceed ceed, CeedInt length, CeedVector *vec) { 159 int ierr; 160 161 if (!ceed->VectorCreate) { 162 Ceed delegate; 163 ierr = CeedGetObjectDelegate(ceed, &delegate, "Vector"); CeedChk(ierr); 164 165 if (!delegate) 166 // LCOV_EXCL_START 167 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 168 "Backend does not support VectorCreate"); 169 // LCOV_EXCL_STOP 170 171 ierr = CeedVectorCreate(delegate, length, vec); CeedChk(ierr); 172 return CEED_ERROR_SUCCESS; 173 } 174 175 ierr = CeedCalloc(1, vec); CeedChk(ierr); 176 (*vec)->ceed = ceed; 177 ierr = CeedReference(ceed); CeedChk(ierr); 178 (*vec)->ref_count = 1; 179 (*vec)->length = length; 180 (*vec)->state = 0; 181 ierr = ceed->VectorCreate(length, *vec); CeedChk(ierr); 182 return CEED_ERROR_SUCCESS; 183 } 184 185 /** 186 @brief Copy the pointer to a CeedVector. Both pointers should 187 be destroyed with `CeedVectorDestroy()`; 188 Note: If `*vec_copy` is non-NULL, then it is assumed that 189 `*vec_copy` is a pointer to a CeedVector. This 190 CeedVector will be destroyed if `*vec_copy` is the only 191 reference to this CeedVector. 192 193 @param vec CeedVector to copy reference to 194 @param[out] vec_copy Variable to store copied reference 195 196 @return An error code: 0 - success, otherwise - failure 197 198 @ref User 199 **/ 200 int CeedVectorReferenceCopy(CeedVector vec, CeedVector *vec_copy) { 201 int ierr; 202 203 ierr = CeedVectorReference(vec); CeedChk(ierr); 204 ierr = CeedVectorDestroy(vec_copy); CeedChk(ierr); 205 *vec_copy = vec; 206 return CEED_ERROR_SUCCESS; 207 } 208 209 /** 210 @brief Set the array used by a CeedVector, freeing any previously allocated 211 array if applicable. The backend may copy values to a different 212 memtype, such as during @ref CeedOperatorApply(). 213 See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray(). 214 215 @param vec CeedVector 216 @param mem_type Memory type of the array being passed 217 @param copy_mode Copy mode for the array 218 @param array Array to be used, or NULL with @ref CEED_COPY_VALUES to have the 219 library allocate 220 221 @return An error code: 0 - success, otherwise - failure 222 223 @ref User 224 **/ 225 int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type, 226 CeedCopyMode copy_mode, 227 CeedScalar *array) { 228 int ierr; 229 230 if (!vec->SetArray) 231 // LCOV_EXCL_START 232 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 233 "Backend does not support VectorSetArray"); 234 // LCOV_EXCL_STOP 235 236 if (vec->state % 2 == 1) 237 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 238 "Cannot grant CeedVector array access, the " 239 "access lock is already in use"); 240 241 if (vec->num_readers > 0) 242 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 243 "Cannot grant CeedVector array access, a " 244 "process has read access"); 245 246 ierr = vec->SetArray(vec, mem_type, copy_mode, array); CeedChk(ierr); 247 vec->state += 2; 248 return CEED_ERROR_SUCCESS; 249 } 250 251 /** 252 @brief Set the CeedVector to a constant value 253 254 @param vec CeedVector 255 @param[in] value Value to be used 256 257 @return An error code: 0 - success, otherwise - failure 258 259 @ref User 260 **/ 261 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 262 int ierr; 263 264 if (vec->state % 2 == 1) 265 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 266 "Cannot grant CeedVector array access, the " 267 "access lock is already in use"); 268 269 if (vec->SetValue) { 270 ierr = vec->SetValue(vec, value); CeedChk(ierr); 271 } else { 272 CeedScalar *array; 273 ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 274 for (int i=0; i<vec->length; i++) array[i] = value; 275 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 276 } 277 vec->state += 2; 278 return CEED_ERROR_SUCCESS; 279 } 280 281 /** 282 @brief Sync the CeedVector to a specified memtype. This function is used to 283 force synchronization of arrays set with @ref CeedVectorSetArray(). 284 If the requested memtype is already synchronized, this function 285 results in a no-op. 286 287 @param vec CeedVector 288 @param mem_type Memtype to be synced 289 290 @return An error code: 0 - success, otherwise - failure 291 292 @ref User 293 **/ 294 int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) { 295 int ierr; 296 297 if (vec->state % 2 == 1) 298 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 299 "Cannot sync CeedVector, the access lock is " 300 "already in use"); 301 302 if (vec->SyncArray) { 303 ierr = vec->SyncArray(vec, mem_type); CeedChk(ierr); 304 } else { 305 const CeedScalar *array; 306 ierr = CeedVectorGetArrayRead(vec, mem_type, &array); CeedChk(ierr); 307 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 308 } 309 return CEED_ERROR_SUCCESS; 310 } 311 312 /** 313 @brief Take ownership of the CeedVector array and remove the array from the 314 CeedVector. The caller is responsible for managing and freeing 315 the array. 316 317 @param vec CeedVector 318 @param mem_type Memory type on which to take the array. If the backend 319 uses a different memory type, this will perform a copy. 320 @param[out] array Array on memory type mem_type, or NULL if array pointer is 321 not required 322 323 @return An error code: 0 - success, otherwise - failure 324 325 @ref User 326 **/ 327 int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type, 328 CeedScalar **array) { 329 int ierr; 330 331 if (vec->state % 2 == 1) 332 // LCOV_EXCL_START 333 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 334 "Cannot take CeedVector array, the access " 335 "lock is already in use"); 336 // LCOV_EXCL_STOP 337 if (vec->num_readers > 0) 338 // LCOV_EXCL_START 339 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 340 "Cannot take CeedVector array, a process " 341 "has read access"); 342 // LCOV_EXCL_STOP 343 344 CeedScalar *temp_array = NULL; 345 ierr = vec->TakeArray(vec, mem_type, &temp_array); CeedChk(ierr); 346 if (array) (*array) = temp_array; 347 return CEED_ERROR_SUCCESS; 348 } 349 350 /** 351 @brief Get read/write access to a CeedVector via the specified memory type. 352 Restore access with @ref CeedVectorRestoreArray(). 353 354 @param vec CeedVector to access 355 @param mem_type Memory type on which to access the array. If the backend 356 uses a different memory type, this will perform a copy. 357 @param[out] array Array on memory type mem_type 358 359 @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide 360 access to array pointers in the desired memory space. Pairing get/restore 361 allows the Vector to track access, thus knowing if norms or other 362 operations may need to be recomputed. 363 364 @return An error code: 0 - success, otherwise - failure 365 366 @ref User 367 **/ 368 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type, 369 CeedScalar **array) { 370 int ierr; 371 372 if (!vec->GetArray) 373 // LCOV_EXCL_START 374 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 375 "Backend does not support GetArray"); 376 // LCOV_EXCL_STOP 377 378 if (vec->state % 2 == 1) 379 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 380 "Cannot grant CeedVector array access, the " 381 "access lock is already in use"); 382 383 if (vec->num_readers > 0) 384 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 385 "Cannot grant CeedVector array access, a " 386 "process has read access"); 387 388 ierr = vec->GetArray(vec, mem_type, array); CeedChk(ierr); 389 vec->state += 1; 390 return CEED_ERROR_SUCCESS; 391 } 392 393 /** 394 @brief Get read-only access to a CeedVector via the specified memory type. 395 Restore access with @ref CeedVectorRestoreArrayRead(). 396 397 @param vec CeedVector to access 398 @param mem_type Memory type on which to access the array. If the backend 399 uses a different memory type, this will perform a copy 400 (possibly cached). 401 @param[out] array Array on memory type mem_type 402 403 @return An error code: 0 - success, otherwise - failure 404 405 @ref User 406 **/ 407 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type, 408 const CeedScalar **array) { 409 int ierr; 410 411 if (!vec->GetArrayRead) 412 // LCOV_EXCL_START 413 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 414 "Backend does not support GetArrayRead"); 415 // LCOV_EXCL_STOP 416 417 if (vec->state % 2 == 1) 418 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 419 "Cannot grant CeedVector read-only array " 420 "access, the access lock is already in use"); 421 422 ierr = vec->GetArrayRead(vec, mem_type, array); CeedChk(ierr); 423 vec->num_readers++; 424 return CEED_ERROR_SUCCESS; 425 } 426 427 /** 428 @brief Restore an array obtained using @ref CeedVectorGetArray() 429 430 @param vec CeedVector to restore 431 @param array Array of vector data 432 433 @return An error code: 0 - success, otherwise - failure 434 435 @ref User 436 **/ 437 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 438 int ierr; 439 440 if (!vec->RestoreArray) 441 // LCOV_EXCL_START 442 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 443 "Backend does not support RestoreArray"); 444 // LCOV_EXCL_STOP 445 446 if (vec->state % 2 != 1) 447 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 448 "Cannot restore CeedVector array access, " 449 "access was not granted"); 450 451 ierr = vec->RestoreArray(vec); CeedChk(ierr); 452 *array = NULL; 453 vec->state += 1; 454 return CEED_ERROR_SUCCESS; 455 } 456 457 /** 458 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 459 460 @param vec CeedVector to restore 461 @param array Array of vector data 462 463 @return An error code: 0 - success, otherwise - failure 464 465 @ref User 466 **/ 467 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 468 int ierr; 469 470 if (!vec->RestoreArrayRead) 471 // LCOV_EXCL_START 472 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 473 "Backend does not support RestoreArrayRead"); 474 // LCOV_EXCL_STOP 475 476 ierr = vec->RestoreArrayRead(vec); CeedChk(ierr); 477 *array = NULL; 478 vec->num_readers--; 479 return CEED_ERROR_SUCCESS; 480 } 481 482 /** 483 @brief Get the norm of a CeedVector. 484 485 Note: This operation is local to the CeedVector. This function will likely 486 not provide the desired results for the norm of the libCEED portion 487 of a parallel vector or a CeedVector with duplicated or hanging nodes. 488 489 @param vec CeedVector to retrieve maximum value 490 @param norm_type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 491 @param[out] norm Variable to store norm value 492 493 @return An error code: 0 - success, otherwise - failure 494 495 @ref User 496 **/ 497 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) { 498 int ierr; 499 500 // Backend impl for GPU, if added 501 if (vec->Norm) { 502 ierr = vec->Norm(vec, norm_type, norm); CeedChk(ierr); 503 return CEED_ERROR_SUCCESS; 504 } 505 506 const CeedScalar *array; 507 ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 508 509 *norm = 0.; 510 switch (norm_type) { 511 case CEED_NORM_1: 512 for (int i=0; i<vec->length; i++) { 513 *norm += fabs(array[i]); 514 } 515 break; 516 case CEED_NORM_2: 517 for (int i=0; i<vec->length; i++) { 518 *norm += fabs(array[i])*fabs(array[i]); 519 } 520 break; 521 case CEED_NORM_MAX: 522 for (int 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) 528 *norm = sqrt(*norm); 529 530 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 531 return CEED_ERROR_SUCCESS; 532 } 533 534 /** 535 @brief Compute y = alpha x + y 536 537 @param y[in,out] target vector for sum 538 @param alpha[in] scaling factor 539 @param x[in] second vector, must be different than y 540 541 @return An error code: 0 - success, otherwise - failure 542 543 @ref User 544 **/ 545 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) { 546 int ierr; 547 CeedScalar *y_array; 548 CeedScalar const *x_array; 549 CeedInt n_x, n_y; 550 551 ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr); 552 ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr); 553 if (n_x != n_y) 554 // LCOV_EXCL_START 555 return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED, 556 "Cannot add vector of different lengths"); 557 // LCOV_EXCL_STOP 558 if (x == y) 559 // LCOV_EXCL_START 560 return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED, 561 "Cannot use same vector for x and y in CeedVectorAXPY"); 562 // LCOV_EXCL_STOP 563 564 // Backend implementation 565 if (y->AXPY) 566 return y->AXPY(y, alpha, x); 567 568 // Default implementation 569 ierr = CeedVectorGetArray(y, CEED_MEM_HOST, &y_array); CeedChk(ierr); 570 ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr); 571 572 for (CeedInt i=0; i<n_y; i++) 573 y_array[i] += alpha * x_array[i]; 574 575 ierr = CeedVectorRestoreArray(y, &y_array); CeedChk(ierr); 576 ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr); 577 578 return CEED_ERROR_SUCCESS; 579 } 580 581 /** 582 @brief Compute the pointwise multiplication w = x * y. Any 583 subset of x, y, and w may be the same vector. 584 585 @param w[out] target vector for the product 586 @param x[in] first vector for product 587 @param y[in] second vector for the product 588 589 @return An error code: 0 - success, otherwise - failure 590 591 @ ref User 592 **/ 593 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) { 594 int ierr; 595 CeedScalar *w_array; 596 CeedScalar const *x_array, *y_array; 597 CeedInt n_x, n_y, n_w; 598 599 ierr = CeedVectorGetLength(w, &n_w); CeedChk(ierr); 600 ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr); 601 ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr); 602 if (n_w != n_x || n_w != n_y) 603 // LCOV_EXCL_START 604 return CeedError(w->ceed, CEED_ERROR_UNSUPPORTED, 605 "Cannot multiply vectors of different lengths"); 606 // LCOV_EXCL_STOP 607 608 // Backend implementation 609 if (w->PointwiseMult) 610 return w->PointwiseMult(w, x, y); 611 612 // Default implementation 613 ierr = CeedVectorGetArray(w, CEED_MEM_HOST, &w_array); CeedChk(ierr); 614 if (x != w) { 615 ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr); 616 } else { 617 x_array = w_array; 618 } 619 if (y != w && y != x) { 620 ierr = CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array); CeedChk(ierr); 621 } else if (y != x) { 622 y_array = w_array; 623 } else { 624 y_array = x_array; 625 } 626 627 for (CeedInt i=0; i<n_w; i++) 628 w_array[i] = x_array[i] * y_array[i]; 629 630 if (y != w && y != x) { 631 ierr = CeedVectorRestoreArrayRead(y, &y_array); CeedChk(ierr); 632 } 633 if (x != w) { 634 ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr); 635 } 636 ierr = CeedVectorRestoreArray(w, &w_array); CeedChk(ierr); 637 return CEED_ERROR_SUCCESS; 638 } 639 640 /** 641 @brief Take the reciprocal of a CeedVector. 642 643 @param vec CeedVector to take reciprocal 644 645 @return An error code: 0 - success, otherwise - failure 646 647 @ref User 648 **/ 649 int CeedVectorReciprocal(CeedVector vec) { 650 int ierr; 651 652 // Check if vector data set 653 if (!vec->state) 654 // LCOV_EXCL_START 655 return CeedError(vec->ceed, CEED_ERROR_INCOMPLETE, 656 "CeedVector must have data set to take reciprocal"); 657 // LCOV_EXCL_STOP 658 659 // Backend impl for GPU, if added 660 if (vec->Reciprocal) { 661 ierr = vec->Reciprocal(vec); CeedChk(ierr); 662 return CEED_ERROR_SUCCESS; 663 } 664 665 CeedInt len; 666 ierr = CeedVectorGetLength(vec, &len); CeedChk(ierr); 667 CeedScalar *array; 668 ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 669 for (CeedInt i=0; i<len; i++) 670 if (fabs(array[i]) > CEED_EPSILON) 671 array[i] = 1./array[i]; 672 673 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 674 return CEED_ERROR_SUCCESS; 675 } 676 677 /** 678 @brief View a CeedVector 679 680 @param[in] vec CeedVector to view 681 @param[in] fp_fmt Printing format 682 @param[in] stream Filestream to write to 683 684 @return An error code: 0 - success, otherwise - failure 685 686 @ref User 687 **/ 688 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) { 689 const CeedScalar *x; 690 691 int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr); 692 693 char fmt[1024]; 694 fprintf(stream, "CeedVector length %ld\n", (long)vec->length); 695 snprintf(fmt, sizeof fmt, " %s\n", fp_fmt ? fp_fmt : "%g"); 696 for (CeedInt i=0; i<vec->length; i++) 697 fprintf(stream, fmt, x[i]); 698 699 ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr); 700 return CEED_ERROR_SUCCESS; 701 } 702 703 /** 704 @brief Get the length of a CeedVector 705 706 @param vec CeedVector to retrieve length 707 @param[out] length Variable to store length 708 709 @return An error code: 0 - success, otherwise - failure 710 711 @ref User 712 **/ 713 int CeedVectorGetLength(CeedVector vec, CeedInt *length) { 714 *length = vec->length; 715 return CEED_ERROR_SUCCESS; 716 } 717 718 /** 719 @brief Destroy a CeedVector 720 721 @param vec CeedVector to destroy 722 723 @return An error code: 0 - success, otherwise - failure 724 725 @ref User 726 **/ 727 int CeedVectorDestroy(CeedVector *vec) { 728 int ierr; 729 730 if (!*vec || --(*vec)->ref_count > 0) return CEED_ERROR_SUCCESS; 731 732 if (((*vec)->state % 2) == 1) 733 return CeedError((*vec)->ceed, CEED_ERROR_ACCESS, 734 "Cannot destroy CeedVector, the writable access " 735 "lock is in use"); 736 737 if ((*vec)->num_readers > 0) 738 return CeedError((*vec)->ceed, CEED_ERROR_ACCESS, 739 "Cannot destroy CeedVector, a process has " 740 "read access"); 741 742 if ((*vec)->Destroy) { 743 ierr = (*vec)->Destroy(*vec); CeedChk(ierr); 744 } 745 746 ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr); 747 ierr = CeedFree(vec); CeedChk(ierr); 748 return CEED_ERROR_SUCCESS; 749 } 750 751 /// @} 752