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