xref: /libCEED/interface/ceed-vector.c (revision 6cf3b68d14a6585b72105699d8534a500a16d388)
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 reference 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   *(void **)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)->state % 2) == 1)
578     return CeedError((*vec)->ceed, 1,
579                      "Cannot destroy CeedVector, the writable access "
580                      "lock is in use");
581 
582   if ((*vec)->numreaders > 0)
583     return CeedError((*vec)->ceed, 1, "Cannot destroy CeedVector, a process has "
584                      "read access");
585 
586   if ((*vec)->Destroy) {
587     ierr = (*vec)->Destroy(*vec); CeedChk(ierr);
588   }
589 
590   ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr);
591   ierr = CeedFree(vec); CeedChk(ierr);
592 
593   return 0;
594 }
595 
596 /// @}
597