LCOV - code coverage report
Current view: top level - sys/classes/fn/impls/combine - fncombine.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 209 211 99.1 %
Date: 2024-12-18 00:51:33 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14