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