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