Actual source code: fncombine.c

slepc-3.18.0 2022-10-01
Report Typos and Errors
  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: }