Date: 2022-10-01T06:39:05+00:00

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: }