@@ -138,6 +138,43 @@ int CeedRegisterImpl(const char *prefix, int (*init)(const char *, Ceed), unsign
138138 return CEED_ERROR_SUCCESS ;
139139}
140140
141+ /**
142+ @brief Create a work vector space for a `ceed`
143+
144+ @param[in,out] ceed `Ceed` to create work vector space for
145+
146+ @return An error code: 0 - success, otherwise - failure
147+
148+ @ref Developer
149+ **/
150+ static int CeedWorkVectorsCreate (Ceed ceed ) {
151+ CeedCall (CeedCalloc (1 , & ceed -> work_vectors ));
152+ return CEED_ERROR_SUCCESS ;
153+ }
154+
155+ /**
156+ @brief Destroy a work vector space for a `ceed`
157+
158+ @param[in,out] ceed `Ceed` to destroy work vector space for
159+
160+ @return An error code: 0 - success, otherwise - failure
161+
162+ @ref Developer
163+ **/
164+ static int CeedWorkVectorsDestroy (Ceed ceed ) {
165+ if (!ceed -> work_vectors ) return CEED_ERROR_SUCCESS ;
166+ for (CeedSize i = 0 ; i < ceed -> work_vectors -> num_vecs ; i ++ ) {
167+ CeedCheck (!ceed -> work_vectors -> is_in_use [i ], ceed , CEED_ERROR_ACCESS , "Work vector %" CeedSize_FMT " checked out but not returned" );
168+ ceed -> ref_count += 2 ; // Note: increase ref_count to prevent Ceed destructor from triggering again
169+ CeedCall (CeedVectorDestroy (& ceed -> work_vectors -> vecs [i ]));
170+ ceed -> ref_count -= 1 ; // Note: restore ref_count
171+ }
172+ CeedCall (CeedFree (& ceed -> work_vectors -> is_in_use ));
173+ CeedCall (CeedFree (& ceed -> work_vectors -> vecs ));
174+ CeedCall (CeedFree (& ceed -> work_vectors ));
175+ return CEED_ERROR_SUCCESS ;
176+ }
177+
141178/// @}
142179
143180/// ----------------------------------------------------------------------------
@@ -751,6 +788,81 @@ int CeedReference(Ceed ceed) {
751788 return CEED_ERROR_SUCCESS ;
752789}
753790
791+ /**
792+ @brief Get a `CeedVector` for scratch work from a `Ceed` context.
793+
794+ Note: This vector must be restored with @ref CeedRestoreWorkVector().
795+
796+ @param[in] ceed `Ceed` context
797+ @param[in] len Minimum length of work vector
798+ @param[out] vec Address of the variable where `CeedVector` will be stored
799+
800+ @return An error code: 0 - success, otherwise - failure
801+
802+ @ref Backend
803+ **/
804+ int CeedGetWorkVector (Ceed ceed , CeedSize len , CeedVector * vec ) {
805+ CeedInt i = 0 ;
806+
807+ if (!ceed -> work_vectors ) CeedCall (CeedWorkVectorsCreate (ceed ));
808+
809+ // Search for big enough work vector
810+ for (i = 0 ; i < ceed -> work_vectors -> num_vecs ; i ++ ) {
811+ if (!ceed -> work_vectors -> is_in_use [i ]) {
812+ CeedSize work_len ;
813+
814+ CeedCall (CeedVectorGetLength (ceed -> work_vectors -> vecs [i ], & work_len ));
815+ if (work_len >= len ) break ;
816+ }
817+ }
818+ // Long enough vector was not found
819+ if (i == ceed -> work_vectors -> num_vecs ) {
820+ if (ceed -> work_vectors -> max_vecs == 0 ) {
821+ ceed -> work_vectors -> max_vecs = 1 ;
822+ CeedCall (CeedCalloc (ceed -> work_vectors -> max_vecs , & ceed -> work_vectors -> vecs ));
823+ CeedCall (CeedCalloc (ceed -> work_vectors -> max_vecs , & ceed -> work_vectors -> is_in_use ));
824+ } else if (ceed -> work_vectors -> max_vecs == i ) {
825+ ceed -> work_vectors -> max_vecs *= 2 ;
826+ CeedCall (CeedRealloc (ceed -> work_vectors -> max_vecs , & ceed -> work_vectors -> vecs ));
827+ CeedCall (CeedRealloc (ceed -> work_vectors -> max_vecs , & ceed -> work_vectors -> is_in_use ));
828+ }
829+ ceed -> work_vectors -> num_vecs ++ ;
830+ CeedCallBackend (CeedVectorCreate (ceed , len , & ceed -> work_vectors -> vecs [i ]));
831+ ceed -> ref_count -- ; // Note: ref_count manipulation to prevent a ref-loop
832+ }
833+ // Return pointer to work vector
834+ ceed -> work_vectors -> is_in_use [i ] = true;
835+ * vec = NULL ;
836+ CeedCall (CeedVectorReferenceCopy (ceed -> work_vectors -> vecs [i ], vec ));
837+ ceed -> ref_count ++ ; // Note: bump ref_count to account for external access
838+ return CEED_ERROR_SUCCESS ;
839+ }
840+
841+ /**
842+ @brief Restore a `CeedVector` for scratch work from a `Ceed` context from @ref CeedGetWorkVector()
843+
844+ @param[in] ceed `Ceed` context
845+ @param[out] vec `CeedVector` to restore
846+
847+ @return An error code: 0 - success, otherwise - failure
848+
849+ @ref Backend
850+ **/
851+ int CeedRestoreWorkVector (Ceed ceed , CeedVector * vec ) {
852+ for (CeedInt i = 0 ; i < ceed -> work_vectors -> num_vecs ; i ++ ) {
853+ if (* vec == ceed -> work_vectors -> vecs [i ]) {
854+ CeedCheck (ceed -> work_vectors -> is_in_use [i ], ceed , CEED_ERROR_ACCESS , "Work vector %" CeedSize_FMT " was not checked out but is being returned" );
855+ CeedCall (CeedVectorDestroy (vec ));
856+ ceed -> work_vectors -> is_in_use [i ] = false;
857+ ceed -> ref_count -- ; // Note: reduce ref_count again to prevent a ref-loop
858+ return CEED_ERROR_SUCCESS ;
859+ }
860+ }
861+ // LCOV_EXCL_START
862+ return CeedError (ceed , CEED_ERROR_MAJOR , "vec was not checked out via CeedGetWorkVector()" );
863+ // LCOV_EXCL_STOP
864+ }
865+
754866/// @}
755867
756868/// ----------------------------------------------------------------------------
@@ -1200,6 +1312,7 @@ int CeedDestroy(Ceed *ceed) {
12001312 CeedCall (CeedFree (& (* ceed )-> resource ));
12011313 CeedCall (CeedDestroy (& (* ceed )-> op_fallback_ceed ));
12021314 CeedCall (CeedFree (& (* ceed )-> op_fallback_resource ));
1315+ CeedCall (CeedWorkVectorsDestroy (* ceed ));
12031316 CeedCall (CeedFree (ceed ));
12041317 return CEED_ERROR_SUCCESS ;
12051318}
0 commit comments