xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-elemrestriction.c (revision 8795c9458136fc8cad6e4d699e4c8f3c99be02e2) !
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 
20 /// @file
21 /// Implementation of public CeedElemRestriction interfaces
22 ///
23 /// @addtogroup CeedElemRestriction
24 /// @{
25 
26 /**
27   @brief Create a CeedElemRestriction
28 
29   @param ceed       A Ceed object where the CeedElemRestriction will be created
30   @param nelem      Number of elements described in the @a indices array
31   @param elemsize   Size (number of "nodes") per element
32   @param nnodes     The number of nodes in the L-vector. The input CeedVector
33                       to which the restriction will be applied is of size
34                       @a nnodes * @a ncomp. This size may include data
35                       used by other CeedElemRestriction objects describing
36                       different types of elements.
37   @param ncomp      Number of field components per interpolation node
38   @param mtype      Memory type of the @a indices array, see CeedMemType
39   @param cmode      Copy mode for the @a indices array, see CeedCopyMode
40   @param indices    Array of shape [@a nelem, @a elemsize]. Row i holds the
41                       ordered list of the indices (into the input CeedVector)
42                       for the unknowns corresponding to element i, where
43                       0 <= i < @a nelements. All indices must be in the range
44                       [0, @a nnodes].
45   @param[out] rstr  Address of the variable where the newly created
46                       CeedElemRestriction will be stored
47 
48   @return An error code: 0 - success, otherwise - failure
49 
50   @ref Basic
51 **/
52 int CeedElemRestrictionCreate(Ceed ceed, CeedInt nelem, CeedInt elemsize,
53                               CeedInt nnodes, CeedInt ncomp, CeedMemType mtype,
54                               CeedCopyMode cmode, const CeedInt *indices,
55                               CeedElemRestriction *rstr) {
56   int ierr;
57 
58   if (!ceed->ElemRestrictionCreate) {
59     Ceed delegate;
60     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
61     CeedChk(ierr);
62 
63     if (!delegate)
64       return CeedError(ceed, 1, "Backend does not support ElemRestrictionCreate");
65 
66     ierr = CeedElemRestrictionCreate(delegate, nelem, elemsize,
67                                      nnodes, ncomp, mtype, cmode,
68                                      indices, rstr); CeedChk(ierr);
69     return 0;
70   }
71 
72   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
73   (*rstr)->ceed = ceed;
74   ceed->refcount++;
75   (*rstr)->refcount = 1;
76   (*rstr)->nelem = nelem;
77   (*rstr)->elemsize = elemsize;
78   (*rstr)->nnodes = nnodes;
79   (*rstr)->ncomp = ncomp;
80   (*rstr)->nblk = nelem;
81   (*rstr)->blksize = 1;
82   ierr = ceed->ElemRestrictionCreate(mtype, cmode, indices, *rstr); CeedChk(ierr);
83   return 0;
84 }
85 
86 /**
87   @brief Create an identity CeedElemRestriction
88 
89   @param ceed       A Ceed object where the CeedElemRestriction will be created
90   @param nelem      Number of elements described in the @a indices array
91   @param elemsize   Size (number of "nodes") per element
92   @param nnodes     The number of nodes in the L-vector. The input CeedVector
93                       to which the restriction will be applied is of size
94                       @a nnodes * @a ncomp. This size may include data
95                       used by other CeedElemRestriction objects describing
96                       different types of elements.
97   @param ncomp      Number of field components per interpolation node
98   @param rstr       Address of the variable where the newly created
99                       CeedElemRestriction will be stored
100 
101   @return An error code: 0 - success, otherwise - failure
102 
103   @ref Basic
104 **/
105 int CeedElemRestrictionCreateIdentity(Ceed ceed, CeedInt nelem,
106                                       CeedInt elemsize,
107                                       CeedInt nnodes, CeedInt ncomp, CeedElemRestriction *rstr) {
108   int ierr;
109 
110   if (!ceed->ElemRestrictionCreate) {
111     Ceed delegate;
112     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
113     CeedChk(ierr);
114 
115     if (!delegate)
116       return CeedError(ceed, 1,
117                        "Backend does not support ElemRestrictionCreate");
118 
119     ierr = CeedElemRestrictionCreateIdentity(delegate, nelem, elemsize,
120            nnodes, ncomp, rstr); CeedChk(ierr);
121     return 0;
122   }
123 
124   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
125   (*rstr)->ceed = ceed;
126   ceed->refcount++;
127   (*rstr)->refcount = 1;
128   (*rstr)->nelem = nelem;
129   (*rstr)->elemsize = elemsize;
130   (*rstr)->nnodes = nnodes;
131   (*rstr)->ncomp = ncomp;
132   (*rstr)->nblk = nelem;
133   (*rstr)->blksize = 1;
134   ierr = ceed->ElemRestrictionCreate(CEED_MEM_HOST, CEED_OWN_POINTER, NULL,
135                                      *rstr);
136   CeedChk(ierr);
137   return 0;
138 }
139 
140 /**
141   @brief Permute and pad indices for a blocked restriction
142 
143   @param indices    Array of shape [@a nelem, @a elemsize]. Row i holds the
144                       ordered list of the indices (into the input CeedVector)
145                       for the unknowns corresponding to element i, where
146                       0 <= i < @a nelements. All indices must be in the range
147                       [0, @a nnodes).
148   @param blkindices Array of permuted and padded indices of
149                       shape [@a nblk, @a elemsize, @a blksize].
150   @param nblk       Number of blocks
151   @param nelem      Number of elements
152   @param blksize    Number of elements in a block
153   @param elemsize   Size of each element
154 
155   @return An error code: 0 - success, otherwise - failure
156 
157   @ref Utility
158 **/
159 int CeedPermutePadIndices(const CeedInt *indices, CeedInt *blkindices,
160                           CeedInt nblk, CeedInt nelem,
161                           CeedInt blksize, CeedInt elemsize) {
162   for (CeedInt e = 0; e < nblk*blksize; e+=blksize)
163     for (int j = 0; j < blksize; j++)
164       for (int k = 0; k < elemsize; k++)
165         blkindices[e*elemsize + k*blksize + j]
166           = indices[CeedIntMin(e+j,nelem-1)*elemsize + k];
167   return 0;
168 }
169 
170 /**
171   @brief Create a blocked CeedElemRestriction, typically only called by backends
172 
173   @param ceed       A Ceed object where the CeedElemRestriction will be created.
174   @param nelem      Number of elements described in the @a indices array.
175   @param elemsize   Size (number of unknowns) per element
176   @param blksize    Number of elements in a block
177   @param nnodes     The number of nodes in the L-vector. The input CeedVector
178                       to which the restriction will be applied is of size
179                       @a nnodes * @a ncomp. This size may include data
180                       used by other CeedElemRestriction objects describing
181                       different types of elements.
182   @param ncomp      Number of components stored at each node
183   @param mtype      Memory type of the @a indices array, see CeedMemType
184   @param cmode      Copy mode for the @a indices array, see CeedCopyMode
185   @param indices    Array of shape [@a nelem, @a elemsize]. Row i holds the
186                       ordered list of the indices (into the input CeedVector)
187                       for the unknowns corresponding to element i, where
188                       0 <= i < @a nelements. All indices must be in the range
189                       [0, @a nnodes). The backend will permute and pad this
190                       array to the desired ordering for the blocksize, which is
191                       typically given by the backend. The default reordering is
192                       to interlace elements.
193   @param rstr       Address of the variable where the newly created
194                       CeedElemRestriction will be stored
195 
196   @return An error code: 0 - success, otherwise - failure
197 
198   @ref Advanced
199  **/
200 int CeedElemRestrictionCreateBlocked(Ceed ceed, CeedInt nelem, CeedInt elemsize,
201                                      CeedInt blksize, CeedInt nnodes,
202                                      CeedInt ncomp, CeedMemType mtype,
203                                      CeedCopyMode cmode, const CeedInt *indices,
204                                      CeedElemRestriction *rstr) {
205   int ierr;
206   CeedInt *blkindices;
207   CeedInt nblk = (nelem / blksize) + !!(nelem % blksize);
208 
209   if (!ceed->ElemRestrictionCreateBlocked) {
210     Ceed delegate;
211     ierr = CeedGetObjectDelegate(ceed, &delegate, "ElemRestriction");
212     CeedChk(ierr);
213 
214     if (!delegate)
215       return CeedError(ceed, 1,
216                        "Backend does not support ElemRestrictionCreateBlocked");
217 
218     ierr = CeedElemRestrictionCreateBlocked(delegate, nelem, elemsize,
219                                             blksize, nnodes, ncomp, mtype, cmode,
220                                             indices, rstr); CeedChk(ierr);
221     return 0;
222   }
223 
224   ierr = CeedCalloc(1, rstr); CeedChk(ierr);
225 
226   if (indices) {
227     ierr = CeedCalloc(nblk*blksize*elemsize, &blkindices); CeedChk(ierr);
228     ierr = CeedPermutePadIndices(indices, blkindices, nblk, nelem, blksize,
229                                  elemsize);
230     CeedChk(ierr);
231   } else {
232     blkindices = NULL;
233   }
234 
235   (*rstr)->ceed = ceed;
236   ceed->refcount++;
237   (*rstr)->refcount = 1;
238   (*rstr)->nelem = nelem;
239   (*rstr)->elemsize = elemsize;
240   (*rstr)->nnodes = nnodes;
241   (*rstr)->ncomp = ncomp;
242   (*rstr)->nblk = nblk;
243   (*rstr)->blksize = blksize;
244   ierr = ceed->ElemRestrictionCreateBlocked(CEED_MEM_HOST, CEED_OWN_POINTER,
245          (const CeedInt *) blkindices, *rstr);
246   CeedChk(ierr);
247 
248   if (cmode == CEED_OWN_POINTER)
249     ierr = CeedFree(&indices); CeedChk(ierr);
250 
251   return 0;
252 }
253 
254 /**
255   @brief Create CeedVectors associated with a CeedElemRestriction
256 
257   @param rstr  CeedElemRestriction
258   @param lvec  The address of the L-vector to be created, or NULL
259   @param evec  The address of the E-vector to be created, or NULL
260 
261   @return An error code: 0 - success, otherwise - failure
262 
263   @ref Advanced
264 **/
265 int CeedElemRestrictionCreateVector(CeedElemRestriction rstr, CeedVector *lvec,
266                                     CeedVector *evec) {
267   int ierr;
268   CeedInt n, m;
269   m = rstr->nnodes * rstr->ncomp;
270   n = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
271   if (lvec) {
272     ierr = CeedVectorCreate(rstr->ceed, m, lvec); CeedChk(ierr);
273   }
274   if (evec) {
275     ierr = CeedVectorCreate(rstr->ceed, n, evec); CeedChk(ierr);
276   }
277   return 0;
278 }
279 
280 /**
281   @brief Restrict an L-vector to an E-vector or apply transpose
282 
283   @param rstr    CeedElemRestriction
284   @param tmode   Apply restriction or transpose
285   @param lmode   Ordering of the ncomp components
286   @param u       Input vector (of size @a nnodes * @a ncomp when
287                    tmode=CEED_NOTRANSPOSE)
288   @param v       Output vector (of size @a nelem * @a elemsize when
289                    tmode=CEED_NOTRANSPOSE)
290   @param request Request or CEED_REQUEST_IMMEDIATE
291 
292   @return An error code: 0 - success, otherwise - failure
293 
294   @ref Advanced
295 **/
296 int CeedElemRestrictionApply(CeedElemRestriction rstr, CeedTransposeMode tmode,
297                              CeedTransposeMode lmode,
298                              CeedVector u, CeedVector v, CeedRequest *request) {
299   CeedInt m,n;
300   int ierr;
301 
302   if (tmode == CEED_NOTRANSPOSE) {
303     m = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
304     n = rstr->nnodes * rstr->ncomp;
305   } else {
306     m = rstr->nnodes * rstr->ncomp;
307     n = rstr->nblk * rstr->blksize * rstr->elemsize * rstr->ncomp;
308   }
309   if (n != u->length)
310     return CeedError(rstr->ceed, 2,
311                      "Input vector size %d not compatible with element restriction (%d, %d)",
312                      u->length, m, n);
313   if (m != v->length)
314     return CeedError(rstr->ceed, 2,
315                      "Output vector size %d not compatible with element restriction (%d, %d)",
316                      v->length, m, n);
317   ierr = rstr->Apply(rstr, tmode, lmode, u, v, request); CeedChk(ierr);
318 
319   return 0;
320 }
321 
322 /**
323   @brief Restrict an L-vector to a block of an E-vector or apply transpose
324 
325   @param rstr    CeedElemRestriction
326   @param block   Block number to restrict to/from, i.e. block=0 will handle
327                  elements [0 : blksize] and block=3 will handle elements
328                  [3*blksize : 4*blksize]
329   @param tmode   Apply restriction or transpose
330   @param lmode   Ordering of the ncomp components
331   @param u       Input vector (of size @a nnodes * @a ncomp when
332                    tmode=CEED_NOTRANSPOSE)
333   @param v       Output vector (of size @a nelem * @a elemsize when
334                    tmode=CEED_NOTRANSPOSE)
335   @param request Request or CEED_REQUEST_IMMEDIATE
336 
337   @return An error code: 0 - success, otherwise - failure
338 
339   @ref Advanced
340 **/
341 int CeedElemRestrictionApplyBlock(CeedElemRestriction rstr, CeedInt block,
342                                   CeedTransposeMode tmode,
343                                   CeedTransposeMode lmode,
344                                   CeedVector u, CeedVector v,
345                                   CeedRequest *request) {
346   CeedInt m,n;
347   int ierr;
348 
349   if (tmode == CEED_NOTRANSPOSE) {
350     m = rstr->blksize * rstr->elemsize * rstr->ncomp;
351     n = rstr->nnodes * rstr->ncomp;
352   } else {
353     m = rstr->nnodes * rstr->ncomp;
354     n = rstr->blksize * rstr->elemsize * rstr->ncomp;
355   }
356   if (n != u->length)
357     return CeedError(rstr->ceed, 2,
358                      "Input vector size %d not compatible with element restriction (%d, %d)",
359                      u->length, m, n);
360   if (m != v->length)
361     return CeedError(rstr->ceed, 2,
362                      "Output vector size %d not compatible with element restriction (%d, %d)",
363                      v->length, m, n);
364   if (rstr->blksize*block > rstr->nelem)
365     return CeedError(rstr->ceed, 2,
366                      "Cannot retrieve block %d, element %d > total elements %d",
367                      block, rstr->blksize*block, rstr->nelem);
368   ierr = rstr->ApplyBlock(rstr, block, tmode, lmode, u, v, request);
369   CeedChk(ierr);
370 
371   return 0;
372 }
373 
374 /**
375   @brief Get the multiplicity of DoFs in a CeedElemRestriction
376 
377   @param rstr      CeedElemRestriction
378   @param[out] mult Vector to store multiplicity (of size ndof)
379 
380   @return An error code: 0 - success, otherwise - failure
381 
382   @ref Advanced
383 **/
384 int CeedElemRestrictionGetMultiplicity(CeedElemRestriction rstr,
385                              CeedVector mult) {
386   int ierr;
387   CeedVector evec;
388 
389   // Create and set evec
390   ierr = CeedElemRestrictionCreateVector(rstr, NULL, &evec); CeedChk(ierr);
391   ierr = CeedVectorSetValue(evec, 1.0); CeedChk(ierr);
392 
393   // Apply to get multiplicity
394   ierr = CeedElemRestrictionApply(rstr, CEED_TRANSPOSE, CEED_NOTRANSPOSE, evec,
395                                   mult, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
396 
397   // Cleanup
398   ierr = CeedVectorDestroy(&evec); CeedChk(ierr);
399 
400   return 0;
401 }
402 
403 /**
404   @brief Get the Ceed associated with a CeedElemRestriction
405 
406   @param rstr             CeedElemRestriction
407   @param[out] ceed        Variable to store Ceed
408 
409   @return An error code: 0 - success, otherwise - failure
410 
411   @ref Advanced
412 **/
413 int CeedElemRestrictionGetCeed(CeedElemRestriction rstr, Ceed *ceed) {
414   *ceed = rstr->ceed;
415   return 0;
416 }
417 
418 /**
419   @brief Get the total number of elements in the range of a CeedElemRestriction
420 
421   @param rstr             CeedElemRestriction
422   @param[out] numelements Variable to store number of elements
423 
424   @return An error code: 0 - success, otherwise - failure
425 
426   @ref Advanced
427 **/
428 int CeedElemRestrictionGetNumElements(CeedElemRestriction rstr,
429                                       CeedInt *numelem) {
430   *numelem = rstr->nelem;
431   return 0;
432 }
433 
434 /**
435   @brief Get the size of elements in the CeedElemRestriction
436 
437   @param rstr             CeedElemRestriction
438   @param[out] elemsize    Variable to store size of elements
439 
440   @return An error code: 0 - success, otherwise - failure
441 
442   @ref Advanced
443 **/
444 int CeedElemRestrictionGetElementSize(CeedElemRestriction rstr,
445                                       CeedInt *elemsize) {
446   *elemsize = rstr->elemsize;
447   return 0;
448 }
449 
450 /**
451   @brief Get the number of degrees of freedom in the range of a
452          CeedElemRestriction
453 
454   @param rstr             CeedElemRestriction
455   @param[out] numnodes    Variable to store number of nodes
456 
457   @return An error code: 0 - success, otherwise - failure
458 
459   @ref Advanced
460 **/
461 int CeedElemRestrictionGetNumNodes(CeedElemRestriction rstr,
462                                    CeedInt *numnodes) {
463   *numnodes = rstr->nnodes;
464   return 0;
465 }
466 
467 /**
468   @brief Get the number of components in the elements of a
469          CeedElemRestriction
470 
471   @param rstr             CeedElemRestriction
472   @param[out] numcomp     Variable to store number of components
473 
474   @return An error code: 0 - success, otherwise - failure
475 
476   @ref Advanced
477 **/
478 int CeedElemRestrictionGetNumComponents(CeedElemRestriction rstr,
479                                         CeedInt *numcomp) {
480   *numcomp = rstr->ncomp;
481   return 0;
482 }
483 
484 /**
485   @brief Get the number of blocks in a CeedElemRestriction
486 
487   @param rstr             CeedElemRestriction
488   @param[out] numblock    Variable to store number of blocks
489 
490   @return An error code: 0 - success, otherwise - failure
491 
492   @ref Advanced
493 **/
494 int CeedElemRestrictionGetNumBlocks(CeedElemRestriction rstr,
495                                     CeedInt *numblock) {
496   *numblock = rstr->nblk;
497   return 0;
498 }
499 
500 /**
501   @brief Get the size of blocks in the CeedElemRestriction
502 
503   @param r                CeedElemRestriction
504   @param[out] blksize     Variable to store size of blocks
505 
506   @return An error code: 0 - success, otherwise - failure
507 
508   @ref Advanced
509 **/
510 int CeedElemRestrictionGetBlockSize(CeedElemRestriction rstr,
511                                     CeedInt *blksize) {
512   *blksize = rstr->blksize;
513   return 0;
514 }
515 
516 /**
517   @brief Get the backend data of a CeedElemRestriction
518 
519   @param r                CeedElemRestriction
520   @param[out] data        Variable to store data
521 
522   @return An error code: 0 - success, otherwise - failure
523 
524   @ref Advanced
525 **/
526 int CeedElemRestrictionGetData(CeedElemRestriction rstr,
527                                void* *data) {
528   *data = rstr->data;
529   return 0;
530 }
531 
532 /**
533   @brief Set the backend data of a CeedElemRestriction
534 
535   @param[out] r           CeedElemRestriction
536   @param data             Data to set
537 
538   @return An error code: 0 - success, otherwise - failure
539 
540   @ref Advanced
541 **/
542 int CeedElemRestrictionSetData(CeedElemRestriction rstr,
543                                void* *data) {
544   rstr->data = *data;
545   return 0;
546 }
547 
548 /**
549   @brief View a CeedElemRestriction
550 
551   @param[in] rstr CeedElemRestriction to view
552   @param[in] stream Stream to write; typically stdout/stderr or a file
553 
554   @return Error code: 0 - success, otherwise - failure
555 
556   @ref Utility
557 **/
558 int CeedElemRestrictionView(CeedElemRestriction rstr, FILE *stream) {
559   fprintf(stream,
560           "CeedElemRestriction from (%d, %d) to %d elements with %d nodes each\n",
561           rstr->nnodes, rstr->ncomp, rstr->nelem, rstr->elemsize);
562   return 0;
563 }
564 
565 /**
566   @brief Destroy a CeedElemRestriction
567 
568   @param rstr CeedElemRestriction to destroy
569 
570   @return An error code: 0 - success, otherwise - failure
571 
572   @ref Basic
573 **/
574 int CeedElemRestrictionDestroy(CeedElemRestriction *rstr) {
575   int ierr;
576 
577   if (!*rstr || --(*rstr)->refcount > 0) return 0;
578   if ((*rstr)->Destroy) {
579     ierr = (*rstr)->Destroy(*rstr); CeedChk(ierr);
580   }
581   ierr = CeedDestroy(&(*rstr)->ceed); CeedChk(ierr);
582   ierr = CeedFree(rstr); CeedChk(ierr);
583   return 0;
584 }
585 
586 /// @}
587