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 271 272 @param vec CeedVector 273 @param mtype Memory type on which to take the array. If the backend 274 uses a different memory type, this will perform a copy. 275 @param[out] array Array on memory type mtype, or NULL if array pointer is 276 not required 277 278 @return An error code: 0 - success, otherwise - failure 279 280 @ref User 281 **/ 282 int CeedVectorTakeArray(CeedVector vec, CeedMemType mtype, CeedScalar **array) { 283 int ierr; 284 285 if (vec->state % 2 == 1) 286 // LCOV_EXCL_START 287 return CeedError(vec->ceed, 1, "Cannot take CeedVector array, the access " 288 "lock is already in use"); 289 // LCOV_EXCL_STOP 290 if (vec->numreaders > 0) 291 // LCOV_EXCL_START 292 return CeedError(vec->ceed, 1, "Cannot take CeedVector array, a process " 293 "has read access"); 294 // LCOV_EXCL_STOP 295 296 CeedScalar *tempArray = NULL; 297 ierr = vec->TakeArray(vec, mtype, &tempArray); CeedChk(ierr); 298 if (array) 299 (*array) = tempArray; 300 return 0; 301 } 302 303 /** 304 @brief Get read/write access to a CeedVector via the specified memory type. 305 Restore access with @ref CeedVectorRestoreArray(). 306 307 @param vec CeedVector to access 308 @param mtype Memory type on which to access the array. If the backend 309 uses a different memory type, this will perform a copy. 310 @param[out] array Array on memory type mtype 311 312 @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide 313 access to array pointers in the desired memory space. Pairing get/restore 314 allows the Vector to track access, thus knowing if norms or other 315 operations may need to be recomputed. 316 317 @return An error code: 0 - success, otherwise - failure 318 319 @ref User 320 **/ 321 int CeedVectorGetArray(CeedVector vec, CeedMemType mtype, CeedScalar **array) { 322 int ierr; 323 324 if (!vec->GetArray) 325 // LCOV_EXCL_START 326 return CeedError(vec->ceed, 1, "Backend does not support GetArray"); 327 // LCOV_EXCL_STOP 328 329 if (vec->state % 2 == 1) 330 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the " 331 "access lock is already in use"); 332 333 if (vec->numreaders > 0) 334 return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, a " 335 "process has read access"); 336 337 ierr = vec->GetArray(vec, mtype, array); CeedChk(ierr); 338 vec->state += 1; 339 340 return 0; 341 } 342 343 /** 344 @brief Get read-only access to a CeedVector via the specified memory type. 345 Restore access with @ref CeedVectorRestoreArrayRead(). 346 347 @param vec CeedVector to access 348 @param mtype Memory type on which to access the array. If the backend 349 uses a different memory type, this will perform a copy 350 (possibly cached). 351 @param[out] array Array on memory type mtype 352 353 @return An error code: 0 - success, otherwise - failure 354 355 @ref User 356 **/ 357 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mtype, 358 const CeedScalar **array) { 359 int ierr; 360 361 if (!vec->GetArrayRead) 362 // LCOV_EXCL_START 363 return CeedError(vec->ceed, 1, "Backend does not support GetArrayRead"); 364 // LCOV_EXCL_STOP 365 366 if (vec->state % 2 == 1) 367 return CeedError(vec->ceed, 1, "Cannot grant CeedVector read-only array " 368 "access, the access lock is already in use"); 369 370 ierr = vec->GetArrayRead(vec, mtype, array); CeedChk(ierr); 371 vec->numreaders++; 372 373 return 0; 374 } 375 376 /** 377 @brief Restore an array obtained using @ref CeedVectorGetArray() 378 379 @param vec CeedVector to restore 380 @param array Array of vector data 381 382 @return An error code: 0 - success, otherwise - failure 383 384 @ref User 385 **/ 386 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) { 387 int ierr; 388 389 if (!vec->RestoreArray) 390 // LCOV_EXCL_START 391 return CeedError(vec->ceed, 1, "Backend does not support RestoreArray"); 392 // LCOV_EXCL_STOP 393 394 if (vec->state % 2 != 1) 395 return CeedError(vec->ceed, 1, "Cannot restore CeedVector array access, " 396 "access was not granted"); 397 398 ierr = vec->RestoreArray(vec); CeedChk(ierr); 399 *array = NULL; 400 vec->state += 1; 401 402 return 0; 403 } 404 405 /** 406 @brief Restore an array obtained using @ref CeedVectorGetArrayRead() 407 408 @param vec CeedVector to restore 409 @param array Array of vector data 410 411 @return An error code: 0 - success, otherwise - failure 412 413 @ref User 414 **/ 415 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) { 416 int ierr; 417 418 if (!vec->RestoreArrayRead) 419 // LCOV_EXCL_START 420 return CeedError(vec->ceed, 1, "Backend does not support RestoreArrayRead"); 421 // LCOV_EXCL_STOP 422 423 ierr = vec->RestoreArrayRead(vec); CeedChk(ierr); 424 *array = NULL; 425 vec->numreaders--; 426 427 return 0; 428 } 429 430 /** 431 @brief Get the norm of a CeedVector. 432 433 Note: This operation is local to the CeedVector. This function will likely 434 not provide the desired results for the norm of the libCEED portion 435 of a parallel vector or a CeedVector with duplicated or hanging nodes. 436 437 @param vec CeedVector to retrieve maximum value 438 @param type Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX 439 @param[out] norm Variable to store norm value 440 441 @return An error code: 0 - success, otherwise - failure 442 443 @ref User 444 **/ 445 int CeedVectorNorm(CeedVector vec, CeedNormType type, CeedScalar *norm) { 446 int ierr; 447 448 // Backend impl for GPU, if added 449 if (vec->Norm) { 450 ierr = vec->Norm(vec, type, norm); CeedChk(ierr); 451 return 0; 452 } 453 454 const CeedScalar *array; 455 ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr); 456 457 *norm = 0.; 458 switch (type) { 459 case CEED_NORM_1: 460 for (int i=0; i<vec->length; i++) { 461 *norm += fabs(array[i]); 462 } 463 break; 464 case CEED_NORM_2: 465 for (int i=0; i<vec->length; i++) { 466 *norm += fabs(array[i])*fabs(array[i]); 467 } 468 break; 469 case CEED_NORM_MAX: 470 for (int i=0; i<vec->length; i++) { 471 const CeedScalar absi = fabs(array[i]); 472 *norm = *norm > absi ? *norm : absi; 473 } 474 } 475 if (type == CEED_NORM_2) 476 *norm = sqrt(*norm); 477 478 ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr); 479 480 return 0; 481 } 482 483 /** 484 @brief View a CeedVector 485 486 @param[in] vec CeedVector to view 487 @param[in] fpfmt Printing format 488 @param[in] stream Filestream to write to 489 490 @return An error code: 0 - success, otherwise - failure 491 492 @ref User 493 **/ 494 int CeedVectorView(CeedVector vec, const char *fpfmt, FILE *stream) { 495 const CeedScalar *x; 496 497 int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr); 498 499 char fmt[1024]; 500 fprintf(stream, "CeedVector length %ld\n", (long)vec->length); 501 snprintf(fmt, sizeof fmt, " %s\n", fpfmt ? fpfmt : "%g"); 502 for (CeedInt i=0; i<vec->length; i++) 503 fprintf(stream, fmt, x[i]); 504 505 ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr); 506 507 return 0; 508 } 509 510 /** 511 @brief Get the length of a CeedVector 512 513 @param vec CeedVector to retrieve length 514 @param[out] length Variable to store length 515 516 @return An error code: 0 - success, otherwise - failure 517 518 @ref User 519 **/ 520 int CeedVectorGetLength(CeedVector vec, CeedInt *length) { 521 *length = vec->length; 522 return 0; 523 } 524 525 /** 526 @brief Destroy a CeedVector 527 528 @param vec CeedVector to destroy 529 530 @return An error code: 0 - success, otherwise - failure 531 532 @ref User 533 **/ 534 int CeedVectorDestroy(CeedVector *vec) { 535 int ierr; 536 537 if (!*vec || --(*vec)->refcount > 0) 538 return 0; 539 540 if ((*vec) && ((*vec)->state % 2) == 1) 541 return CeedError((*vec)->ceed, 1, "Cannot destroy CeedVector, the access " 542 "lock is in use"); 543 544 if ((*vec)->Destroy) { 545 ierr = (*vec)->Destroy(*vec); CeedChk(ierr); 546 } 547 548 ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr); 549 ierr = CeedFree(vec); CeedChk(ierr); 550 551 return 0; 552 } 553 554 /// @} 555