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