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