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