Actual source code: fncombine.c
slepc-3.18.0 2022-10-01
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: A function that is obtained by combining two other functions (either by
12: addition, multiplication, division or composition)
14: addition: f(x) = f1(x)+f2(x)
15: multiplication: f(x) = f1(x)*f2(x)
16: division: f(x) = f1(x)/f2(x) f(A) = f2(A)\f1(A)
17: composition: f(x) = f2(f1(x))
18: */
20: #include <slepc/private/fnimpl.h>
22: typedef struct {
23: FN f1,f2; /* functions */
24: FNCombineType comb; /* how the functions are combined */
25: } FN_COMBINE;
27: PetscErrorCode FNEvaluateFunction_Combine(FN fn,PetscScalar x,PetscScalar *y)
28: {
29: FN_COMBINE *ctx = (FN_COMBINE*)fn->data;
30: PetscScalar a,b;
32: FNEvaluateFunction(ctx->f1,x,&a);
33: switch (ctx->comb) {
34: case FN_COMBINE_ADD:
35: FNEvaluateFunction(ctx->f2,x,&b);
36: *y = a+b;
37: break;
38: case FN_COMBINE_MULTIPLY:
39: FNEvaluateFunction(ctx->f2,x,&b);
40: *y = a*b;
41: break;
42: case FN_COMBINE_DIVIDE:
43: FNEvaluateFunction(ctx->f2,x,&b);
45: *y = a/b;
46: break;
47: case FN_COMBINE_COMPOSE:
48: FNEvaluateFunction(ctx->f2,a,y);
49: break;
50: }
51: return 0;
52: }
54: PetscErrorCode FNEvaluateDerivative_Combine(FN fn,PetscScalar x,PetscScalar *yp)
55: {
56: FN_COMBINE *ctx = (FN_COMBINE*)fn->data;
57: PetscScalar a,b,ap,bp;
59: switch (ctx->comb) {
60: case FN_COMBINE_ADD:
61: FNEvaluateDerivative(ctx->f1,x,&ap);
62: FNEvaluateDerivative(ctx->f2,x,&bp);
63: *yp = ap+bp;
64: break;
65: case FN_COMBINE_MULTIPLY:
66: FNEvaluateDerivative(ctx->f1,x,&ap);
67: FNEvaluateDerivative(ctx->f2,x,&bp);
68: FNEvaluateFunction(ctx->f1,x,&a);
69: FNEvaluateFunction(ctx->f2,x,&b);
70: *yp = ap*b+a*bp;
71: break;
72: case FN_COMBINE_DIVIDE:
73: FNEvaluateDerivative(ctx->f1,x,&ap);
74: FNEvaluateDerivative(ctx->f2,x,&bp);
75: FNEvaluateFunction(ctx->f1,x,&a);
76: FNEvaluateFunction(ctx->f2,x,&b);
78: *yp = (ap*b-a*bp)/(b*b);
79: break;
80: case FN_COMBINE_COMPOSE:
81: FNEvaluateFunction(ctx->f1,x,&a);
82: FNEvaluateDerivative(ctx->f1,x,&ap);
83: FNEvaluateDerivative(ctx->f2,a,yp);
84: *yp *= ap;
85: break;
86: }
87: return 0;
88: }
90: PetscErrorCode FNEvaluateFunctionMat_Combine(FN fn,Mat A,Mat B)
91: {
92: FN_COMBINE *ctx = (FN_COMBINE*)fn->data;
93: Mat W,Z,F;
94: PetscBool iscuda;
96: FN_AllocateWorkMat(fn,A,&W);
97: switch (ctx->comb) {
98: case FN_COMBINE_ADD:
99: FNEvaluateFunctionMat_Private(ctx->f1,A,W,PETSC_FALSE);
100: FNEvaluateFunctionMat_Private(ctx->f2,A,B,PETSC_FALSE);
101: MatAXPY(B,1.0,W,SAME_NONZERO_PATTERN);
102: break;
103: case FN_COMBINE_MULTIPLY:
104: FN_AllocateWorkMat(fn,A,&Z);
105: FNEvaluateFunctionMat_Private(ctx->f1,A,W,PETSC_FALSE);
106: FNEvaluateFunctionMat_Private(ctx->f2,A,Z,PETSC_FALSE);
107: MatMatMult(W,Z,MAT_REUSE_MATRIX,PETSC_DEFAULT,&B);
108: FN_FreeWorkMat(fn,&Z);
109: break;
110: case FN_COMBINE_DIVIDE:
111: FNEvaluateFunctionMat_Private(ctx->f2,A,W,PETSC_FALSE);
112: FNEvaluateFunctionMat_Private(ctx->f1,A,B,PETSC_FALSE);
113: PetscObjectTypeCompare((PetscObject)A,MATSEQDENSECUDA,&iscuda);
114: MatGetFactor(W,iscuda?MATSOLVERCUDA:MATSOLVERPETSC,MAT_FACTOR_LU,&F);
115: MatLUFactorSymbolic(F,W,NULL,NULL,NULL);
116: MatLUFactorNumeric(F,W,NULL);
117: MatMatSolve(F,B,B);
118: MatDestroy(&F);
119: break;
120: case FN_COMBINE_COMPOSE:
121: FNEvaluateFunctionMat_Private(ctx->f1,A,W,PETSC_FALSE);
122: FNEvaluateFunctionMat_Private(ctx->f2,W,B,PETSC_FALSE);
123: break;
124: }
125: FN_FreeWorkMat(fn,&W);
126: return 0;
127: }
129: PetscErrorCode FNEvaluateFunctionMatVec_Combine(FN fn,Mat A,Vec v)
130: {
131: FN_COMBINE *ctx = (FN_COMBINE*)fn->data;
132: PetscBool iscuda;
133: Mat Z,F;
134: Vec w;
136: switch (ctx->comb) {
137: case FN_COMBINE_ADD:
138: VecDuplicate(v,&w);
139: FNEvaluateFunctionMatVec_Private(ctx->f1,A,w,PETSC_FALSE);
140: FNEvaluateFunctionMatVec_Private(ctx->f2,A,v,PETSC_FALSE);
141: VecAXPY(v,1.0,w);
142: VecDestroy(&w);
143: break;
144: case FN_COMBINE_MULTIPLY:
145: VecDuplicate(v,&w);
146: FN_AllocateWorkMat(fn,A,&Z);
147: FNEvaluateFunctionMat_Private(ctx->f1,A,Z,PETSC_FALSE);
148: FNEvaluateFunctionMatVec_Private(ctx->f2,A,w,PETSC_FALSE);
149: MatMult(Z,w,v);
150: FN_FreeWorkMat(fn,&Z);
151: VecDestroy(&w);
152: break;
153: case FN_COMBINE_DIVIDE:
154: VecDuplicate(v,&w);
155: FN_AllocateWorkMat(fn,A,&Z);
156: FNEvaluateFunctionMat_Private(ctx->f2,A,Z,PETSC_FALSE);
157: FNEvaluateFunctionMatVec_Private(ctx->f1,A,w,PETSC_FALSE);
158: PetscObjectTypeCompare((PetscObject)A,MATSEQDENSECUDA,&iscuda);
159: MatGetFactor(Z,iscuda?MATSOLVERCUDA:MATSOLVERPETSC,MAT_FACTOR_LU,&F);
160: MatLUFactorSymbolic(F,Z,NULL,NULL,NULL);
161: MatLUFactorNumeric(F,Z,NULL);
162: MatSolve(F,w,v);
163: MatDestroy(&F);
164: FN_FreeWorkMat(fn,&Z);
165: VecDestroy(&w);
166: break;
167: case FN_COMBINE_COMPOSE:
168: FN_AllocateWorkMat(fn,A,&Z);
169: FNEvaluateFunctionMat_Private(ctx->f1,A,Z,PETSC_FALSE);
170: FNEvaluateFunctionMatVec_Private(ctx->f2,Z,v,PETSC_FALSE);
171: FN_FreeWorkMat(fn,&Z);
172: break;
173: }
174: return 0;
175: }
177: PetscErrorCode FNView_Combine(FN fn,PetscViewer viewer)
178: {
179: FN_COMBINE *ctx = (FN_COMBINE*)fn->data;
180: PetscBool isascii;
182: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
183: if (isascii) {
184: switch (ctx->comb) {
185: case FN_COMBINE_ADD:
186: PetscViewerASCIIPrintf(viewer," two added functions f1+f2\n");
187: break;
188: case FN_COMBINE_MULTIPLY:
189: PetscViewerASCIIPrintf(viewer," two multiplied functions f1*f2\n");
190: break;
191: case FN_COMBINE_DIVIDE:
192: PetscViewerASCIIPrintf(viewer," a quotient of two functions f1/f2\n");
193: break;
194: case FN_COMBINE_COMPOSE:
195: PetscViewerASCIIPrintf(viewer," two composed functions f2(f1(.))\n");
196: break;
197: }
198: PetscViewerASCIIPushTab(viewer);
199: FNView(ctx->f1,viewer);
200: FNView(ctx->f2,viewer);
201: PetscViewerASCIIPopTab(viewer);
202: }
203: return 0;
204: }
206: static PetscErrorCode FNCombineSetChildren_Combine(FN fn,FNCombineType comb,FN f1,FN f2)
207: {
208: FN_COMBINE *ctx = (FN_COMBINE*)fn->data;
210: ctx->comb = comb;
211: PetscObjectReference((PetscObject)f1);
212: FNDestroy(&ctx->f1);
213: ctx->f1 = f1;
214: PetscObjectReference((PetscObject)f2);
215: FNDestroy(&ctx->f2);
216: ctx->f2 = f2;
217: return 0;
218: }
220: /*@
221: FNCombineSetChildren - Sets the two child functions that constitute this
222: combined function, and the way they must be combined.
224: Logically Collective on fn
226: Input Parameters:
227: + fn - the math function context
228: . comb - how to combine the functions (addition, multiplication, division or composition)
229: . f1 - first function
230: - f2 - second function
232: Level: intermediate
234: .seealso: FNCombineGetChildren()
235: @*/
236: PetscErrorCode FNCombineSetChildren(FN fn,FNCombineType comb,FN f1,FN f2)
237: {
242: PetscTryMethod(fn,"FNCombineSetChildren_C",(FN,FNCombineType,FN,FN),(fn,comb,f1,f2));
243: return 0;
244: }
246: static PetscErrorCode FNCombineGetChildren_Combine(FN fn,FNCombineType *comb,FN *f1,FN *f2)
247: {
248: FN_COMBINE *ctx = (FN_COMBINE*)fn->data;
250: if (comb) *comb = ctx->comb;
251: if (f1) {
252: if (!ctx->f1) FNCreate(PetscObjectComm((PetscObject)fn),&ctx->f1);
253: *f1 = ctx->f1;
254: }
255: if (f2) {
256: if (!ctx->f2) FNCreate(PetscObjectComm((PetscObject)fn),&ctx->f2);
257: *f2 = ctx->f2;
258: }
259: return 0;
260: }
262: /*@
263: FNCombineGetChildren - Gets the two child functions that constitute this
264: combined function, and the way they are combined.
266: Not Collective
268: Input Parameter:
269: . fn - the math function context
271: Output Parameters:
272: + comb - how to combine the functions (addition, multiplication, division or composition)
273: . f1 - first function
274: - f2 - second function
276: Level: intermediate
278: .seealso: FNCombineSetChildren()
279: @*/
280: PetscErrorCode FNCombineGetChildren(FN fn,FNCombineType *comb,FN *f1,FN *f2)
281: {
283: PetscUseMethod(fn,"FNCombineGetChildren_C",(FN,FNCombineType*,FN*,FN*),(fn,comb,f1,f2));
284: return 0;
285: }
287: PetscErrorCode FNDuplicate_Combine(FN fn,MPI_Comm comm,FN *newfn)
288: {
289: FN_COMBINE *ctx = (FN_COMBINE*)fn->data,*ctx2 = (FN_COMBINE*)(*newfn)->data;
291: ctx2->comb = ctx->comb;
292: FNDuplicate(ctx->f1,comm,&ctx2->f1);
293: FNDuplicate(ctx->f2,comm,&ctx2->f2);
294: return 0;
295: }
297: PetscErrorCode FNDestroy_Combine(FN fn)
298: {
299: FN_COMBINE *ctx = (FN_COMBINE*)fn->data;
301: FNDestroy(&ctx->f1);
302: FNDestroy(&ctx->f2);
303: PetscFree(fn->data);
304: PetscObjectComposeFunction((PetscObject)fn,"FNCombineSetChildren_C",NULL);
305: PetscObjectComposeFunction((PetscObject)fn,"FNCombineGetChildren_C",NULL);
306: return 0;
307: }
309: SLEPC_EXTERN PetscErrorCode FNCreate_Combine(FN fn)
310: {
311: FN_COMBINE *ctx;
313: PetscNew(&ctx);
314: fn->data = (void*)ctx;
316: fn->ops->evaluatefunction = FNEvaluateFunction_Combine;
317: fn->ops->evaluatederivative = FNEvaluateDerivative_Combine;
318: fn->ops->evaluatefunctionmat[0] = FNEvaluateFunctionMat_Combine;
319: fn->ops->evaluatefunctionmatvec[0] = FNEvaluateFunctionMatVec_Combine;
320: #if defined(PETSC_HAVE_CUDA)
321: fn->ops->evaluatefunctionmatcuda[0] = FNEvaluateFunctionMat_Combine;
322: fn->ops->evaluatefunctionmatveccuda[0] = FNEvaluateFunctionMatVec_Combine;
323: #endif
324: fn->ops->view = FNView_Combine;
325: fn->ops->duplicate = FNDuplicate_Combine;
326: fn->ops->destroy = FNDestroy_Combine;
327: PetscObjectComposeFunction((PetscObject)fn,"FNCombineSetChildren_C",FNCombineSetChildren_Combine);
328: PetscObjectComposeFunction((PetscObject)fn,"FNCombineGetChildren_C",FNCombineGetChildren_Combine);
329: return 0;
330: }