xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-vector.c (revision 547d9b97859fb07c9c2b832a30615e0bf91eaab3)
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   @param vec           CeedVector to retrieve maximum value
349   @param type          Norm type CEED_NORM_1, CEED_NORM_2, or CEED_NORM_MAX
350   @param[out] norm     Variable to store norm value
351 
352   @return An error code: 0 - success, otherwise - failure
353 
354   @ref Advanced
355 **/
356 int CeedVectorNorm(CeedVector vec, CeedNormType type, CeedScalar *norm) {
357   int ierr;
358 
359   // Backend impl for GPU, if added
360   if (vec->Norm) {
361     ierr = vec->Norm(vec, type, norm); CeedChk(ierr);
362     return 0;
363   }
364 
365   const CeedScalar *array;
366   ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
367 
368   *norm = 0.;
369   switch (type) {
370   case CEED_NORM_1:
371     for (int i=0; i<vec->length; i++) {
372       *norm += fabs(array[i]);
373     }
374     break;
375   case CEED_NORM_2:
376     for (int i=0; i<vec->length; i++) {
377       *norm += fabs(array[i])*fabs(array[i]);
378     }
379     break;
380   case CEED_NORM_MAX:
381     for (int i=0; i<vec->length; i++) {
382       const CeedScalar absi = fabs(array[i]);
383       *norm = *norm > absi ? *norm : absi;
384     }
385   }
386   if (type == CEED_NORM_2)
387     *norm = sqrt(*norm);
388 
389   ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
390 
391   return 0;
392 }
393 
394 /**
395   @brief Get the state of a CeedVector
396 
397   @param vec           CeedVector to retrieve state
398   @param[out] state    Variable to store state
399 
400   @return An error code: 0 - success, otherwise - failure
401 
402   @ref Advanced
403 **/
404 int CeedVectorGetState(CeedVector vec, uint64_t *state) {
405   *state = vec->state;
406   return 0;
407 }
408 
409 /**
410   @brief Get the backend data of a CeedVector
411 
412   @param vec           CeedVector to retrieve state
413   @param[out] data     Variable to store data
414 
415   @return An error code: 0 - success, otherwise - failure
416 
417   @ref Advanced
418 **/
419 int CeedVectorGetData(CeedVector vec, void **data) {
420   *data = vec->data;
421   return 0;
422 }
423 
424 /**
425   @brief Set the backend data of a CeedVector
426 
427   @param[out] vec     CeedVector to retrieve state
428   @param data         Data to set
429 
430   @return An error code: 0 - success, otherwise - failure
431 
432   @ref Advanced
433 **/
434 int CeedVectorSetData(CeedVector vec, void **data) {
435   vec->data = *data;
436   return 0;
437 }
438 
439 /**
440   @brief Add a refrence to a CeedVector
441 
442   @param[out] vec     CeedVector to increment refrence counter
443 
444   @return An error code: 0 - success, otherwise - failure
445 
446   @ref Advanced
447 **/
448 int CeedVectorAddReference(CeedVector vec) {
449   vec->refcount++;
450   return 0;
451 }
452 
453 /**
454   @brief Destroy a CeedVector
455 
456   @param vec   CeedVector to destroy
457 
458   @return An error code: 0 - success, otherwise - failure
459 
460   @ref Basic
461 **/
462 int CeedVectorDestroy(CeedVector *vec) {
463   int ierr;
464 
465   if (!*vec || --(*vec)->refcount > 0)
466     return 0;
467 
468   if ((*vec) && ((*vec)->state % 2) == 1)
469     return CeedError((*vec)->ceed, 1, "Cannot destroy CeedVector, the access "
470                      "lock is in use");
471 
472   if ((*vec)->Destroy) {
473     ierr = (*vec)->Destroy(*vec); CeedChk(ierr);
474   }
475 
476   ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr);
477   ierr = CeedFree(vec); CeedChk(ierr);
478 
479   return 0;
480 }
481 
482 /// @cond DOXYGEN_SKIP
483 // Indicate that vector will be provided as an explicit argument to
484 //   CeedOperatorApply().
485 CeedVector CEED_VECTOR_ACTIVE = &ceed_vector_active;
486 
487 // Indicate that no vector is applicable (i.e., for CEED_EVAL_WEIGHTS).
488 CeedVector CEED_VECTOR_NONE = &ceed_vector_none;
489 /// @endcond
490 /// @}
491