xref: /libCEED/interface/ceed-operator.c (revision 2b8e417a3eed07850d5ff14106f7d8075f249a2b)
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 #include <string.h>
20 
21 /// @file
22 /// Implementation of public CeedOperator interfaces
23 ///
24 /// @addtogroup CeedOperator
25 ///   @{
26 
27 /**
28   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
29            CeedElemRestriction can be associated with CeedQFunction fields with
30            \ref CeedOperatorSetField.
31 
32   @param ceed    A Ceed object where the CeedOperator will be created
33   @param qf      QFunction defining the action of the operator at quadrature points
34   @param dqf     QFunction defining the action of the Jacobian of @a qf (or NULL)
35   @param dqfT    QFunction defining the action of the transpose of the Jacobian
36                    of @a qf (or NULL)
37   @param[out] op Address of the variable where the newly created
38                      CeedOperator will be stored
39 
40   @return An error code: 0 - success, otherwise - failure
41 
42   @ref Basic
43  */
44 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
45                        CeedQFunction dqfT, CeedOperator *op) {
46   int ierr;
47 
48   if (!ceed->OperatorCreate) {
49     Ceed delegate;
50     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
51 
52     if (!delegate)
53       // LCOV_EXCL_START
54       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
55     // LCOV_EXCL_STOP
56 
57     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
58     return 0;
59   }
60 
61   ierr = CeedCalloc(1,op); CeedChk(ierr);
62   (*op)->ceed = ceed;
63   ceed->refcount++;
64   (*op)->refcount = 1;
65   (*op)->qf = qf;
66   qf->refcount++;
67   (*op)->dqf = dqf;
68   if (dqf) dqf->refcount++;
69   (*op)->dqfT = dqfT;
70   if (dqfT) dqfT->refcount++;
71   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
72   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
73   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
74   return 0;
75 }
76 
77 /**
78   @brief Create an operator that composes the action of several operators
79 
80   @param ceed    A Ceed object where the CeedOperator will be created
81   @param[out] op Address of the variable where the newly created
82                      Composite CeedOperator will be stored
83 
84   @return An error code: 0 - success, otherwise - failure
85 
86   @ref Basic
87  */
88 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
89   int ierr;
90 
91   if (!ceed->CompositeOperatorCreate) {
92     Ceed delegate;
93     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
94 
95     if (!delegate)
96       // LCOV_EXCL_START
97       return CeedError(ceed, 1, "Backend does not support CompositeOperatorCreate");
98     // LCOV_EXCL_STOP
99 
100     ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
101     return 0;
102   }
103 
104   ierr = CeedCalloc(1,op); CeedChk(ierr);
105   (*op)->ceed = ceed;
106   ceed->refcount++;
107   (*op)->composite = true;
108   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
109   ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
110   return 0;
111 }
112 
113 /**
114   @brief Provide a field to a CeedOperator for use by its CeedQFunction
115 
116   This function is used to specify both active and passive fields to a
117   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
118   fields can inputs or outputs (updated in-place when operator is applied).
119 
120   Active fields must be specified using this function, but their data (in a
121   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
122   input and at most one active output.
123 
124   @param op         CeedOperator on which to provide the field
125   @param fieldname  Name of the field (to be matched with the name used by
126                       CeedQFunction)
127   @param r          CeedElemRestriction
128   @param lmode      CeedTransposeMode which specifies the ordering of the
129                       components of the l-vector used by this CeedOperatorField,
130                       CEED_NOTRANSPOSE indicates the component is the
131                       outermost index and CEED_TRANSPOSE indicates the component
132                       is the innermost index in ordering of the l-vector
133   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
134                       if collocated with quadrature points
135   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
136                       if field is active or CEED_VECTOR_NONE if using
137                       CEED_EVAL_WEIGHT in the QFunction
138 
139   @return An error code: 0 - success, otherwise - failure
140 
141   @ref Basic
142 **/
143 int CeedOperatorSetField(CeedOperator op, const char *fieldname,
144                          CeedElemRestriction r, CeedTransposeMode lmode,
145                          CeedBasis b, CeedVector v) {
146   int ierr;
147   if (op->composite)
148     // LCOV_EXCL_START
149     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
150   // LCOV_EXCL_STOP
151   if (!r)
152     // LCOV_EXCL_START
153     return CeedError(op->ceed, 1,
154                      "ElemRestriction r for field \"%s\" must be non-NULL.",
155                      fieldname);
156   // LCOV_EXCL_STOP
157   if (!b)
158     // LCOV_EXCL_START
159     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
160                      fieldname);
161   // LCOV_EXCL_STOP
162   if (!v)
163     // LCOV_EXCL_START
164     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
165                      fieldname);
166   // LCOV_EXCL_STOP
167 
168   CeedInt numelements;
169   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
170   if (op->numelements && op->numelements != numelements)
171     // LCOV_EXCL_START
172     return CeedError(op->ceed, 1,
173                      "ElemRestriction with %d elements incompatible with prior %d elements",
174                      numelements, op->numelements);
175   // LCOV_EXCL_STOP
176   op->numelements = numelements;
177 
178   if (b != CEED_BASIS_COLLOCATED) {
179     CeedInt numqpoints;
180     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
181     if (op->numqpoints && op->numqpoints != numqpoints)
182       // LCOV_EXCL_START
183       return CeedError(op->ceed, 1,
184                        "Basis with %d quadrature points incompatible with prior %d points",
185                        numqpoints, op->numqpoints);
186     // LCOV_EXCL_STOP
187     op->numqpoints = numqpoints;
188   }
189   CeedOperatorField *ofield;
190   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
191     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
192       ofield = &op->inputfields[i];
193       goto found;
194     }
195   }
196   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
197     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
198       ofield = &op->outputfields[i];
199       goto found;
200     }
201   }
202   // LCOV_EXCL_START
203   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
204                    fieldname);
205   // LCOV_EXCL_STOP
206 found:
207   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
208   (*ofield)->Erestrict = r;
209   (*ofield)->lmode = lmode;
210   (*ofield)->basis = b;
211   (*ofield)->vec = v;
212   op->nfields += 1;
213   return 0;
214 }
215 
216 /**
217   @brief Add a sub-operator to a composite CeedOperator
218 
219   @param[out] compositeop Address of the composite CeedOperator
220   @param      subop       Address of the sub-operator CeedOperator
221 
222   @return An error code: 0 - success, otherwise - failure
223 
224   @ref Basic
225  */
226 int CeedCompositeOperatorAddSub(CeedOperator compositeop,
227                                 CeedOperator subop) {
228   if (!compositeop->composite)
229     // LCOV_EXCL_START
230     return CeedError(compositeop->ceed, 1,
231                      "CeedOperator is not a composite operator");
232   // LCOV_EXCL_STOP
233 
234   if (compositeop->numsub == CEED_COMPOSITE_MAX)
235     // LCOV_EXCL_START
236     return CeedError(compositeop->ceed, 1,
237                      "Cannot add additional suboperators");
238   // LCOV_EXCL_STOP
239 
240   compositeop->suboperators[compositeop->numsub] = subop;
241   subop->refcount++;
242   compositeop->numsub++;
243   return 0;
244 }
245 
246 /**
247   @brief Apply CeedOperator to a vector
248 
249   This computes the action of the operator on the specified (active) input,
250   yielding its (active) output.  All inputs and outputs must be specified using
251   CeedOperatorSetField().
252 
253   @param op        CeedOperator to apply
254   @param[in] in    CeedVector containing input state or NULL if there are no
255                      active inputs
256   @param[out] out  CeedVector to store result of applying operator (must be
257                      distinct from @a in) or NULL if there are no active outputs
258   @param request   Address of CeedRequest for non-blocking completion, else
259                      CEED_REQUEST_IMMEDIATE
260 
261   @return An error code: 0 - success, otherwise - failure
262 
263   @ref Basic
264 **/
265 int CeedOperatorApply(CeedOperator op, CeedVector in,
266                       CeedVector out, CeedRequest *request) {
267   int ierr;
268   Ceed ceed = op->ceed;
269   CeedQFunction qf = op->qf;
270 
271   if (op->composite) {
272     if (!op->numsub)
273       // LCOV_EXCL_START
274       return CeedError(ceed, 1, "No suboperators set");
275     // LCOV_EXCL_STOP
276   } else {
277     if (op->nfields == 0)
278       // LCOV_EXCL_START
279       return CeedError(ceed, 1, "No operator fields set");
280     // LCOV_EXCL_STOP
281     if (op->nfields < qf->numinputfields + qf->numoutputfields)
282       // LCOV_EXCL_START
283       return CeedError(ceed, 1, "Not all operator fields set");
284     // LCOV_EXCL_STOP
285     if (op->numelements == 0)
286       // LCOV_EXCL_START
287       return CeedError(ceed, 1,"At least one restriction required");
288     // LCOV_EXCL_STOP
289     if (op->numqpoints == 0)
290       // LCOV_EXCL_START
291       return CeedError(ceed, 1,"At least one non-collocated basis required");
292     // LCOV_EXCL_STOP
293   }
294   ierr = op->Apply(op, in, out, request); CeedChk(ierr);
295   return 0;
296 }
297 
298 /**
299   @brief Get the Ceed associated with a CeedOperator
300 
301   @param op              CeedOperator
302   @param[out] ceed       Variable to store Ceed
303 
304   @return An error code: 0 - success, otherwise - failure
305 
306   @ref Advanced
307 **/
308 
309 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
310   *ceed = op->ceed;
311   return 0;
312 }
313 
314 /**
315   @brief Get the number of elements associated with a CeedOperator
316 
317   @param op              CeedOperator
318   @param[out] numelem    Variable to store number of elements
319 
320   @return An error code: 0 - success, otherwise - failure
321 
322   @ref Advanced
323 **/
324 
325 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
326   if (op->composite)
327     // LCOV_EXCL_START
328     return CeedError(op->ceed, 1, "Not defined for composite operator");
329   // LCOV_EXCL_STOP
330 
331   *numelem = op->numelements;
332   return 0;
333 }
334 
335 /**
336   @brief Get the number of quadrature points associated with a CeedOperator
337 
338   @param op              CeedOperator
339   @param[out] numqpts    Variable to store vector number of quadrature points
340 
341   @return An error code: 0 - success, otherwise - failure
342 
343   @ref Advanced
344 **/
345 
346 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
347   if (op->composite)
348     // LCOV_EXCL_START
349     return CeedError(op->ceed, 1, "Not defined for composite operator");
350   // LCOV_EXCL_STOP
351 
352   *numqpts = op->numqpoints;
353   return 0;
354 }
355 
356 /**
357   @brief Get the number of arguments associated with a CeedOperator
358 
359   @param op              CeedOperator
360   @param[out] numargs    Variable to store vector number of arguments
361 
362   @return An error code: 0 - success, otherwise - failure
363 
364   @ref Advanced
365 **/
366 
367 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
368   if (op->composite)
369     // LCOV_EXCL_START
370     return CeedError(op->ceed, 1, "Not defined for composite operators");
371   // LCOV_EXCL_STOP
372 
373   *numargs = op->nfields;
374   return 0;
375 }
376 
377 /**
378   @brief Get the setup status of a CeedOperator
379 
380   @param op             CeedOperator
381   @param[out] setupdone Variable to store setup status
382 
383   @return An error code: 0 - success, otherwise - failure
384 
385   @ref Advanced
386 **/
387 
388 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
389   *setupdone = op->setupdone;
390   return 0;
391 }
392 
393 /**
394   @brief Get the QFunction associated with a CeedOperator
395 
396   @param op              CeedOperator
397   @param[out] qf         Variable to store QFunction
398 
399   @return An error code: 0 - success, otherwise - failure
400 
401   @ref Advanced
402 **/
403 
404 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
405   if (op->composite)
406     // LCOV_EXCL_START
407     return CeedError(op->ceed, 1, "Not defined for composite operator");
408   // LCOV_EXCL_STOP
409 
410   *qf = op->qf;
411   return 0;
412 }
413 
414 /**
415   @brief Get the number of suboperators associated with a CeedOperator
416 
417   @param op              CeedOperator
418   @param[out] numsub     Variable to store number of suboperators
419 
420   @return An error code: 0 - success, otherwise - failure
421 
422   @ref Advanced
423 **/
424 
425 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
426   if (!op->composite)
427     // LCOV_EXCL_START
428     return CeedError(op->ceed, 1, "Not a composite operator");
429   // LCOV_EXCL_STOP
430 
431   *numsub = op->numsub;
432   return 0;
433 }
434 
435 /**
436   @brief Get the list of suboperators associated with a CeedOperator
437 
438   @param op                CeedOperator
439   @param[out] suboperators Variable to store list of suboperators
440 
441   @return An error code: 0 - success, otherwise - failure
442 
443   @ref Advanced
444 **/
445 
446 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) {
447   if (!op->composite)
448     // LCOV_EXCL_START
449     return CeedError(op->ceed, 1, "Not a composite operator");
450   // LCOV_EXCL_STOP
451 
452   *suboperators = op->suboperators;
453   return 0;
454 }
455 
456 /**
457   @brief Set the backend data of a CeedOperator
458 
459   @param[out] op         CeedOperator
460   @param data            Data to set
461 
462   @return An error code: 0 - success, otherwise - failure
463 
464   @ref Advanced
465 **/
466 
467 int CeedOperatorSetData(CeedOperator op, void* *data) {
468   op->data = *data;
469   return 0;
470 }
471 
472 /**
473   @brief Get the backend data of a CeedOperator
474 
475   @param op              CeedOperator
476   @param[out] data       Variable to store data
477 
478   @return An error code: 0 - success, otherwise - failure
479 
480   @ref Advanced
481 **/
482 
483 int CeedOperatorGetData(CeedOperator op, void* *data) {
484   *data = op->data;
485   return 0;
486 }
487 
488 /**
489   @brief Set the setup flag of a CeedOperator to True
490 
491   @param op              CeedOperator
492 
493   @return An error code: 0 - success, otherwise - failure
494 
495   @ref Advanced
496 **/
497 
498 int CeedOperatorSetSetupDone(CeedOperator op) {
499   op->setupdone = 1;
500   return 0;
501 }
502 
503 /**
504   @brief Get the CeedOperatorFields of a CeedOperator
505 
506   @param op                 CeedOperator
507   @param[out] inputfields   Variable to store inputfields
508   @param[out] outputfields  Variable to store outputfields
509 
510   @return An error code: 0 - success, otherwise - failure
511 
512   @ref Advanced
513 **/
514 
515 int CeedOperatorGetFields(CeedOperator op,
516                           CeedOperatorField* *inputfields,
517                           CeedOperatorField* *outputfields) {
518   if (op->composite)
519     // LCOV_EXCL_START
520     return CeedError(op->ceed, 1, "Not defined for composite operator");
521   // LCOV_EXCL_STOP
522 
523   if (inputfields) *inputfields = op->inputfields;
524   if (outputfields) *outputfields = op->outputfields;
525   return 0;
526 }
527 
528 /**
529   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
530 
531   @param opfield         CeedOperatorField
532   @param[out] lmode      Variable to store CeedTransposeMode
533 
534   @return An error code: 0 - success, otherwise - failure
535 
536   @ref Advanced
537 **/
538 
539 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
540                               CeedTransposeMode *lmode) {
541   *lmode = opfield->lmode;
542   return 0;
543 }
544 
545 /**
546   @brief Get the CeedElemRestriction of a CeedOperatorField
547 
548   @param opfield         CeedOperatorField
549   @param[out] rstr       Variable to store CeedElemRestriction
550 
551   @return An error code: 0 - success, otherwise - failure
552 
553   @ref Advanced
554 **/
555 
556 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
557                                         CeedElemRestriction *rstr) {
558   *rstr = opfield->Erestrict;
559   return 0;
560 }
561 
562 /**
563   @brief Get the CeedBasis of a CeedOperatorField
564 
565   @param opfield         CeedOperatorField
566   @param[out] basis      Variable to store CeedBasis
567 
568   @return An error code: 0 - success, otherwise - failure
569 
570   @ref Advanced
571 **/
572 
573 int CeedOperatorFieldGetBasis(CeedOperatorField opfield,
574                               CeedBasis *basis) {
575   *basis = opfield->basis;
576   return 0;
577 }
578 
579 /**
580   @brief Get the CeedVector of a CeedOperatorField
581 
582   @param opfield         CeedOperatorField
583   @param[out] vec        Variable to store CeedVector
584 
585   @return An error code: 0 - success, otherwise - failure
586 
587   @ref Advanced
588 **/
589 
590 int CeedOperatorFieldGetVector(CeedOperatorField opfield,
591                                CeedVector *vec) {
592   *vec = opfield->vec;
593   return 0;
594 }
595 
596 /**
597   @brief Destroy a CeedOperator
598 
599   @param op CeedOperator to destroy
600 
601   @return An error code: 0 - success, otherwise - failure
602 
603   @ref Basic
604 **/
605 int CeedOperatorDestroy(CeedOperator *op) {
606   int ierr;
607 
608   if (!*op || --(*op)->refcount > 0) return 0;
609   if ((*op)->Destroy) {
610     ierr = (*op)->Destroy(*op); CeedChk(ierr);
611   }
612   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
613   // Free fields
614   for (int i=0; i<(*op)->nfields; i++) {
615     if ((*op)->inputfields[i]) {
616       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
617     }
618   }
619   for (int i=0; i<(*op)->nfields; i++) {
620     if ((*op)->outputfields[i]) {
621       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
622     }
623   }
624   // Destroy suboperators
625   for (int i=0; i<(*op)->numsub; i++) {
626     if ((*op)->suboperators[i]) {
627       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
628     }
629   }
630   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
631   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
632   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
633 
634   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
635   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
636   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
637   ierr = CeedFree(op); CeedChk(ierr);
638   return 0;
639 }
640 
641 /// @}
642