xref: /petsc/src/vec/pf/interface/pf.c (revision d756bedd70a89ca052be956bccd75c5761cb2ab4)
1 /*
2     The PF mathematical functions interface routines, callable by users.
3 */
4 #include <../src/vec/pf/pfimpl.h> /*I "petscpf.h" I*/
5 
6 PetscClassId      PF_CLASSID          = 0;
7 PetscFunctionList PFList              = NULL; /* list of all registered PD functions */
8 PetscBool         PFRegisterAllCalled = PETSC_FALSE;
9 
10 /*@C
11   PFSet - Sets the C/C++/Fortran functions to be used by the PF function
12 
13   Collective
14 
15   Input Parameters:
16 + pf       - the function context
17 . apply    - function to apply to an array
18 . applyvec - function to apply to a Vec
19 . view     - function that prints information about the `PF`
20 . destroy  - function to free the private function context
21 - ctx      - private function context
22 
23   Level: beginner
24 
25 .seealso: `PF`, `PFCreate()`, `PFDestroy()`, `PFSetType()`, `PFApply()`, `PFApplyVec()`
26 @*/
27 PetscErrorCode PFSet(PF pf, PetscErrorCode (*apply)(void *, PetscInt, const PetscScalar *, PetscScalar *), PetscErrorCode (*applyvec)(void *, Vec, Vec), PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*destroy)(PetscCtxRt), PetscCtx ctx)
28 {
29   PetscFunctionBegin;
30   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
31   pf->data          = ctx;
32   pf->ops->destroy  = destroy;
33   pf->ops->apply    = apply;
34   pf->ops->applyvec = applyvec;
35   pf->ops->view     = view;
36   PetscFunctionReturn(PETSC_SUCCESS);
37 }
38 
39 /*@C
40   PFDestroy - Destroys `PF` context that was created with `PFCreate()`.
41 
42   Collective
43 
44   Input Parameter:
45 . pf - the function context
46 
47   Level: beginner
48 
49 .seealso: `PF`, `PFCreate()`, `PFSet()`, `PFSetType()`
50 @*/
51 PetscErrorCode PFDestroy(PF *pf)
52 {
53   PetscFunctionBegin;
54   if (!*pf) PetscFunctionReturn(PETSC_SUCCESS);
55   PetscValidHeaderSpecific(*pf, PF_CLASSID, 1);
56   if (--((PetscObject)*pf)->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
57 
58   PetscCall(PFViewFromOptions(*pf, NULL, "-pf_view"));
59   /* if memory was published with SAWs then destroy it */
60   PetscCall(PetscObjectSAWsViewOff((PetscObject)*pf));
61 
62   if ((*pf)->ops->destroy) PetscCall((*(*pf)->ops->destroy)((*pf)->data));
63   PetscCall(PetscHeaderDestroy(pf));
64   PetscFunctionReturn(PETSC_SUCCESS);
65 }
66 
67 /*@C
68   PFCreate - Creates a mathematical function context.
69 
70   Collective
71 
72   Input Parameters:
73 + comm   - MPI communicator
74 . dimin  - dimension of the space you are mapping from
75 - dimout - dimension of the space you are mapping to
76 
77   Output Parameter:
78 . pf - the function context
79 
80   Level: developer
81 
82 .seealso: `PF`, `PFSet()`, `PFApply()`, `PFDestroy()`, `PFApplyVec()`
83 @*/
84 PetscErrorCode PFCreate(MPI_Comm comm, PetscInt dimin, PetscInt dimout, PF *pf)
85 {
86   PF newpf;
87 
88   PetscFunctionBegin;
89   PetscAssertPointer(pf, 4);
90   *pf = NULL;
91   PetscCall(PFInitializePackage());
92 
93   PetscCall(PetscHeaderCreate(newpf, PF_CLASSID, "PF", "Mathematical functions", "Vec", comm, PFDestroy, PFView));
94   newpf->data          = NULL;
95   newpf->ops->destroy  = NULL;
96   newpf->ops->apply    = NULL;
97   newpf->ops->applyvec = NULL;
98   newpf->ops->view     = NULL;
99   newpf->dimin         = dimin;
100   newpf->dimout        = dimout;
101 
102   *pf = newpf;
103   PetscFunctionReturn(PETSC_SUCCESS);
104 }
105 
106 /*@
107   PFApplyVec - Applies the mathematical function to a vector
108 
109   Collective
110 
111   Input Parameters:
112 + pf - the function context
113 - x  - input vector (or `NULL` for the vector (0,1, .... N-1)
114 
115   Output Parameter:
116 . y - output vector
117 
118   Level: beginner
119 
120 .seealso: `PF`, `PFApply()`, `PFCreate()`, `PFDestroy()`, `PFSetType()`, `PFSet()`
121 @*/
122 PetscErrorCode PFApplyVec(PF pf, Vec x, Vec y)
123 {
124   PetscInt  i, rstart, rend, n, p;
125   PetscBool nox = PETSC_FALSE;
126 
127   PetscFunctionBegin;
128   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
129   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
130   if (x) {
131     PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
132     PetscCheck(x != y, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "x and y must be different vectors");
133   } else {
134     PetscScalar *xx;
135     PetscInt     lsize;
136 
137     PetscCall(VecGetLocalSize(y, &lsize));
138     lsize = pf->dimin * lsize / pf->dimout;
139     PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)y), lsize, PETSC_DETERMINE, &x));
140     nox = PETSC_TRUE;
141     PetscCall(VecGetOwnershipRange(x, &rstart, &rend));
142     PetscCall(VecGetArray(x, &xx));
143     for (i = rstart; i < rend; i++) xx[i - rstart] = (PetscScalar)i;
144     PetscCall(VecRestoreArray(x, &xx));
145   }
146 
147   PetscCall(VecGetLocalSize(x, &n));
148   PetscCall(VecGetLocalSize(y, &p));
149   PetscCheck((pf->dimin * (n / pf->dimin)) == n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local input vector length %" PetscInt_FMT " not divisible by dimin %" PetscInt_FMT " of function", n, pf->dimin);
150   PetscCheck((pf->dimout * (p / pf->dimout)) == p, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local output vector length %" PetscInt_FMT " not divisible by dimout %" PetscInt_FMT " of function", p, pf->dimout);
151   PetscCheck((n / pf->dimin) == (p / pf->dimout), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local vector lengths %" PetscInt_FMT " %" PetscInt_FMT " are wrong for dimin and dimout %" PetscInt_FMT " %" PetscInt_FMT " of function", n, p, pf->dimin, pf->dimout);
152 
153   if (pf->ops->applyvec) PetscCallBack("PF callback apply to vector", (*pf->ops->applyvec)(pf->data, x, y));
154   else {
155     const PetscScalar *xx;
156     PetscScalar       *yy;
157 
158     PetscCall(VecGetLocalSize(x, &n));
159     n = n / pf->dimin;
160     PetscCall(VecGetArrayRead(x, &xx));
161     PetscCall(VecGetArray(y, &yy));
162     PetscCallBack("PF callback apply to array", (*pf->ops->apply)(pf->data, n, xx, yy));
163     PetscCall(VecRestoreArrayRead(x, &xx));
164     PetscCall(VecRestoreArray(y, &yy));
165   }
166   if (nox) PetscCall(VecDestroy(&x));
167   PetscFunctionReturn(PETSC_SUCCESS);
168 }
169 
170 /*@
171   PFApply - Applies the mathematical function to an array of values.
172 
173   Collective
174 
175   Input Parameters:
176 + pf - the function context
177 . n  - number of pointwise function evaluations to perform, each pointwise function evaluation
178        is a function of dimin variables and computes dimout variables where dimin and dimout are defined
179        in the call to `PFCreate()`
180 - x  - input array
181 
182   Output Parameter:
183 . y - output array
184 
185   Level: beginner
186 
187 .seealso: `PF`, `PFApplyVec()`, `PFCreate()`, `PFDestroy()`, `PFSetType()`, `PFSet()`
188 @*/
189 PetscErrorCode PFApply(PF pf, PetscInt n, const PetscScalar *x, PetscScalar *y)
190 {
191   PetscFunctionBegin;
192   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
193   PetscAssertPointer(x, 3);
194   PetscAssertPointer(y, 4);
195   PetscCheck(x != y, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "x and y must be different arrays");
196 
197   PetscCallBack("PF callback apply", (*pf->ops->apply)(pf->data, n, x, y));
198   PetscFunctionReturn(PETSC_SUCCESS);
199 }
200 
201 /*@
202   PFViewFromOptions - View a `PF` based on options set in the options database
203 
204   Collective
205 
206   Input Parameters:
207 + A    - the `PF` context
208 . obj  - Optional object that provides the prefix used to search the options database
209 - name - command line option
210 
211   Level: intermediate
212 
213   Note:
214   See `PetscObjectViewFromOptions()` for the variety of viewer options available
215 
216 .seealso: `PF`, `PFView`, `PetscObjectViewFromOptions()`, `PFCreate()`
217 @*/
218 PetscErrorCode PFViewFromOptions(PF A, PetscObject obj, const char name[])
219 {
220   PetscFunctionBegin;
221   PetscValidHeaderSpecific(A, PF_CLASSID, 1);
222   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
223   PetscFunctionReturn(PETSC_SUCCESS);
224 }
225 
226 /*@
227   PFView - Prints information about a mathematical function
228 
229   Collective unless `viewer` is `PETSC_VIEWER_STDOUT_SELF`
230 
231   Input Parameters:
232 + pf     - the `PF` context
233 - viewer - optional visualization context
234 
235   Level: developer
236 
237   Note:
238   The available visualization contexts include
239 +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
240 -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
241   output where only the first processor opens
242   the file.  All other processors send their
243   data to the first processor to print.
244 
245   The user can open an alternative visualization contexts with
246   `PetscViewerASCIIOpen()` (output to a specified file).
247 
248 .seealso: `PF`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`
249 @*/
250 PetscErrorCode PFView(PF pf, PetscViewer viewer)
251 {
252   PetscBool         isascii;
253   PetscViewerFormat format;
254 
255   PetscFunctionBegin;
256   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
257   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)pf), &viewer));
258   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
259   PetscCheckSameComm(pf, 1, viewer, 2);
260 
261   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
262   if (isascii) {
263     PetscCall(PetscViewerGetFormat(viewer, &format));
264     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)pf, viewer));
265     if (pf->ops->view) {
266       PetscCall(PetscViewerASCIIPushTab(viewer));
267       PetscCallBack("PF callback view", (*pf->ops->view)(pf->data, viewer));
268       PetscCall(PetscViewerASCIIPopTab(viewer));
269     }
270   }
271   PetscFunctionReturn(PETSC_SUCCESS);
272 }
273 
274 /*@C
275   PFRegister - Adds a method to the mathematical function package.
276 
277   Not Collective
278 
279   Input Parameters:
280 + sname    - name of a new user-defined solver
281 - function - routine to create method context
282 
283   Example Usage:
284 .vb
285    PFRegister("my_function", MyFunctionSetCreate);
286 .ve
287 
288   Then, your solver can be chosen with the procedural interface via
289 .vb
290   PFSetType(pf, "my_function")
291 .ve
292   or at runtime via the option
293 .vb
294   -pf_type my_function
295 .ve
296 
297   Level: advanced
298 
299   Note:
300   `PFRegister()` may be called multiple times to add several user-defined functions
301 
302 .seealso: `PF`, `PFRegisterAll()`, `PFRegisterDestroy()`
303 @*/
304 PetscErrorCode PFRegister(const char sname[], PetscErrorCode (*function)(PF, void *))
305 {
306   PetscFunctionBegin;
307   PetscCall(PFInitializePackage());
308   PetscCall(PetscFunctionListAdd(&PFList, sname, function));
309   PetscFunctionReturn(PETSC_SUCCESS);
310 }
311 
312 /*@
313   PFGetType - Gets the `PFType` name (as a string) from the `PF`
314   context.
315 
316   Not Collective
317 
318   Input Parameter:
319 . pf - the function context
320 
321   Output Parameter:
322 . type - name of function
323 
324   Level: intermediate
325 
326 .seealso: `PF`, `PFSetType()`
327 @*/
328 PetscErrorCode PFGetType(PF pf, PFType *type)
329 {
330   PetscFunctionBegin;
331   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
332   PetscAssertPointer(type, 2);
333   *type = ((PetscObject)pf)->type_name;
334   PetscFunctionReturn(PETSC_SUCCESS);
335 }
336 
337 /*@
338   PFSetType - Builds `PF` for a particular function
339 
340   Collective
341 
342   Input Parameters:
343 + pf   - the function context.
344 . type - a known method
345 - ctx  - optional type dependent context
346 
347   Options Database Key:
348 . -pf_type <type> - Sets PF type
349 
350   Level: intermediate
351 
352   Note:
353   See "petsc/include/petscpf.h" for available methods (for instance, `PFCONSTANT`)
354 
355 .seealso: `PF`, `PFSet()`, `PFRegister()`, `PFCreate()`, `DMDACreatePF()`
356 @*/
357 PetscErrorCode PFSetType(PF pf, PFType type, PetscCtx ctx)
358 {
359   PetscBool match;
360   PetscErrorCode (*r)(PF, void *);
361 
362   PetscFunctionBegin;
363   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
364   PetscAssertPointer(type, 2);
365 
366   PetscCall(PetscObjectTypeCompare((PetscObject)pf, type, &match));
367   if (match) PetscFunctionReturn(PETSC_SUCCESS);
368 
369   PetscTryTypeMethod(pf, destroy);
370   pf->data = NULL;
371 
372   /* Determine the PFCreateXXX routine for a particular function */
373   PetscCall(PetscFunctionListFind(PFList, type, &r));
374   PetscCheck(r, PetscObjectComm((PetscObject)pf), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested PF type %s", type);
375   pf->ops->destroy  = NULL;
376   pf->ops->view     = NULL;
377   pf->ops->apply    = NULL;
378   pf->ops->applyvec = NULL;
379 
380   /* Call the PFCreateXXX routine for this particular function */
381   PetscCall((*r)(pf, ctx));
382 
383   PetscCall(PetscObjectChangeTypeName((PetscObject)pf, type));
384   PetscFunctionReturn(PETSC_SUCCESS);
385 }
386 
387 /*@
388   PFSetFromOptions - Sets `PF` options from the options database.
389 
390   Collective
391 
392   Input Parameters:
393 . pf - the mathematical function context
394 
395   Level: intermediate
396 
397   Notes:
398   To see all options, run your program with the -help option
399   or consult the users manual.
400 
401 .seealso: `PF`
402 @*/
403 PetscErrorCode PFSetFromOptions(PF pf)
404 {
405   char      type[256];
406   PetscBool flg;
407 
408   PetscFunctionBegin;
409   PetscValidHeaderSpecific(pf, PF_CLASSID, 1);
410 
411   PetscObjectOptionsBegin((PetscObject)pf);
412   PetscCall(PetscOptionsFList("-pf_type", "Type of function", "PFSetType", PFList, NULL, type, 256, &flg));
413   if (flg) PetscCall(PFSetType(pf, type, NULL));
414   PetscTryTypeMethod(pf, setfromoptions, PetscOptionsObject);
415 
416   /* process any options handlers added with PetscObjectAddOptionsHandler() */
417   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)pf, PetscOptionsObject));
418   PetscOptionsEnd();
419   PetscFunctionReturn(PETSC_SUCCESS);
420 }
421 
422 static PetscBool PFPackageInitialized = PETSC_FALSE;
423 
424 /*@C
425   PFFinalizePackage - This function destroys everything in the PETSc `PF` package. It is
426   called from `PetscFinalize()`.
427 
428   Level: developer
429 
430 .seealso: `PF`, `PetscFinalize()`
431 @*/
432 PetscErrorCode PFFinalizePackage(void)
433 {
434   PetscFunctionBegin;
435   PetscCall(PetscFunctionListDestroy(&PFList));
436   PFPackageInitialized = PETSC_FALSE;
437   PFRegisterAllCalled  = PETSC_FALSE;
438   PetscFunctionReturn(PETSC_SUCCESS);
439 }
440 
441 /*@C
442   PFInitializePackage - This function initializes everything in the `PF` package. It is called
443   from PetscDLLibraryRegister_petscvec() when using dynamic libraries, and on the first call to `PFCreate()`
444   when using shared or static libraries.
445 
446   Level: developer
447 
448 .seealso: `PF`, `PetscInitialize()`
449 @*/
450 PetscErrorCode PFInitializePackage(void)
451 {
452   char      logList[256];
453   PetscBool opt, pkg;
454 
455   PetscFunctionBegin;
456   if (PFPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
457   PFPackageInitialized = PETSC_TRUE;
458   /* Register Classes */
459   PetscCall(PetscClassIdRegister("PointFunction", &PF_CLASSID));
460   /* Register Constructors */
461   PetscCall(PFRegisterAll());
462   /* Process Info */
463   {
464     PetscClassId classids[1];
465 
466     classids[0] = PF_CLASSID;
467     PetscCall(PetscInfoProcessClass("pf", 1, classids));
468   }
469   /* Process summary exclusions */
470   PetscCall(PetscOptionsGetString(NULL, NULL, "-log_exclude", logList, sizeof(logList), &opt));
471   if (opt) {
472     PetscCall(PetscStrInList("pf", logList, ',', &pkg));
473     if (pkg) PetscCall(PetscLogEventExcludeClass(PF_CLASSID));
474   }
475   /* Register package finalizer */
476   PetscCall(PetscRegisterFinalize(PFFinalizePackage));
477   PetscFunctionReturn(PETSC_SUCCESS);
478 }
479