xref: /libCEED/interface/ceed-vector.c (revision 25fd8ed6e8da5733645afac88444c97cbc278f75)
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            Use @CeedVectorSyncArray() to force synchronization for externally
172            allocated arrays, such as arrays set with @ref CEED_USE_POINTER.
173 
174   @param vec   CeedVector
175   @param mtype Memory type of the array being passed
176   @param cmode Copy mode for the array
177   @param array Array to be used, or NULL with @ref CEED_COPY_VALUES to have the
178                  library allocate
179 
180   @return An error code: 0 - success, otherwise - failure
181 
182   @ref User
183 **/
184 int CeedVectorSetArray(CeedVector vec, CeedMemType mtype, CeedCopyMode cmode,
185                        CeedScalar *array) {
186   int ierr;
187 
188   if (!vec->SetArray)
189     // LCOV_EXCL_START
190     return CeedError(vec->ceed, 1, "Backend does not support VectorSetArray");
191   // LCOV_EXCL_STOP
192 
193   if (vec->state % 2 == 1)
194     return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the "
195                      "access lock is already in use");
196 
197   if (vec->numreaders > 0)
198     return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, a "
199                      "process has read access");
200 
201   ierr = vec->SetArray(vec, mtype, cmode, array); CeedChk(ierr);
202   vec->state += 2;
203 
204   return 0;
205 }
206 
207 /**
208   @brief Set the CeedVector to a constant value
209 
210   @param vec        CeedVector
211   @param[in] value  Value to be used
212 
213   @return An error code: 0 - success, otherwise - failure
214 
215   @ref User
216 **/
217 int CeedVectorSetValue(CeedVector vec, CeedScalar value) {
218   int ierr;
219 
220   if (vec->state % 2 == 1)
221     return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the "
222                      "access lock is already in use");
223 
224   if (vec->SetValue) {
225     ierr = vec->SetValue(vec, value); CeedChk(ierr);
226   } else {
227     CeedScalar *array;
228     ierr = CeedVectorGetArray(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
229     for (int i=0; i<vec->length; i++) array[i] = value;
230     ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr);
231   }
232 
233   vec->state += 2;
234 
235   return 0;
236 }
237 
238 /**
239   @brief Sync the CeedVector to a specified memtype. This function is used to
240            force synchronization of arrays set with @ref CeedVectorSetArray().
241            If the requested memtype is already synchronized, this function
242            results in a no-op.
243 
244   @param vec        CeedVector
245   @param mtype      Memtype to be synced
246 
247   @return An error code: 0 - success, otherwise - failure
248 
249   @ref User
250 **/
251 int CeedVectorSyncArray(CeedVector vec, CeedMemType mtype) {
252   int ierr;
253 
254   if (vec->state % 2 == 1)
255     return CeedError(vec->ceed, 1, "Cannot sync CeedVector, the access lock is "
256                      "already in use");
257 
258   if (vec->SyncArray) {
259     ierr = vec->SyncArray(vec, mtype); CeedChk(ierr);
260   } else {
261     const CeedScalar *array;
262     ierr = CeedVectorGetArrayRead(vec, mtype, &array); CeedChk(ierr);
263     ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
264   }
265 
266   return 0;
267 }
268 
269 /**
270   @brief Get read/write access to a CeedVector via the specified memory type.
271            Restore access with @ref CeedVectorRestoreArray().
272 
273   @param vec        CeedVector to access
274   @param mtype      Memory type on which to access 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
277 
278   @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide
279     access to array pointers in the desired memory space. Pairing get/restore
280     allows the Vector to track access, thus knowing if norms or other
281     operations may need to be recomputed.
282 
283   @return An error code: 0 - success, otherwise - failure
284 
285   @ref User
286 **/
287 int CeedVectorGetArray(CeedVector vec, CeedMemType mtype, CeedScalar **array) {
288   int ierr;
289 
290   if (!vec->GetArray)
291     // LCOV_EXCL_START
292     return CeedError(vec->ceed, 1, "Backend does not support GetArray");
293   // LCOV_EXCL_STOP
294 
295   if (vec->state % 2 == 1)
296     return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, the "
297                      "access lock is already in use");
298 
299   if (vec->numreaders > 0)
300     return CeedError(vec->ceed, 1, "Cannot grant CeedVector array access, a "
301                      "process has read access");
302 
303   ierr = vec->GetArray(vec, mtype, array); CeedChk(ierr);
304   vec->state += 1;
305 
306   return 0;
307 }
308 
309 /**
310   @brief Get read-only access to a CeedVector via the specified memory type.
311            Restore access with @ref CeedVectorRestoreArrayRead().
312 
313   @param vec        CeedVector to access
314   @param mtype      Memory type on which to access the array.  If the backend
315                     uses a different memory type, this will perform a copy
316                     (possibly cached).
317   @param[out] array Array on memory type mtype
318 
319   @return An error code: 0 - success, otherwise - failure
320 
321   @ref User
322 **/
323 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mtype,
324                            const CeedScalar **array) {
325   int ierr;
326 
327   if (!vec->GetArrayRead)
328     // LCOV_EXCL_START
329     return CeedError(vec->ceed, 1, "Backend does not support GetArrayRead");
330   // LCOV_EXCL_STOP
331 
332   if (vec->state % 2 == 1)
333     return CeedError(vec->ceed, 1, "Cannot grant CeedVector read-only array "
334                      "access, the access lock is already in use");
335 
336   ierr = vec->GetArrayRead(vec, mtype, array); CeedChk(ierr);
337   vec->numreaders++;
338 
339   return 0;
340 }
341 
342 /**
343   @brief Restore an array obtained using @ref CeedVectorGetArray()
344 
345   @param vec     CeedVector to restore
346   @param array   Array of vector data
347 
348   @return An error code: 0 - success, otherwise - failure
349 
350   @ref User
351 **/
352 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) {
353   int ierr;
354 
355   if (!vec->RestoreArray)
356     // LCOV_EXCL_START
357     return CeedError(vec->ceed, 1, "Backend does not support RestoreArray");
358   // LCOV_EXCL_STOP
359 
360   if (vec->state % 2 != 1)
361     return CeedError(vec->ceed, 1, "Cannot restore CeedVector array access, "
362                      "access was not granted");
363 
364   ierr = vec->RestoreArray(vec); CeedChk(ierr);
365   *array = NULL;
366   vec->state += 1;
367 
368   return 0;
369 }
370 
371 /**
372   @brief Restore an array obtained using @ref CeedVectorGetArrayRead()
373 
374   @param vec     CeedVector to restore
375   @param array   Array of vector data
376 
377   @return An error code: 0 - success, otherwise - failure
378 
379   @ref User
380 **/
381 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) {
382   int ierr;
383 
384   if (!vec->RestoreArrayRead)
385     // LCOV_EXCL_START
386     return CeedError(vec->ceed, 1, "Backend does not support RestoreArrayRead");
387   // LCOV_EXCL_STOP
388 
389   ierr = vec->RestoreArrayRead(vec); CeedChk(ierr);
390   *array = NULL;
391   vec->numreaders--;
392 
393   return 0;
394 }
395 
396 /**
397   @brief Get the norm of a CeedVector.
398 
399   Note: This operation is local to the CeedVector. This function will likely
400           not provide the desired results for the norm of the libCEED portion
401           of a parallel vector or a CeedVector with duplicated or hanging nodes.
402 
403   @param vec           CeedVector to retrieve maximum value
404   @param type          Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX
405   @param[out] norm     Variable to store norm value
406 
407   @return An error code: 0 - success, otherwise - failure
408 
409   @ref User
410 **/
411 int CeedVectorNorm(CeedVector vec, CeedNormType type, CeedScalar *norm) {
412   int ierr;
413 
414   // Backend impl for GPU, if added
415   if (vec->Norm) {
416     ierr = vec->Norm(vec, type, norm); CeedChk(ierr);
417     return 0;
418   }
419 
420   const CeedScalar *array;
421   ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
422 
423   *norm = 0.;
424   switch (type) {
425   case CEED_NORM_1:
426     for (int i=0; i<vec->length; i++) {
427       *norm += fabs(array[i]);
428     }
429     break;
430   case CEED_NORM_2:
431     for (int i=0; i<vec->length; i++) {
432       *norm += fabs(array[i])*fabs(array[i]);
433     }
434     break;
435   case CEED_NORM_MAX:
436     for (int i=0; i<vec->length; i++) {
437       const CeedScalar absi = fabs(array[i]);
438       *norm = *norm > absi ? *norm : absi;
439     }
440   }
441   if (type == CEED_NORM_2)
442     *norm = sqrt(*norm);
443 
444   ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
445 
446   return 0;
447 }
448 
449 /**
450   @brief View a CeedVector
451 
452   @param[in] vec           CeedVector to view
453   @param[in] fpfmt         Printing format
454   @param[in] stream        Filestream to write to
455 
456   @return An error code: 0 - success, otherwise - failure
457 
458   @ref User
459 **/
460 int CeedVectorView(CeedVector vec, const char *fpfmt, FILE *stream) {
461   const CeedScalar *x;
462 
463   int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr);
464 
465   char fmt[1024];
466   fprintf(stream, "CeedVector length %ld\n", (long)vec->length);
467   snprintf(fmt, sizeof fmt, "  %s\n", fpfmt ? fpfmt : "%g");
468   for (CeedInt i=0; i<vec->length; i++)
469     fprintf(stream, fmt, x[i]);
470 
471   ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr);
472 
473   return 0;
474 }
475 
476 /**
477   @brief Get the length of a CeedVector
478 
479   @param vec           CeedVector to retrieve length
480   @param[out] length   Variable to store length
481 
482   @return An error code: 0 - success, otherwise - failure
483 
484   @ref User
485 **/
486 int CeedVectorGetLength(CeedVector vec, CeedInt *length) {
487   *length = vec->length;
488   return 0;
489 }
490 
491 /**
492   @brief Destroy a CeedVector
493 
494   @param vec   CeedVector to destroy
495 
496   @return An error code: 0 - success, otherwise - failure
497 
498   @ref User
499 **/
500 int CeedVectorDestroy(CeedVector *vec) {
501   int ierr;
502 
503   if (!*vec || --(*vec)->refcount > 0)
504     return 0;
505 
506   if ((*vec) && ((*vec)->state % 2) == 1)
507     return CeedError((*vec)->ceed, 1, "Cannot destroy CeedVector, the access "
508                      "lock is in use");
509 
510   if ((*vec)->Destroy) {
511     ierr = (*vec)->Destroy(*vec); CeedChk(ierr);
512   }
513 
514   ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr);
515   ierr = CeedFree(vec); CeedChk(ierr);
516 
517   return 0;
518 }
519 
520 /// @}
521