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