xref: /libCEED/interface/ceed-vector.c (revision 9932a2afa242bd4abc454ccf5a69a8315f76e5b0) !
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/ceed.h>
18 #include <ceed/backend.h>
19 #include <ceed-impl.h>
20 #include <assert.h>
21 #include <math.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 
25 /// @file
26 /// Implementation of public CeedVector interfaces
27 
28 /// @cond DOXYGEN_SKIP
29 static struct CeedVector_private ceed_vector_active;
30 static struct CeedVector_private ceed_vector_none;
31 /// @endcond
32 
33 /// @addtogroup CeedVectorUser
34 /// @{
35 
36 /// Indicate that vector will be provided as an explicit argument to
37 ///   CeedOperatorApply().
38 const CeedVector CEED_VECTOR_ACTIVE = &ceed_vector_active;
39 
40 /// Indicate that no vector is applicable (i.e., for @ref CEED_EVAL_WEIGHT).
41 const CeedVector CEED_VECTOR_NONE = &ceed_vector_none;
42 
43 /// @}
44 
45 /// ----------------------------------------------------------------------------
46 /// CeedVector Backend API
47 /// ----------------------------------------------------------------------------
48 /// @addtogroup CeedVectorBackend
49 /// @{
50 
51 /**
52   @brief Check for valid data in a CeedVector
53 
54   @param vec                   CeedVector to check validity
55   @param[out] has_valid_array  Variable to store validity
56 
57   @return An error code: 0 - success, otherwise - failure
58 
59   @ref Backend
60 **/
61 int CeedVectorHasValidArray(CeedVector vec, bool *has_valid_array) {
62   int ierr;
63 
64   if (!vec->HasValidArray)
65     // LCOV_EXCL_START
66     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
67                      "Backend does not support HasValidArray");
68   // LCOV_EXCL_STOP
69 
70   ierr = vec->HasValidArray(vec, has_valid_array); CeedChk(ierr);
71 
72   return CEED_ERROR_SUCCESS;
73 }
74 
75 /**
76   @brief Check for borrowed array of a specific CeedMemType in a CeedVector
77 
78   @param vec                              CeedVector to check
79   @param mem_type                         Memory type to check
80   @param[out] has_borrowed_array_of_type  Variable to store result
81 
82   @return An error code: 0 - success, otherwise - failure
83 
84   @ref Backend
85 **/
86 int CeedVectorHasBorrowedArrayOfType(CeedVector vec, CeedMemType mem_type,
87                                      bool *has_borrowed_array_of_type) {
88   int ierr;
89 
90   if (!vec->HasBorrowedArrayOfType)
91     // LCOV_EXCL_START
92     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
93                      "Backend does not support HasBorrowedArrayOfType");
94   // LCOV_EXCL_STOP
95 
96   ierr = vec->HasBorrowedArrayOfType(vec, mem_type, has_borrowed_array_of_type);
97   CeedChk(ierr);
98 
99   return CEED_ERROR_SUCCESS;
100 }
101 
102 /**
103   @brief Get the state of a CeedVector
104 
105   @param vec         CeedVector to retrieve state
106   @param[out] state  Variable to store state
107 
108   @return An error code: 0 - success, otherwise - failure
109 
110   @ref Backend
111 **/
112 int CeedVectorGetState(CeedVector vec, uint64_t *state) {
113   *state = vec->state;
114   return CEED_ERROR_SUCCESS;
115 }
116 
117 /**
118   @brief Add a reference to a CeedVector
119 
120   @param[out] vec  CeedVector to increment reference counter
121 
122   @return An error code: 0 - success, otherwise - failure
123 
124   @ref Backend
125 **/
126 int CeedVectorAddReference(CeedVector vec) {
127   vec->ref_count++;
128   return CEED_ERROR_SUCCESS;
129 }
130 
131 /**
132   @brief Get the backend data of a CeedVector
133 
134   @param vec        CeedVector to retrieve state
135   @param[out] data  Variable to store data
136 
137   @return An error code: 0 - success, otherwise - failure
138 
139   @ref Backend
140 **/
141 int CeedVectorGetData(CeedVector vec, void *data) {
142   *(void **)data = vec->data;
143   return CEED_ERROR_SUCCESS;
144 }
145 
146 /**
147   @brief Set the backend data of a CeedVector
148 
149   @param[out] vec  CeedVector to retrieve state
150   @param data      Data to set
151 
152   @return An error code: 0 - success, otherwise - failure
153 
154   @ref Backend
155 **/
156 int CeedVectorSetData(CeedVector vec, void *data) {
157   vec->data = data;
158   return CEED_ERROR_SUCCESS;
159 }
160 
161 /**
162   @brief Increment the reference counter for a CeedVector
163 
164   @param vec  CeedVector to increment the reference counter
165 
166   @return An error code: 0 - success, otherwise - failure
167 
168   @ref Backend
169 **/
170 int CeedVectorReference(CeedVector vec) {
171   vec->ref_count++;
172   return CEED_ERROR_SUCCESS;
173 }
174 
175 /// @}
176 
177 /// ----------------------------------------------------------------------------
178 /// CeedVector Public API
179 /// ----------------------------------------------------------------------------
180 /// @addtogroup CeedVectorUser
181 /// @{
182 
183 /**
184   @brief Create a CeedVector of the specified length (does not allocate memory)
185 
186   @param ceed      Ceed object where the CeedVector will be created
187   @param length    Length of vector
188   @param[out] vec  Address of the variable where the newly created
189                      CeedVector will be stored
190 
191   @return An error code: 0 - success, otherwise - failure
192 
193   @ref User
194 **/
195 int CeedVectorCreate(Ceed ceed, CeedSize length, CeedVector *vec) {
196   int ierr;
197 
198   if (!ceed->VectorCreate) {
199     Ceed delegate;
200     ierr = CeedGetObjectDelegate(ceed, &delegate, "Vector"); CeedChk(ierr);
201 
202     if (!delegate)
203       // LCOV_EXCL_START
204       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
205                        "Backend does not support VectorCreate");
206     // LCOV_EXCL_STOP
207 
208     ierr = CeedVectorCreate(delegate, length, vec); CeedChk(ierr);
209     return CEED_ERROR_SUCCESS;
210   }
211 
212   ierr = CeedCalloc(1, vec); CeedChk(ierr);
213   (*vec)->ceed = ceed;
214   ierr = CeedReference(ceed); CeedChk(ierr);
215   (*vec)->ref_count = 1;
216   (*vec)->length = length;
217   (*vec)->state = 0;
218   ierr = ceed->VectorCreate(length, *vec); CeedChk(ierr);
219   return CEED_ERROR_SUCCESS;
220 }
221 
222 /**
223   @brief Copy the pointer to a CeedVector. Both pointers should
224            be destroyed with `CeedVectorDestroy()`;
225            Note: If `*vec_copy` is non-NULL, then it is assumed that
226            `*vec_copy` is a pointer to a CeedVector. This
227            CeedVector will be destroyed if `*vec_copy` is the only
228            reference to this CeedVector.
229 
230   @param vec            CeedVector to copy reference to
231   @param[out] vec_copy  Variable to store copied reference
232 
233   @return An error code: 0 - success, otherwise - failure
234 
235   @ref User
236 **/
237 int CeedVectorReferenceCopy(CeedVector vec, CeedVector *vec_copy) {
238   int ierr;
239 
240   ierr = CeedVectorReference(vec); CeedChk(ierr);
241   ierr = CeedVectorDestroy(vec_copy); CeedChk(ierr);
242   *vec_copy = vec;
243   return CEED_ERROR_SUCCESS;
244 }
245 
246 /**
247   @brief Set the array used by a CeedVector, freeing any previously allocated
248            array if applicable. The backend may copy values to a different
249            memtype, such as during @ref CeedOperatorApply().
250            See also @ref CeedVectorSyncArray() and @ref CeedVectorTakeArray().
251 
252   @param vec        CeedVector
253   @param mem_type   Memory type of the array being passed
254   @param copy_mode  Copy mode for the array
255   @param array      Array to be used, or NULL with @ref CEED_COPY_VALUES to have the
256                       library allocate
257 
258   @return An error code: 0 - success, otherwise - failure
259 
260   @ref User
261 **/
262 int CeedVectorSetArray(CeedVector vec, CeedMemType mem_type,
263                        CeedCopyMode copy_mode,
264                        CeedScalar *array) {
265   int ierr;
266 
267   if (!vec->SetArray)
268     // LCOV_EXCL_START
269     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
270                      "Backend does not support VectorSetArray");
271   // LCOV_EXCL_STOP
272 
273   if (vec->state % 2 == 1)
274     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
275                      "Cannot grant CeedVector array access, the "
276                      "access lock is already in use");
277 
278   if (vec->num_readers > 0)
279     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
280                      "Cannot grant CeedVector array access, a "
281                      "process has read access");
282 
283   ierr = vec->SetArray(vec, mem_type, copy_mode, array); CeedChk(ierr);
284   vec->state += 2;
285   return CEED_ERROR_SUCCESS;
286 }
287 
288 /**
289   @brief Set the CeedVector to a constant value
290 
291   @param vec        CeedVector
292   @param[in] value  Value to be used
293 
294   @return An error code: 0 - success, otherwise - failure
295 
296   @ref User
297 **/
298 int CeedVectorSetValue(CeedVector vec, CeedScalar value) {
299   int ierr;
300 
301   if (vec->state % 2 == 1)
302     // LCOV_EXCL_START
303     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
304                      "Cannot grant CeedVector array access, the "
305                      "access lock is already in use");
306   // LCOV_EXCL_STOP
307 
308   if (vec->num_readers > 0)
309     // LCOV_EXCL_START
310     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
311                      "Cannot grant CeedVector array access, a "
312                      "process has read access");
313   // LCOV_EXCL_STOP
314 
315   if (vec->SetValue) {
316     ierr = vec->SetValue(vec, value); CeedChk(ierr);
317   } else {
318     CeedScalar *array;
319     ierr = CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
320     for (int i=0; i<vec->length; i++) array[i] = value;
321     ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr);
322   }
323   vec->state += 2;
324   return CEED_ERROR_SUCCESS;
325 }
326 
327 /**
328   @brief Sync the CeedVector to a specified memtype. This function is used to
329            force synchronization of arrays set with @ref CeedVectorSetArray().
330            If the requested memtype is already synchronized, this function
331            results in a no-op.
332 
333   @param vec       CeedVector
334   @param mem_type  Memtype to be synced
335 
336   @return An error code: 0 - success, otherwise - failure
337 
338   @ref User
339 **/
340 int CeedVectorSyncArray(CeedVector vec, CeedMemType mem_type) {
341   int ierr;
342 
343   if (vec->state % 2 == 1)
344     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
345                      "Cannot sync CeedVector, the access lock is "
346                      "already in use");
347 
348   if (vec->SyncArray) {
349     ierr = vec->SyncArray(vec, mem_type); CeedChk(ierr);
350   } else {
351     const CeedScalar *array;
352     ierr = CeedVectorGetArrayRead(vec, mem_type, &array); CeedChk(ierr);
353     ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
354   }
355   return CEED_ERROR_SUCCESS;
356 }
357 
358 /**
359   @brief Take ownership of the CeedVector array set by @ref CeedVectorSetArray()
360            with @ref CEED_USE_POINTER and remove the array from the CeedVector.
361            The caller is responsible for managing and freeing the array.
362            This function will error if @ref CeedVectorSetArray() was not previously
363            called with @ref CEED_USE_POINTER for the corresponding mem_type.
364 
365   @param vec         CeedVector
366   @param mem_type    Memory type on which to take the array. If the backend
367                        uses a different memory type, this will perform a copy.
368   @param[out] array  Array on memory type mem_type, or NULL if array pointer is
369                        not required
370 
371   @return An error code: 0 - success, otherwise - failure
372 
373   @ref User
374 **/
375 int CeedVectorTakeArray(CeedVector vec, CeedMemType mem_type,
376                         CeedScalar **array) {
377   int ierr;
378 
379   if (vec->state % 2 == 1)
380     // LCOV_EXCL_START
381     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
382                      "Cannot take CeedVector array, the access "
383                      "lock is already in use");
384   // LCOV_EXCL_STOP
385   if (vec->num_readers > 0)
386     // LCOV_EXCL_START
387     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
388                      "Cannot take CeedVector array, a process "
389                      "has read access");
390   // LCOV_EXCL_STOP
391   CeedScalar *temp_array = NULL;
392   if (vec->length > 0) {
393     bool has_borrowed_array_of_type = true;
394     ierr = CeedVectorHasBorrowedArrayOfType(vec, mem_type,
395                                             &has_borrowed_array_of_type);
396     CeedChk(ierr);
397     if (!has_borrowed_array_of_type)
398       // LCOV_EXCL_START
399       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
400                        "CeedVector has no borrowed %s array, "
401                        "must set array with CeedVectorSetArray", CeedMemTypes[mem_type]);
402     // LCOV_EXCL_STOP
403 
404     bool has_valid_array = true;
405     ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
406     if (!has_valid_array)
407       // LCOV_EXCL_START
408       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
409                        "CeedVector has no valid data to take, "
410                        "must set data with CeedVectorSetValue or CeedVectorSetArray");
411     // LCOV_EXCL_STOP
412 
413     ierr = vec->TakeArray(vec, mem_type, &temp_array); CeedChk(ierr);
414   }
415   if (array) (*array) = temp_array;
416   return CEED_ERROR_SUCCESS;
417 }
418 
419 /**
420   @brief Get read/write access to a CeedVector via the specified memory type.
421            Restore access with @ref CeedVectorRestoreArray().
422 
423   @param vec         CeedVector to access
424   @param mem_type    Memory type on which to access the array. If the backend
425                        uses a different memory type, this will perform a copy.
426   @param[out] array  Array on memory type mem_type
427 
428   @note The CeedVectorGetArray* and CeedVectorRestoreArray* functions provide
429     access to array pointers in the desired memory space. Pairing get/restore
430     allows the Vector to track access, thus knowing if norms or other
431     operations may need to be recomputed.
432 
433   @return An error code: 0 - success, otherwise - failure
434 
435   @ref User
436 **/
437 int CeedVectorGetArray(CeedVector vec, CeedMemType mem_type,
438                        CeedScalar **array) {
439   int ierr;
440 
441   if (!vec->GetArray)
442     // LCOV_EXCL_START
443     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
444                      "Backend does not support GetArray");
445   // LCOV_EXCL_STOP
446 
447   if (vec->state % 2 == 1)
448     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
449                      "Cannot grant CeedVector array access, the "
450                      "access lock is already in use");
451 
452   if (vec->num_readers > 0)
453     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
454                      "Cannot grant CeedVector array access, a "
455                      "process has read access");
456 
457   bool has_valid_array = true;
458   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
459   if (!has_valid_array)
460     // LCOV_EXCL_START
461     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
462                      "CeedVector has no valid data to read, "
463                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
464   // LCOV_EXCL_STOP
465 
466   ierr = vec->GetArray(vec, mem_type, array); CeedChk(ierr);
467   vec->state++;
468   return CEED_ERROR_SUCCESS;
469 }
470 
471 /**
472   @brief Get read-only access to a CeedVector via the specified memory type.
473            Restore access with @ref CeedVectorRestoreArrayRead().
474 
475   @param vec         CeedVector to access
476   @param mem_type    Memory type on which to access the array.  If the backend
477                        uses a different memory type, this will perform a copy
478                        (possibly cached).
479   @param[out] array  Array on memory type mem_type
480 
481   @return An error code: 0 - success, otherwise - failure
482 
483   @ref User
484 **/
485 int CeedVectorGetArrayRead(CeedVector vec, CeedMemType mem_type,
486                            const CeedScalar **array) {
487   int ierr;
488 
489   if (!vec->GetArrayRead)
490     // LCOV_EXCL_START
491     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
492                      "Backend does not support GetArrayRead");
493   // LCOV_EXCL_STOP
494 
495   if (vec->state % 2 == 1)
496     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
497                      "Cannot grant CeedVector read-only array "
498                      "access, the access lock is already in use");
499 
500   if (vec->length > 0) {
501     bool has_valid_array = true;
502     ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
503     if (!has_valid_array)
504       // LCOV_EXCL_START
505       return CeedError(vec->ceed, CEED_ERROR_BACKEND,
506                        "CeedVector has no valid data to read, "
507                        "must set data with CeedVectorSetValue or CeedVectorSetArray");
508     // LCOV_EXCL_STOP
509 
510     ierr = vec->GetArrayRead(vec, mem_type, array); CeedChk(ierr);
511   } else {
512     *array = NULL;
513   }
514   vec->num_readers++;
515   return CEED_ERROR_SUCCESS;
516 }
517 
518 /**
519   @brief Get write access to a CeedVector via the specified memory type.
520            Restore access with @ref CeedVectorRestoreArray(). All old
521            values should be assumed to be invalid.
522 
523   @param vec         CeedVector to access
524   @param mem_type    Memory type on which to access the array.
525   @param[out] array  Array on memory type mem_type
526 
527   @return An error code: 0 - success, otherwise - failure
528 
529   @ref User
530 **/
531 int CeedVectorGetArrayWrite(CeedVector vec, CeedMemType mem_type,
532                             CeedScalar **array) {
533   int ierr;
534 
535   if (!vec->GetArrayWrite)
536     // LCOV_EXCL_START
537     return CeedError(vec->ceed, CEED_ERROR_UNSUPPORTED,
538                      "Backend does not support GetArrayWrite");
539   // LCOV_EXCL_STOP
540 
541   if (vec->state % 2 == 1)
542     // LCOV_EXCL_START
543     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
544                      "Cannot grant CeedVector array access, the "
545                      "access lock is already in use");
546   // LCOV_EXCL_STOP
547 
548   if (vec->num_readers > 0)
549     // LCOV_EXCL_START
550     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
551                      "Cannot grant CeedVector array access, a "
552                      "process has read access");
553   // LCOV_EXCL_STOP
554 
555   ierr = vec->GetArrayWrite(vec, mem_type, array); CeedChk(ierr);
556   vec->state++;
557   return CEED_ERROR_SUCCESS;
558 }
559 
560 /**
561   @brief Restore an array obtained using @ref CeedVectorGetArray()
562            or @ref CeedVectorGetArrayWrite()
563 
564   @param vec    CeedVector to restore
565   @param array  Array of vector data
566 
567   @return An error code: 0 - success, otherwise - failure
568 
569   @ref User
570 **/
571 int CeedVectorRestoreArray(CeedVector vec, CeedScalar **array) {
572   int ierr;
573 
574   if (vec->state % 2 != 1)
575     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
576                      "Cannot restore CeedVector array access, "
577                      "access was not granted");
578   if (vec->RestoreArray) {
579     ierr = vec->RestoreArray(vec); CeedChk(ierr);
580   }
581   *array = NULL;
582   vec->state++;
583   return CEED_ERROR_SUCCESS;
584 }
585 
586 /**
587   @brief Restore an array obtained using @ref CeedVectorGetArrayRead()
588 
589   @param vec    CeedVector to restore
590   @param array  Array of vector data
591 
592   @return An error code: 0 - success, otherwise - failure
593 
594   @ref User
595 **/
596 int CeedVectorRestoreArrayRead(CeedVector vec, const CeedScalar **array) {
597   int ierr;
598 
599   if (vec->num_readers == 0)
600     // LCOV_EXCL_START
601     return CeedError(vec->ceed, CEED_ERROR_ACCESS,
602                      "Cannot restore CeedVector array read access, "
603                      "access was not granted");
604   // LCOV_EXCL_STOP
605 
606   if (vec->RestoreArrayRead) {
607     ierr = vec->RestoreArrayRead(vec); CeedChk(ierr);
608   }
609   *array = NULL;
610   vec->num_readers--;
611   return CEED_ERROR_SUCCESS;
612 }
613 
614 /**
615   @brief Get the norm of a CeedVector.
616 
617   Note: This operation is local to the CeedVector. This function will likely
618           not provide the desired results for the norm of the libCEED portion
619           of a parallel vector or a CeedVector with duplicated or hanging nodes.
620 
621   @param vec        CeedVector to retrieve maximum value
622   @param norm_type  Norm type @ref CEED_NORM_1, @ref CEED_NORM_2, or @ref CEED_NORM_MAX
623   @param[out] norm  Variable to store norm value
624 
625   @return An error code: 0 - success, otherwise - failure
626 
627   @ref User
628 **/
629 int CeedVectorNorm(CeedVector vec, CeedNormType norm_type, CeedScalar *norm) {
630   int ierr;
631 
632   bool has_valid_array = true;
633   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
634   if (!has_valid_array)
635     // LCOV_EXCL_START
636     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
637                      "CeedVector has no valid data to compute norm, "
638                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
639   // LCOV_EXCL_STOP
640 
641   // Backend impl for GPU, if added
642   if (vec->Norm) {
643     ierr = vec->Norm(vec, norm_type, norm); CeedChk(ierr);
644     return CEED_ERROR_SUCCESS;
645   }
646 
647   const CeedScalar *array;
648   ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
649 
650   *norm = 0.;
651   switch (norm_type) {
652   case CEED_NORM_1:
653     for (int i=0; i<vec->length; i++) {
654       *norm += fabs(array[i]);
655     }
656     break;
657   case CEED_NORM_2:
658     for (int i=0; i<vec->length; i++) {
659       *norm += fabs(array[i])*fabs(array[i]);
660     }
661     break;
662   case CEED_NORM_MAX:
663     for (int i=0; i<vec->length; i++) {
664       const CeedScalar abs_v_i = fabs(array[i]);
665       *norm = *norm > abs_v_i ? *norm : abs_v_i;
666     }
667   }
668   if (norm_type == CEED_NORM_2)
669     *norm = sqrt(*norm);
670 
671   ierr = CeedVectorRestoreArrayRead(vec, &array); CeedChk(ierr);
672   return CEED_ERROR_SUCCESS;
673 }
674 
675 /**
676   @brief Compute x = alpha x
677 
678   @param[in,out] x  vector for scaling
679   @param[in] alpha  scaling factor
680 
681   @return An error code: 0 - success, otherwise - failure
682 
683   @ref User
684 **/
685 int CeedVectorScale(CeedVector x, CeedScalar alpha) {
686   int ierr;
687   CeedScalar *x_array = NULL;
688   CeedSize n_x;
689 
690   bool has_valid_array = true;
691   ierr = CeedVectorHasValidArray(x, &has_valid_array); CeedChk(ierr);
692   if (!has_valid_array)
693     // LCOV_EXCL_START
694     return CeedError(x->ceed, CEED_ERROR_BACKEND,
695                      "CeedVector has no valid data to scale, "
696                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
697   // LCOV_EXCL_STOP
698 
699   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
700 
701   // Backend implementation
702   if (x->Scale)
703     return x->Scale(x, alpha);
704 
705   // Default implementation
706   ierr = CeedVectorGetArrayWrite(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
707   for (CeedInt i=0; i<n_x; i++)
708     x_array[i] *= alpha;
709   ierr = CeedVectorRestoreArray(x, &x_array); CeedChk(ierr);
710 
711   return CEED_ERROR_SUCCESS;
712 }
713 
714 /**
715   @brief Compute y = alpha x + y
716 
717   @param[in,out] y  target vector for sum
718   @param[in] alpha  scaling factor
719   @param[in] x      second vector, must be different than y
720 
721   @return An error code: 0 - success, otherwise - failure
722 
723   @ref User
724 **/
725 int CeedVectorAXPY(CeedVector y, CeedScalar alpha, CeedVector x) {
726   int ierr;
727   CeedScalar *y_array = NULL;
728   CeedScalar const *x_array = NULL;
729   CeedSize n_x, n_y;
730 
731   ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr);
732   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
733   if (n_x != n_y)
734     // LCOV_EXCL_START
735     return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED,
736                      "Cannot add vector of different lengths");
737   // LCOV_EXCL_STOP
738   if (x == y)
739     // LCOV_EXCL_START
740     return CeedError(y->ceed, CEED_ERROR_UNSUPPORTED,
741                      "Cannot use same vector for x and y in CeedVectorAXPY");
742   // LCOV_EXCL_STOP
743 
744   bool has_valid_array_x = true, has_valid_array_y = true;
745   ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr);
746   if (!has_valid_array_x)
747     // LCOV_EXCL_START
748     return CeedError(x->ceed, CEED_ERROR_BACKEND,
749                      "CeedVector x has no valid data, "
750                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
751   // LCOV_EXCL_STOP
752   ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr);
753   if (!has_valid_array_y)
754     // LCOV_EXCL_START
755     return CeedError(y->ceed, CEED_ERROR_BACKEND,
756                      "CeedVector y has no valid data, "
757                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
758   // LCOV_EXCL_STOP
759 
760   Ceed ceed_parent_x, ceed_parent_y;
761   ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr);
762   ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr);
763   if (ceed_parent_x != ceed_parent_y)
764     // LCOV_EXCL_START
765     return CeedError(y->ceed, CEED_ERROR_INCOMPATIBLE,
766                      "Vectors x and y must be created by the same Ceed context");
767   // LCOV_EXCL_STOP
768 
769   // Backend implementation
770   if (y->AXPY) {
771     ierr = y->AXPY(y, alpha, x); CeedChk(ierr);
772     return CEED_ERROR_SUCCESS;
773   }
774 
775   // Default implementation
776   ierr = CeedVectorGetArrayWrite(y, CEED_MEM_HOST, &y_array); CeedChk(ierr);
777   ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
778 
779   assert(x_array); assert(y_array);
780 
781   for (CeedInt i=0; i<n_y; i++)
782     y_array[i] += alpha * x_array[i];
783 
784   ierr = CeedVectorRestoreArray(y, &y_array); CeedChk(ierr);
785   ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr);
786 
787   return CEED_ERROR_SUCCESS;
788 }
789 
790 /**
791   @brief Compute the pointwise multiplication w = x .* y. Any
792            subset of x, y, and w may be the same vector.
793 
794   @param[out] w  target vector for the product
795   @param[in] x   first vector for product
796   @param[in] y   second vector for the product
797 
798   @return An error code: 0 - success, otherwise - failure
799 
800   @ ref User
801 **/
802 int CeedVectorPointwiseMult(CeedVector w, CeedVector x, CeedVector y) {
803   int ierr;
804   CeedScalar *w_array = NULL;
805   CeedScalar const *x_array = NULL, *y_array = NULL;
806   CeedSize n_w, n_x, n_y;
807 
808   ierr = CeedVectorGetLength(w, &n_w); CeedChk(ierr);
809   ierr = CeedVectorGetLength(x, &n_x); CeedChk(ierr);
810   ierr = CeedVectorGetLength(y, &n_y); CeedChk(ierr);
811   if (n_w != n_x || n_w != n_y)
812     // LCOV_EXCL_START
813     return CeedError(w->ceed, CEED_ERROR_UNSUPPORTED,
814                      "Cannot multiply vectors of different lengths");
815   // LCOV_EXCL_STOP
816 
817   Ceed ceed_parent_w, ceed_parent_x, ceed_parent_y;
818   ierr = CeedGetParent(w->ceed, &ceed_parent_w); CeedChk(ierr);
819   ierr = CeedGetParent(x->ceed, &ceed_parent_x); CeedChk(ierr);
820   ierr = CeedGetParent(y->ceed, &ceed_parent_y); CeedChk(ierr);
821   if ((ceed_parent_w != ceed_parent_x) ||
822       (ceed_parent_w != ceed_parent_y))
823     // LCOV_EXCL_START
824     return CeedError(w->ceed, CEED_ERROR_INCOMPATIBLE,
825                      "Vectors w, x, and y must be created by the same Ceed context");
826   // LCOV_EXCL_STOP
827 
828   bool has_valid_array_x = true, has_valid_array_y = true;
829   ierr = CeedVectorHasValidArray(x, &has_valid_array_x); CeedChk(ierr);
830   if (!has_valid_array_x)
831     // LCOV_EXCL_START
832     return CeedError(x->ceed, CEED_ERROR_BACKEND,
833                      "CeedVector x has no valid data, "
834                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
835   // LCOV_EXCL_STOP
836   ierr = CeedVectorHasValidArray(y, &has_valid_array_y); CeedChk(ierr);
837   if (!has_valid_array_y)
838     // LCOV_EXCL_START
839     return CeedError(y->ceed, CEED_ERROR_BACKEND,
840                      "CeedVector y has no valid data, "
841                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
842   // LCOV_EXCL_STOP
843 
844   // Backend implementation
845   if (w->PointwiseMult) {
846     ierr = w->PointwiseMult(w, x, y); CeedChk(ierr);
847     return CEED_ERROR_SUCCESS;
848   }
849 
850   // Default implementation
851   ierr = CeedVectorGetArrayWrite(w, CEED_MEM_HOST, &w_array); CeedChk(ierr);
852   if (x != w) {
853     ierr = CeedVectorGetArrayRead(x, CEED_MEM_HOST, &x_array); CeedChk(ierr);
854   } else {
855     x_array = w_array;
856   }
857   if (y != w && y != x) {
858     ierr = CeedVectorGetArrayRead(y, CEED_MEM_HOST, &y_array); CeedChk(ierr);
859   } else if (y != x) {
860     y_array = w_array;
861   } else {
862     y_array = x_array;
863   }
864 
865   assert(w_array); assert(x_array); assert(y_array);
866 
867   for (CeedInt i=0; i<n_w; i++)
868     w_array[i] = x_array[i] * y_array[i];
869 
870   if (y != w && y != x) {
871     ierr = CeedVectorRestoreArrayRead(y, &y_array); CeedChk(ierr);
872   }
873   if (x != w) {
874     ierr = CeedVectorRestoreArrayRead(x, &x_array); CeedChk(ierr);
875   }
876   ierr = CeedVectorRestoreArray(w, &w_array); CeedChk(ierr);
877   return CEED_ERROR_SUCCESS;
878 }
879 
880 /**
881   @brief Take the reciprocal of a CeedVector.
882 
883   @param vec  CeedVector to take reciprocal
884 
885   @return An error code: 0 - success, otherwise - failure
886 
887   @ref User
888 **/
889 int CeedVectorReciprocal(CeedVector vec) {
890   int ierr;
891 
892   bool has_valid_array = true;
893   ierr = CeedVectorHasValidArray(vec, &has_valid_array); CeedChk(ierr);
894   if (!has_valid_array)
895     // LCOV_EXCL_START
896     return CeedError(vec->ceed, CEED_ERROR_BACKEND,
897                      "CeedVector has no valid data to compute reciprocal, "
898                      "must set data with CeedVectorSetValue or CeedVectorSetArray");
899   // LCOV_EXCL_STOP
900 
901   // Check if vector data set
902   if (!vec->state)
903     // LCOV_EXCL_START
904     return CeedError(vec->ceed, CEED_ERROR_INCOMPLETE,
905                      "CeedVector must have data set to take reciprocal");
906   // LCOV_EXCL_STOP
907 
908   // Backend impl for GPU, if added
909   if (vec->Reciprocal) {
910     ierr = vec->Reciprocal(vec); CeedChk(ierr);
911     return CEED_ERROR_SUCCESS;
912   }
913 
914   CeedSize len;
915   ierr = CeedVectorGetLength(vec, &len); CeedChk(ierr);
916   CeedScalar *array;
917   ierr = CeedVectorGetArrayWrite(vec, CEED_MEM_HOST, &array); CeedChk(ierr);
918   for (CeedInt i=0; i<len; i++)
919     if (fabs(array[i]) > CEED_EPSILON)
920       array[i] = 1./array[i];
921 
922   ierr = CeedVectorRestoreArray(vec, &array); CeedChk(ierr);
923   return CEED_ERROR_SUCCESS;
924 }
925 
926 /**
927   @brief View a CeedVector
928 
929   @param[in] vec     CeedVector to view
930   @param[in] fp_fmt  Printing format
931   @param[in] stream  Filestream to write to
932 
933   @return An error code: 0 - success, otherwise - failure
934 
935   @ref User
936 **/
937 int CeedVectorView(CeedVector vec, const char *fp_fmt, FILE *stream) {
938   const CeedScalar *x;
939 
940   int ierr = CeedVectorGetArrayRead(vec, CEED_MEM_HOST, &x); CeedChk(ierr);
941 
942   char fmt[1024];
943   fprintf(stream, "CeedVector length %ld\n", (long)vec->length);
944   snprintf(fmt, sizeof fmt, "  %s\n", fp_fmt ? fp_fmt : "%g");
945   for (CeedInt i=0; i<vec->length; i++)
946     fprintf(stream, fmt, x[i]);
947 
948   ierr = CeedVectorRestoreArrayRead(vec, &x); CeedChk(ierr);
949   return CEED_ERROR_SUCCESS;
950 }
951 
952 /**
953   @brief Get the Ceed associated with a CeedVector
954 
955   @param vec        CeedVector to retrieve state
956   @param[out] ceed  Variable to store ceed
957 
958   @return An error code: 0 - success, otherwise - failure
959 
960   @ref Advanced
961 **/
962 int CeedVectorGetCeed(CeedVector vec, Ceed *ceed) {
963   *ceed = vec->ceed;
964   return CEED_ERROR_SUCCESS;
965 }
966 
967 /**
968   @brief Get the length of a CeedVector
969 
970   @param vec          CeedVector to retrieve length
971   @param[out] length  Variable to store length
972 
973   @return An error code: 0 - success, otherwise - failure
974 
975   @ref User
976 **/
977 int CeedVectorGetLength(CeedVector vec, CeedSize *length) {
978   *length = vec->length;
979   return CEED_ERROR_SUCCESS;
980 }
981 
982 /**
983   @brief Destroy a CeedVector
984 
985   @param vec  CeedVector to destroy
986 
987   @return An error code: 0 - success, otherwise - failure
988 
989   @ref User
990 **/
991 int CeedVectorDestroy(CeedVector *vec) {
992   int ierr;
993 
994   if (!*vec || --(*vec)->ref_count > 0) return CEED_ERROR_SUCCESS;
995 
996   if (((*vec)->state % 2) == 1)
997     return CeedError((*vec)->ceed, CEED_ERROR_ACCESS,
998                      "Cannot destroy CeedVector, the writable access "
999                      "lock is in use");
1000 
1001   if ((*vec)->num_readers > 0)
1002     // LCOV_EXCL_START
1003     return CeedError((*vec)->ceed, CEED_ERROR_ACCESS,
1004                      "Cannot destroy CeedVector, a process has "
1005                      "read access");
1006   // LCOV_EXCL_STOP
1007 
1008   if ((*vec)->Destroy) {
1009     ierr = (*vec)->Destroy(*vec); CeedChk(ierr);
1010   }
1011 
1012   ierr = CeedDestroy(&(*vec)->ceed); CeedChk(ierr);
1013   ierr = CeedFree(vec); CeedChk(ierr);
1014   return CEED_ERROR_SUCCESS;
1015 }
1016 
1017 /// @}
1018