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