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