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.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->refcount++; 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 126 /// ---------------------------------------------------------------------------- 127 /// CeedVector Public API 128 /// ---------------------------------------------------------------------------- 129 /// @addtogroup CeedVectorUser 130 /// @{ 131 132 /** 133 @brief Create a CeedVector of the specified length (does not allocate memory) 134 135 @param ceed Ceed object where the CeedVector will be created 136 @param length Length of vector 137 @param[out] vec Address of the variable where the newly created 138 CeedVector will be stored 139 140 @return An error code: 0 - success, otherwise - failure 141 142 @ref User 143 **/ 144 int CeedVectorCreate(Ceed ceed, CeedInt length, CeedVector *vec) { 145 int ierr; 146 147 if (!ceed->VectorCreate) { 148 Ceed delegate; 149 ierr = CeedGetObjectDelegate(ceed, &delegate, "Vector"); CeedChk(ierr); 150 151 if (!delegate) 152 // LCOV_EXCL_START 153 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, 154 "Backend does not support VectorCreate"); 155 // LCOV_EXCL_STOP 156 157 ierr = CeedVectorCreate(delegate, length, vec); CeedChk(ierr); 158 return CEED_ERROR_SUCCESS; 159 } 160 161 ierr = CeedCalloc(1, vec); CeedChk(ierr); 162 (*vec)->ceed = ceed; 163 ceed->refcount++; 164 (*vec)->refcount = 1; 165 (*vec)->length = length; 166 (*vec)->state = 0; 167 ierr = ceed->VectorCreate(length, *vec); CeedChk(ierr); 168 return CEED_ERROR_SUCCESS; 169 } 170 171 /** 172 @brief Set the array used by a CeedVector, freeing any previously allocated 173 array if applicable. The backend may copy values to a different 174 memtype, such as during @ref CeedOperatorApply(). 175 See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray(). 176 177 @param vec CeedVector 178 @param mtype Memory type of the array being passed 179 @param cmode Copy mode for the array 180 @param array Array to be used, or NULL with @ref CEED_COPY_VALUES to have the 181 library allocate 182 183 @return An error code: 0 - success, otherwise - failure 184 185 @ref User 186 **/ 187 int CeedVectorSetArray(CeedVector vec, CeedMemType mtype, CeedCopyMode cmode, 188 CeedScalar *array) { 189 int ierr; 190 191 if (!vec->SetArray) 192 // LCOV_EXCL_START 193 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 194 "Backend does not support VectorSetArray"); 195 // LCOV_EXCL_STOP 196 197 if (vec->state % 2 == 1) 198 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 199 "Cannot grant CeedVector array access, the " 200 "access lock is already in use"); 201 202 if (vec->numreaders > 0) 203 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 204 "Cannot grant CeedVector array access, a " 205 "process has read access"); 206 207 ierr = vec->SetArray(vec, mtype, cmode, array); CeedChk(ierr); 208 vec->state += 2; 209 return CEED_ERROR_SUCCESS; 210 } 211 212 /** 213 @brief Set the CeedVector to a constant value 214 215 @param vec CeedVector 216 @param[in] value Value to be used 217 218 @return An error code: 0 - success, otherwise - failure 219 220 @ref User 221 **/ 222 int CeedVectorSetValue(CeedVector vec, CeedScalar value) { 223 int ierr; 224 225 if (vec->state % 2 == 1) 226 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 227 "Cannot grant CeedVector array access, the " 228 "access lock is already in use"); 229 230 if (vec->SetValue) { 231 ierr = vec->SetValue(vec, value); CeedChk(ierr); 232 } else { 233 CeedScalar *array; 234 ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 235 for (int i=0; i<vec->length; i++) array[i] = value; 236 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 237 } 238 vec->state += 2; 239 return CEED_ERROR_SUCCESS; 240 } 241 242 /** 243 @brief Sync the CeedVector to a specified memtype. This function is used to 244 force synchronization of arrays set with @ref CeedVectorSetArray(). 245 If the requested memtype is already synchronized, this function 246 results in a no-op. 247 248 @param vec CeedVector 249 @param mtype Memtype to be synced 250 251 @return An error code: 0 - success, otherwise - failure 252 253 @ref User 254 **/ 255 int CeedVectorSyncArray(CeedVector vec, CeedMemType mtype) { 256 int ierr; 257 258 if (vec->state % 2 == 1) 259 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 260 "Cannot sync CeedVector, the access lock is " 261 "already in use"); 262 263 if (vec->SyncArray) { 264 ierr = vec->SyncArray(vec, mtype); CeedChk(ierr); 265 } else { 266 const CeedScalar *array; 267 ierr = CeedVectorGetArrayRead(vec, mtype, &array); CeedChk(ierr); 268 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 269 } 270 return CEED_ERROR_SUCCESS; 271 } 272 273 /** 274 @brief Take ownership of the CeedVector array and remove the array from the 275 CeedVector. The caller is responsible for managing and freeing 276 the array. 277 278 @param vec CeedVector 279 @param mtype Memory type on which to take the array. If the backend 280 uses a different memory type, this will perform a copy. 281 @param[out] array Array on memory type mtype, or NULL if array pointer is 282 not required 283 284 @return An error code: 0 - success, otherwise - failure 285 286 @ref User 287 **/ 288 int CeedVectorTakeArray(CeedVector vec, CeedMemType mtype, CeedScalar **array) { 289 int ierr; 290 291 if (vec->state % 2 == 1) 292 // LCOV_EXCL_START 293 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 294 "Cannot take CeedVector array, the access " 295 "lock is already in use"); 296 // LCOV_EXCL_STOP 297 if (vec->numreaders > 0) 298 // LCOV_EXCL_START 299 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 300 "Cannot take CeedVector array, a process " 301 "has read access"); 302 // LCOV_EXCL_STOP 303 304 CeedScalar *tempArray = NULL; 305 ierr = vec->TakeArray(vec, mtype, &tempArray); CeedChk(ierr); 306 if (array) (*array) = tempArray; 307 return CEED_ERROR_SUCCESS; 308 } 309 310 /** 311 @brief Get read/write access to a CeedVector via the specified memory type. 312 Restore access with @ref CeedVectorRestoreArray(). 313 314 @param vec CeedVector to access 315 @param mtype Memory type on which to access the array. If the backend 316 uses a different memory type, this will perform a copy. 317 @param[out] array Array on memory type mtype 318 319 @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide 320 access to array pointers in the desired memory space. Pairing get/restore 321 allows the Vector to track access, thus knowing if norms or other 322 operations may need to be recomputed. 323 324 @return An error code: 0 - success, otherwise - failure 325 326 @ref User 327 **/ 328 int CeedVectorGetArray(CeedVector vec, CeedMemType mtype, CeedScalar **array) { 329 int ierr; 330 331 if (!vec->GetArray) 332 // LCOV_EXCL_START 333 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 334 "Backend does not support GetArray"); 335 // LCOV_EXCL_STOP 336 337 if (vec->state % 2 == 1) 338 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 339 "Cannot grant CeedVector array access, the " 340 "access lock is already in use"); 341 342 if (vec->numreaders > 0) 343 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 344 "Cannot grant CeedVector array access, a " 345 "process has read access"); 346 347 ierr = vec->GetArray(vec, mtype, array); CeedChk(ierr); 348 vec->state += 1; 349 return CEED_ERROR_SUCCESS; 350 } 351 352 /** 353 @brief Get read-only access to a CeedVector via the specified memory type. 354 Restore access with @ref CeedVectorRestoreArrayRead(). 355 356 @param vec CeedVector to access 357 @param mtype Memory type on which to access the array. If the backend 358 uses a different memory type, this will perform a copy 359 (possibly cached). 360 @param[out] array Array on memory type mtype 361 362 @return An error code: 0 - success, otherwise - failure 363 364 @ref User 365 **/ 366 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mtype, 367 const CeedScalar **array) { 368 int ierr; 369 370 if (!vec->GetArrayRead) 371 // LCOV_EXCL_START 372 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 373 "Backend does not support GetArrayRead"); 374 // LCOV_EXCL_STOP 375 376 if (vec->state % 2 == 1) 377 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 378 "Cannot grant CeedVector read-only array " 379 "access, the access lock is already in use"); 380 381 ierr = vec->GetArrayRead(vec, mtype, array); CeedChk(ierr); 382 vec->numreaders++; 383 return CEED_ERROR_SUCCESS; 384 } 385 386 /** 387 @brief Restore an array obtained using @ref CeedVectorGetArray() 388 389 @param vec CeedVector to restore 390 @param array Array of vector data 391 392 @return An error code: 0 - success, otherwise - failure 393 394 @ref User 395 **/ 396 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 397 int ierr; 398 399 if (!vec->RestoreArray) 400 // LCOV_EXCL_START 401 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 402 "Backend does not support RestoreArray"); 403 // LCOV_EXCL_STOP 404 405 if (vec->state % 2 != 1) 406 return CeedError(vec->ceed, CEED_ERROR_ACCESS, 407 "Cannot restore CeedVector array access, " 408 "access was not granted"); 409 410 ierr = vec->RestoreArray(vec); CeedChk(ierr); 411 *array = NULL; 412 vec->state += 1; 413 return CEED_ERROR_SUCCESS; 414 } 415 416 /** 417 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 418 419 @param vec CeedVector to restore 420 @param array Array of vector data 421 422 @return An error code: 0 - success, otherwise - failure 423 424 @ref User 425 **/ 426 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 427 int ierr; 428 429 if (!vec->RestoreArrayRead) 430 // LCOV_EXCL_START 431 return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED, 432 "Backend does not support RestoreArrayRead"); 433 // LCOV_EXCL_STOP 434 435 ierr = vec->RestoreArrayRead(vec); CeedChk(ierr); 436 *array = NULL; 437 vec->numreaders--; 438 return CEED_ERROR_SUCCESS; 439 } 440 441 /** 442 @brief Get the norm of a CeedVector. 443 444 Note: This operation is local to the CeedVector. This function will likely 445 not provide the desired results for the norm of the libCEED portion 446 of a parallel vector or a CeedVector with duplicated or hanging nodes. 447 448 @param vec CeedVector to retrieve maximum value 449 @param type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 450 @param[out] norm Variable to store norm value 451 452 @return An error code: 0 - success, otherwise - failure 453 454 @ref User 455 **/ 456 int CeedVectorNorm(CeedVector vec, CeedNormType type, CeedScalar *norm) { 457 int ierr; 458 459 // Backend impl for GPU, if added 460 if (vec->Norm) { 461 ierr = vec->Norm(vec, type, norm); CeedChk(ierr); 462 return CEED_ERROR_SUCCESS; 463 } 464 465 const CeedScalar *array; 466 ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 467 468 *norm = 0.; 469 switch (type) { 470 case CEED_NORM_1: 471 for (int i=0; i<vec->length; i++) { 472 *norm += fabs(array[i]); 473 } 474 break; 475 case CEED_NORM_2: 476 for (int i=0; i<vec->length; i++) { 477 *norm += fabs(array[i])*fabs(array[i]); 478 } 479 break; 480 case CEED_NORM_MAX: 481 for (int i=0; i<vec->length; i++) { 482 const CeedScalar absi = fabs(array[i]); 483 *norm = *norm > absi ? *norm : absi; 484 } 485 } 486 if (type == CEED_NORM_2) 487 *norm = sqrt(*norm); 488 489 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 490 return CEED_ERROR_SUCCESS; 491 } 492 493 /** 494 @brief Take the reciprocal of a CeedVector. 495 496 @param vec CeedVector to take reciprocal 497 498 @return An error code: 0 - success, otherwise - failure 499 500 @ref User 501 **/ 502 int CeedVectorReciprocal(CeedVector vec) { 503 int ierr; 504 505 // Check if vector data set 506 if (!vec->state) 507 // LCOV_EXCL_START 508 return CeedError(vec->ceed, CEED_ERROR_INCOMPLETE, 509 "CeedVector must have data set to take reciprocal"); 510 // LCOV_EXCL_STOP 511 512 // Backend impl for GPU, if added 513 if (vec->Reciprocal) { 514 ierr = vec->Reciprocal(vec); CeedChk(ierr); 515 return CEED_ERROR_SUCCESS; 516 } 517 518 CeedInt len; 519 ierr = CeedVectorGetLength(vec, &len); CeedChk(ierr); 520 CeedScalar *array; 521 ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 522 for (CeedInt i=0; i<len; i++) 523 if (fabs(array[i]) > CEED_EPSILON) 524 array[i] = 1./array[i]; 525 526 ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr); 527 return CEED_ERROR_SUCCESS; 528 } 529 530 /** 531 @brief View a CeedVector 532 533 @param[in] vec CeedVector to view 534 @param[in] fpfmt Printing format 535 @param[in] stream Filestream to write to 536 537 @return An error code: 0 - success, otherwise - failure 538 539 @ref User 540 **/ 541 int CeedVectorView(CeedVector vec, const char *fpfmt, FILE *stream) { 542 const CeedScalar *x; 543 544 int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr); 545 546 char fmt[1024]; 547 fprintf(stream, "CeedVector length %ld\n", (long)vec->length); 548 snprintf(fmt, sizeof fmt, " %s\n", fpfmt ? fpfmt : "%g"); 549 for (CeedInt i=0; i<vec->length; i++) 550 fprintf(stream, fmt, x[i]); 551 552 ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr); 553 return CEED_ERROR_SUCCESS; 554 } 555 556 /** 557 @brief Get the length of a CeedVector 558 559 @param vec CeedVector to retrieve length 560 @param[out] length Variable to store length 561 562 @return An error code: 0 - success, otherwise - failure 563 564 @ref User 565 **/ 566 int CeedVectorGetLength(CeedVector vec, CeedInt *length) { 567 *length = vec->length; 568 return CEED_ERROR_SUCCESS; 569 } 570 571 /** 572 @brief Destroy a CeedVector 573 574 @param vec CeedVector to destroy 575 576 @return An error code: 0 - success, otherwise - failure 577 578 @ref User 579 **/ 580 int CeedVectorDestroy(CeedVector *vec) { 581 int ierr; 582 583 if (!*vec || --(*vec)->refcount > 0) return CEED_ERROR_SUCCESS; 584 585 if (((*vec)->state % 2) == 1) 586 return CeedError((*vec)->ceed, CEED_ERROR_ACCESS, 587 "Cannot destroy CeedVector, the writable access " 588 "lock is in use"); 589 590 if ((*vec)->numreaders > 0) 591 return CeedError((*vec)->ceed, CEED_ERROR_ACCESS, 592 "Cannot destroy CeedVector, a process has " 593 "read access"); 594 595 if ((*vec)->Destroy) { 596 ierr = (*vec)->Destroy(*vec); CeedChk(ierr); 597 } 598 599 ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr); 600 ierr = CeedFree(vec); CeedChk(ierr); 601 return CEED_ERROR_SUCCESS; 602 } 603 604 /// @} 605