xref: /libCEED/interface/ceed-operator.c (revision c521346b1c30750713425cdd0818875370ae626d)
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   r->refcount += 1;
210   (*ofield)->lmode = lmode;
211   (*ofield)->basis = b;
212   if (b != CEED_BASIS_COLLOCATED)
213     b->refcount += 1;
214   (*ofield)->vec = v;
215   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
216     v->refcount += 1;
217   op->nfields += 1;
218   return 0;
219 }
220 
221 /**
222   @brief Add a sub-operator to a composite CeedOperator
223 
224   @param[out] compositeop Address of the composite CeedOperator
225   @param      subop       Address of the sub-operator CeedOperator
226 
227   @return An error code: 0 - success, otherwise - failure
228 
229   @ref Basic
230  */
231 int CeedCompositeOperatorAddSub(CeedOperator compositeop,
232                                 CeedOperator subop) {
233   if (!compositeop->composite)
234     // LCOV_EXCL_START
235     return CeedError(compositeop->ceed, 1,
236                      "CeedOperator is not a composite operator");
237   // LCOV_EXCL_STOP
238 
239   if (compositeop->numsub == CEED_COMPOSITE_MAX)
240     // LCOV_EXCL_START
241     return CeedError(compositeop->ceed, 1,
242                      "Cannot add additional suboperators");
243   // LCOV_EXCL_STOP
244 
245   compositeop->suboperators[compositeop->numsub] = subop;
246   subop->refcount++;
247   compositeop->numsub++;
248   return 0;
249 }
250 
251 /**
252   @brief Apply CeedOperator to a vector
253 
254   This computes the action of the operator on the specified (active) input,
255   yielding its (active) output.  All inputs and outputs must be specified using
256   CeedOperatorSetField().
257 
258   @param op        CeedOperator to apply
259   @param[in] in    CeedVector containing input state or NULL if there are no
260                      active inputs
261   @param[out] out  CeedVector to store result of applying operator (must be
262                      distinct from @a in) or NULL if there are no active outputs
263   @param request   Address of CeedRequest for non-blocking completion, else
264                      CEED_REQUEST_IMMEDIATE
265 
266   @return An error code: 0 - success, otherwise - failure
267 
268   @ref Basic
269 **/
270 int CeedOperatorApply(CeedOperator op, CeedVector in,
271                       CeedVector out, CeedRequest *request) {
272   int ierr;
273   Ceed ceed = op->ceed;
274   CeedQFunction qf = op->qf;
275 
276   if (op->composite) {
277     if (!op->numsub)
278       // LCOV_EXCL_START
279       return CeedError(ceed, 1, "No suboperators set");
280     // LCOV_EXCL_STOP
281   } else {
282     if (op->nfields == 0)
283       // LCOV_EXCL_START
284       return CeedError(ceed, 1, "No operator fields set");
285     // LCOV_EXCL_STOP
286     if (op->nfields < qf->numinputfields + qf->numoutputfields)
287       // LCOV_EXCL_START
288       return CeedError(ceed, 1, "Not all operator fields set");
289     // LCOV_EXCL_STOP
290     if (op->numelements == 0)
291       // LCOV_EXCL_START
292       return CeedError(ceed, 1,"At least one restriction required");
293     // LCOV_EXCL_STOP
294     if (op->numqpoints == 0)
295       // LCOV_EXCL_START
296       return CeedError(ceed, 1,"At least one non-collocated basis required");
297     // LCOV_EXCL_STOP
298   }
299   ierr = op->Apply(op, in, out, request); CeedChk(ierr);
300   return 0;
301 }
302 
303 /**
304   @brief Get the Ceed associated with a CeedOperator
305 
306   @param op              CeedOperator
307   @param[out] ceed       Variable to store Ceed
308 
309   @return An error code: 0 - success, otherwise - failure
310 
311   @ref Advanced
312 **/
313 
314 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
315   *ceed = op->ceed;
316   return 0;
317 }
318 
319 /**
320   @brief Get the number of elements associated with a CeedOperator
321 
322   @param op              CeedOperator
323   @param[out] numelem    Variable to store number of elements
324 
325   @return An error code: 0 - success, otherwise - failure
326 
327   @ref Advanced
328 **/
329 
330 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
331   if (op->composite)
332     // LCOV_EXCL_START
333     return CeedError(op->ceed, 1, "Not defined for composite operator");
334   // LCOV_EXCL_STOP
335 
336   *numelem = op->numelements;
337   return 0;
338 }
339 
340 /**
341   @brief Get the number of quadrature points associated with a CeedOperator
342 
343   @param op              CeedOperator
344   @param[out] numqpts    Variable to store vector number of quadrature points
345 
346   @return An error code: 0 - success, otherwise - failure
347 
348   @ref Advanced
349 **/
350 
351 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
352   if (op->composite)
353     // LCOV_EXCL_START
354     return CeedError(op->ceed, 1, "Not defined for composite operator");
355   // LCOV_EXCL_STOP
356 
357   *numqpts = op->numqpoints;
358   return 0;
359 }
360 
361 /**
362   @brief Get the number of arguments associated with a CeedOperator
363 
364   @param op              CeedOperator
365   @param[out] numargs    Variable to store vector number of arguments
366 
367   @return An error code: 0 - success, otherwise - failure
368 
369   @ref Advanced
370 **/
371 
372 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
373   if (op->composite)
374     // LCOV_EXCL_START
375     return CeedError(op->ceed, 1, "Not defined for composite operators");
376   // LCOV_EXCL_STOP
377 
378   *numargs = op->nfields;
379   return 0;
380 }
381 
382 /**
383   @brief Get the setup status of a CeedOperator
384 
385   @param op             CeedOperator
386   @param[out] setupdone Variable to store setup status
387 
388   @return An error code: 0 - success, otherwise - failure
389 
390   @ref Advanced
391 **/
392 
393 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
394   *setupdone = op->setupdone;
395   return 0;
396 }
397 
398 /**
399   @brief Get the QFunction associated with a CeedOperator
400 
401   @param op              CeedOperator
402   @param[out] qf         Variable to store QFunction
403 
404   @return An error code: 0 - success, otherwise - failure
405 
406   @ref Advanced
407 **/
408 
409 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
410   if (op->composite)
411     // LCOV_EXCL_START
412     return CeedError(op->ceed, 1, "Not defined for composite operator");
413   // LCOV_EXCL_STOP
414 
415   *qf = op->qf;
416   return 0;
417 }
418 
419 /**
420   @brief Get the number of suboperators associated with a CeedOperator
421 
422   @param op              CeedOperator
423   @param[out] numsub     Variable to store number of suboperators
424 
425   @return An error code: 0 - success, otherwise - failure
426 
427   @ref Advanced
428 **/
429 
430 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
431   if (!op->composite)
432     // LCOV_EXCL_START
433     return CeedError(op->ceed, 1, "Not a composite operator");
434   // LCOV_EXCL_STOP
435 
436   *numsub = op->numsub;
437   return 0;
438 }
439 
440 /**
441   @brief Get the list of suboperators associated with a CeedOperator
442 
443   @param op                CeedOperator
444   @param[out] suboperators Variable to store list of suboperators
445 
446   @return An error code: 0 - success, otherwise - failure
447 
448   @ref Advanced
449 **/
450 
451 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) {
452   if (!op->composite)
453     // LCOV_EXCL_START
454     return CeedError(op->ceed, 1, "Not a composite operator");
455   // LCOV_EXCL_STOP
456 
457   *suboperators = op->suboperators;
458   return 0;
459 }
460 
461 /**
462   @brief Set the backend data of a CeedOperator
463 
464   @param[out] op         CeedOperator
465   @param data            Data to set
466 
467   @return An error code: 0 - success, otherwise - failure
468 
469   @ref Advanced
470 **/
471 
472 int CeedOperatorSetData(CeedOperator op, void* *data) {
473   op->data = *data;
474   return 0;
475 }
476 
477 /**
478   @brief Get the backend data of a CeedOperator
479 
480   @param op              CeedOperator
481   @param[out] data       Variable to store data
482 
483   @return An error code: 0 - success, otherwise - failure
484 
485   @ref Advanced
486 **/
487 
488 int CeedOperatorGetData(CeedOperator op, void* *data) {
489   *data = op->data;
490   return 0;
491 }
492 
493 /**
494   @brief Set the setup flag of a CeedOperator to True
495 
496   @param op              CeedOperator
497 
498   @return An error code: 0 - success, otherwise - failure
499 
500   @ref Advanced
501 **/
502 
503 int CeedOperatorSetSetupDone(CeedOperator op) {
504   op->setupdone = 1;
505   return 0;
506 }
507 
508 /**
509   @brief Get the CeedOperatorFields of a CeedOperator
510 
511   @param op                 CeedOperator
512   @param[out] inputfields   Variable to store inputfields
513   @param[out] outputfields  Variable to store outputfields
514 
515   @return An error code: 0 - success, otherwise - failure
516 
517   @ref Advanced
518 **/
519 
520 int CeedOperatorGetFields(CeedOperator op,
521                           CeedOperatorField* *inputfields,
522                           CeedOperatorField* *outputfields) {
523   if (op->composite)
524     // LCOV_EXCL_START
525     return CeedError(op->ceed, 1, "Not defined for composite operator");
526   // LCOV_EXCL_STOP
527 
528   if (inputfields) *inputfields = op->inputfields;
529   if (outputfields) *outputfields = op->outputfields;
530   return 0;
531 }
532 
533 /**
534   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
535 
536   @param opfield         CeedOperatorField
537   @param[out] lmode      Variable to store CeedTransposeMode
538 
539   @return An error code: 0 - success, otherwise - failure
540 
541   @ref Advanced
542 **/
543 
544 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
545                               CeedTransposeMode *lmode) {
546   *lmode = opfield->lmode;
547   return 0;
548 }
549 
550 /**
551   @brief Get the CeedElemRestriction of a CeedOperatorField
552 
553   @param opfield         CeedOperatorField
554   @param[out] rstr       Variable to store CeedElemRestriction
555 
556   @return An error code: 0 - success, otherwise - failure
557 
558   @ref Advanced
559 **/
560 
561 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
562                                         CeedElemRestriction *rstr) {
563   *rstr = opfield->Erestrict;
564   return 0;
565 }
566 
567 /**
568   @brief Get the CeedBasis of a CeedOperatorField
569 
570   @param opfield         CeedOperatorField
571   @param[out] basis      Variable to store CeedBasis
572 
573   @return An error code: 0 - success, otherwise - failure
574 
575   @ref Advanced
576 **/
577 
578 int CeedOperatorFieldGetBasis(CeedOperatorField opfield,
579                               CeedBasis *basis) {
580   *basis = opfield->basis;
581   return 0;
582 }
583 
584 /**
585   @brief Get the CeedVector of a CeedOperatorField
586 
587   @param opfield         CeedOperatorField
588   @param[out] vec        Variable to store CeedVector
589 
590   @return An error code: 0 - success, otherwise - failure
591 
592   @ref Advanced
593 **/
594 
595 int CeedOperatorFieldGetVector(CeedOperatorField opfield,
596                                CeedVector *vec) {
597   *vec = opfield->vec;
598   return 0;
599 }
600 
601 /**
602   @brief Destroy a CeedOperator
603 
604   @param op CeedOperator to destroy
605 
606   @return An error code: 0 - success, otherwise - failure
607 
608   @ref Basic
609 **/
610 int CeedOperatorDestroy(CeedOperator *op) {
611   int ierr;
612 
613   if (!*op || --(*op)->refcount > 0) return 0;
614   if ((*op)->Destroy) {
615     ierr = (*op)->Destroy(*op); CeedChk(ierr);
616   }
617   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
618   // Free fields
619   for (int i=0; i<(*op)->nfields; i++) {
620     if ((*op)->inputfields[i]) {
621       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
622       CeedChk(ierr);
623       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
624         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
625       }
626       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
627           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
628         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
629       }
630       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
631     }
632   }
633   for (int i=0; i<(*op)->nfields; i++) {
634     if ((*op)->outputfields[i]) {
635       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
636       CeedChk(ierr);
637       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
638         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
639       }
640       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
641           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
642         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
643       }
644       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
645     }
646   }
647   // Destroy suboperators
648   for (int i=0; i<(*op)->numsub; i++) {
649     if ((*op)->suboperators[i]) {
650       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
651     }
652   }
653   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
654   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
655   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
656 
657   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
658   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
659   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
660   ierr = CeedFree(op); CeedChk(ierr);
661   return 0;
662 }
663 
664 /// @}
665