LCOV - code coverage report
Current view: top level - nep/tutorials - ex21.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 172 191 90.1 %
Date: 2024-11-21 00:34:55 Functions: 9 10 90.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             : static char help[] = "Simple 1-D nonlinear eigenproblem (matrix-free version).\n\n"
      12             :   "The command line options are:\n"
      13             :   "  -n <n>, where <n> = number of grid subdivisions\n\n";
      14             : 
      15             : /*
      16             :    Solve 1-D PDE
      17             :             -u'' = lambda*u
      18             :    on [0,1] subject to
      19             :             u(0)=0, u'(1)=u(1)*lambda*kappa/(kappa-lambda)
      20             : */
      21             : 
      22             : #include <slepcnep.h>
      23             : 
      24             : /*
      25             :    User-defined routines
      26             : */
      27             : PetscErrorCode FormFunction(NEP,PetscScalar,Mat,Mat,void*);
      28             : PetscErrorCode FormJacobian(NEP,PetscScalar,Mat,void*);
      29             : 
      30             : /*
      31             :    Matrix operations and context
      32             : */
      33             : PetscErrorCode MatMult_Fun(Mat,Vec,Vec);
      34             : PetscErrorCode MatGetDiagonal_Fun(Mat,Vec);
      35             : PetscErrorCode MatDestroy_Fun(Mat);
      36             : PetscErrorCode MatDuplicate_Fun(Mat,MatDuplicateOption,Mat*);
      37             : PetscErrorCode MatMult_Jac(Mat,Vec,Vec);
      38             : PetscErrorCode MatGetDiagonal_Jac(Mat,Vec);
      39             : PetscErrorCode MatDestroy_Jac(Mat);
      40             : 
      41             : typedef struct {
      42             :   PetscScalar lambda,kappa;
      43             :   PetscReal   h;
      44             :   PetscMPIInt next,prev;
      45             : } MatCtx;
      46             : 
      47             : /*
      48             :    User-defined application context
      49             : */
      50             : typedef struct {
      51             :   PetscScalar kappa;   /* ratio between stiffness of spring and attached mass */
      52             :   PetscReal   h;       /* mesh spacing */
      53             : } ApplicationCtx;
      54             : 
      55           6 : int main(int argc,char **argv)
      56             : {
      57           6 :   NEP            nep;             /* nonlinear eigensolver context */
      58           6 :   Mat            F,J;             /* Function and Jacobian matrices */
      59           6 :   ApplicationCtx ctx;             /* user-defined context */
      60           6 :   MatCtx         *ctxF,*ctxJ;     /* contexts for shell matrices */
      61           6 :   PetscInt       n=128,nev;
      62           6 :   KSP            ksp;
      63           6 :   PC             pc;
      64           6 :   PetscMPIInt    rank,size;
      65           6 :   PetscBool      terse;
      66             : 
      67           6 :   PetscFunctionBeginUser;
      68           6 :   PetscCall(SlepcInitialize(&argc,&argv,NULL,help));
      69           6 :   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
      70           6 :   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
      71           6 :   PetscCall(PetscOptionsGetInt(NULL,NULL,"-n",&n,NULL));
      72           6 :   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\n1-D Nonlinear Eigenproblem, n=%" PetscInt_FMT "\n\n",n));
      73           6 :   ctx.h = 1.0/(PetscReal)n;
      74           6 :   ctx.kappa = 1.0;
      75             : 
      76             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      77             :      Create nonlinear eigensolver context
      78             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
      79             : 
      80           6 :   PetscCall(NEPCreate(PETSC_COMM_WORLD,&nep));
      81             : 
      82             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      83             :      Create matrix data structure; set Function evaluation routine
      84             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
      85             : 
      86           6 :   PetscCall(PetscNew(&ctxF));
      87           6 :   ctxF->h = ctx.h;
      88           6 :   ctxF->kappa = ctx.kappa;
      89           6 :   ctxF->next = rank==size-1? MPI_PROC_NULL: rank+1;
      90           6 :   ctxF->prev = rank==0? MPI_PROC_NULL: rank-1;
      91             : 
      92           6 :   PetscCall(MatCreateShell(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,n,n,(void*)ctxF,&F));
      93           6 :   PetscCall(MatShellSetOperation(F,MATOP_MULT,(void(*)(void))MatMult_Fun));
      94           6 :   PetscCall(MatShellSetOperation(F,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Fun));
      95           6 :   PetscCall(MatShellSetOperation(F,MATOP_DESTROY,(void(*)(void))MatDestroy_Fun));
      96           6 :   PetscCall(MatShellSetOperation(F,MATOP_DUPLICATE,(void(*)(void))MatDuplicate_Fun));
      97             : 
      98             :   /*
      99             :      Set Function matrix data structure and default Function evaluation
     100             :      routine
     101             :   */
     102           6 :   PetscCall(NEPSetFunction(nep,F,F,FormFunction,NULL));
     103             : 
     104             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     105             :      Create matrix data structure; set Jacobian evaluation routine
     106             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     107             : 
     108           6 :   PetscCall(PetscNew(&ctxJ));
     109           6 :   ctxJ->h = ctx.h;
     110           6 :   ctxJ->kappa = ctx.kappa;
     111           6 :   ctxJ->next = rank==size-1? MPI_PROC_NULL: rank+1;
     112           6 :   ctxJ->prev = rank==0? MPI_PROC_NULL: rank-1;
     113             : 
     114           6 :   PetscCall(MatCreateShell(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,n,n,(void*)ctxJ,&J));
     115           6 :   PetscCall(MatShellSetOperation(J,MATOP_MULT,(void(*)(void))MatMult_Jac));
     116           6 :   PetscCall(MatShellSetOperation(J,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Jac));
     117           6 :   PetscCall(MatShellSetOperation(J,MATOP_DESTROY,(void(*)(void))MatDestroy_Jac));
     118             : 
     119             :   /*
     120             :      Set Jacobian matrix data structure and default Jacobian evaluation
     121             :      routine
     122             :   */
     123           6 :   PetscCall(NEPSetJacobian(nep,J,FormJacobian,NULL));
     124             : 
     125             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     126             :      Customize nonlinear solver; set runtime options
     127             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     128             : 
     129           6 :   PetscCall(NEPSetType(nep,NEPRII));
     130           6 :   PetscCall(NEPRIISetLagPreconditioner(nep,0));
     131           6 :   PetscCall(NEPRIIGetKSP(nep,&ksp));
     132           6 :   PetscCall(KSPSetType(ksp,KSPBCGS));
     133           6 :   PetscCall(KSPGetPC(ksp,&pc));
     134           6 :   PetscCall(PCSetType(pc,PCJACOBI));
     135             : 
     136             :   /*
     137             :      Set solver parameters at runtime
     138             :   */
     139           6 :   PetscCall(NEPSetFromOptions(nep));
     140             : 
     141             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     142             :                       Solve the eigensystem
     143             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     144             : 
     145           6 :   PetscCall(NEPSolve(nep));
     146           6 :   PetscCall(NEPGetDimensions(nep,&nev,NULL,NULL));
     147           6 :   PetscCall(PetscPrintf(PETSC_COMM_WORLD," Number of requested eigenvalues: %" PetscInt_FMT "\n",nev));
     148             : 
     149             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     150             :                     Display solution and clean up
     151             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     152             : 
     153             :   /* show detailed info unless -terse option is given by user */
     154           6 :   PetscCall(PetscOptionsHasName(NULL,NULL,"-terse",&terse));
     155           6 :   if (terse) PetscCall(NEPErrorView(nep,NEP_ERROR_RELATIVE,NULL));
     156             :   else {
     157           0 :     PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO_DETAIL));
     158           0 :     PetscCall(NEPConvergedReasonView(nep,PETSC_VIEWER_STDOUT_WORLD));
     159           0 :     PetscCall(NEPErrorView(nep,NEP_ERROR_RELATIVE,PETSC_VIEWER_STDOUT_WORLD));
     160           0 :     PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
     161             :   }
     162           6 :   PetscCall(NEPDestroy(&nep));
     163           6 :   PetscCall(MatDestroy(&F));
     164           6 :   PetscCall(MatDestroy(&J));
     165           6 :   PetscCall(SlepcFinalize());
     166             :   return 0;
     167             : }
     168             : 
     169             : /* ------------------------------------------------------------------- */
     170             : /*
     171             :    FormFunction - Computes Function matrix  T(lambda)
     172             : 
     173             :    Input Parameters:
     174             : .  nep    - the NEP context
     175             : .  lambda - real part of the scalar argument
     176             : .  ctx    - optional user-defined context, as set by NEPSetFunction()
     177             : 
     178             :    Output Parameters:
     179             : .  fun - Function matrix
     180             : .  B   - optionally different preconditioning matrix
     181             : */
     182          90 : PetscErrorCode FormFunction(NEP nep,PetscScalar lambda,Mat fun,Mat B,void *ctx)
     183             : {
     184          90 :   MatCtx         *ctxF;
     185             : 
     186          90 :   PetscFunctionBeginUser;
     187          90 :   PetscCall(MatShellGetContext(fun,&ctxF));
     188          90 :   ctxF->lambda = lambda;
     189          90 :   PetscFunctionReturn(PETSC_SUCCESS);
     190             : }
     191             : 
     192             : /* ------------------------------------------------------------------- */
     193             : /*
     194             :    FormJacobian - Computes Jacobian matrix  T'(lambda)
     195             : 
     196             :    Input Parameters:
     197             : .  nep    - the NEP context
     198             : .  lambda - real part of the scalar argument
     199             : .  ctx    - optional user-defined context, as set by NEPSetJacobian()
     200             : 
     201             :    Output Parameters:
     202             : .  jac - Jacobian matrix
     203             : */
     204          75 : PetscErrorCode FormJacobian(NEP nep,PetscScalar lambda,Mat jac,void *ctx)
     205             : {
     206          75 :   MatCtx         *ctxJ;
     207             : 
     208          75 :   PetscFunctionBeginUser;
     209          75 :   PetscCall(MatShellGetContext(jac,&ctxJ));
     210          75 :   ctxJ->lambda = lambda;
     211          75 :   PetscFunctionReturn(PETSC_SUCCESS);
     212             : }
     213             : 
     214             : /* ------------------------------------------------------------------- */
     215       74547 : PetscErrorCode MatMult_Fun(Mat A,Vec x,Vec y)
     216             : {
     217       74547 :   MatCtx            *ctx;
     218       74547 :   PetscInt          i,n,N;
     219       74547 :   const PetscScalar *px;
     220       74547 :   PetscScalar       *py,c,d,de,oe,upper=0.0,lower=0.0;
     221       74547 :   PetscReal         h;
     222       74547 :   MPI_Comm          comm;
     223             : 
     224       74547 :   PetscFunctionBeginUser;
     225       74547 :   PetscCall(MatShellGetContext(A,&ctx));
     226       74547 :   PetscCall(VecGetArrayRead(x,&px));
     227       74547 :   PetscCall(VecGetArray(y,&py));
     228       74547 :   PetscCall(VecGetSize(x,&N));
     229       74547 :   PetscCall(VecGetLocalSize(x,&n));
     230             : 
     231       74547 :   PetscCall(PetscObjectGetComm((PetscObject)A,&comm));
     232       74547 :   PetscCallMPI(MPI_Sendrecv(px,1,MPIU_SCALAR,ctx->prev,0,&lower,1,MPIU_SCALAR,ctx->next,0,comm,MPI_STATUS_IGNORE));
     233       74547 :   PetscCallMPI(MPI_Sendrecv(px+n-1,1,MPIU_SCALAR,ctx->next,0,&upper,1,MPIU_SCALAR,ctx->prev,0,comm,MPI_STATUS_IGNORE));
     234             : 
     235       74547 :   h = ctx->h;
     236       74547 :   c = ctx->kappa/(ctx->lambda-ctx->kappa);
     237       74547 :   d = N;
     238       74547 :   de = 2.0*(d-ctx->lambda*h/3.0);   /* diagonal entry */
     239       74547 :   oe = -d-ctx->lambda*h/6.0;        /* offdiagonal entry */
     240       74547 :   py[0] = oe*upper + de*px[0] + oe*px[1];
     241     6426189 :   for (i=1;i<n-1;i++) py[i] = oe*px[i-1] +de*px[i] + oe*px[i+1];
     242       74547 :   if (ctx->next==MPI_PROC_NULL) de = d-ctx->lambda*h/3.0+ctx->lambda*c;   /* diagonal entry of last row */
     243       74547 :   py[n-1] = oe*px[n-2] + de*px[n-1] + oe*lower;
     244             : 
     245       74547 :   PetscCall(VecRestoreArrayRead(x,&px));
     246       74547 :   PetscCall(VecRestoreArray(y,&py));
     247       74547 :   PetscFunctionReturn(PETSC_SUCCESS);
     248             : }
     249             : 
     250             : /* ------------------------------------------------------------------- */
     251           6 : PetscErrorCode MatGetDiagonal_Fun(Mat A,Vec diag)
     252             : {
     253           6 :   MatCtx         *ctx;
     254           6 :   PetscInt       n,N;
     255           6 :   PetscScalar    *pd,c,d;
     256           6 :   PetscReal      h;
     257             : 
     258           6 :   PetscFunctionBeginUser;
     259           6 :   PetscCall(MatShellGetContext(A,&ctx));
     260           6 :   PetscCall(VecGetSize(diag,&N));
     261           6 :   PetscCall(VecGetLocalSize(diag,&n));
     262           6 :   h = ctx->h;
     263           6 :   c = ctx->kappa/(ctx->lambda-ctx->kappa);
     264           6 :   d = N;
     265           6 :   PetscCall(VecSet(diag,2.0*(d-ctx->lambda*h/3.0)));
     266           6 :   PetscCall(VecGetArray(diag,&pd));
     267           6 :   pd[n-1] = d-ctx->lambda*h/3.0+ctx->lambda*c;
     268           6 :   PetscCall(VecRestoreArray(diag,&pd));
     269           6 :   PetscFunctionReturn(PETSC_SUCCESS);
     270             : }
     271             : 
     272             : /* ------------------------------------------------------------------- */
     273           9 : PetscErrorCode MatDestroy_Fun(Mat A)
     274             : {
     275           9 :   MatCtx         *ctx;
     276             : 
     277           9 :   PetscFunctionBegin;
     278           9 :   PetscCall(MatShellGetContext(A,&ctx));
     279           9 :   PetscCall(PetscFree(ctx));
     280           9 :   PetscFunctionReturn(PETSC_SUCCESS);
     281             : }
     282             : 
     283             : /* ------------------------------------------------------------------- */
     284           3 : PetscErrorCode MatDuplicate_Fun(Mat A,MatDuplicateOption op,Mat *B)
     285             : {
     286           3 :   MatCtx         *actx,*bctx;
     287           3 :   PetscInt       m,n,M,N;
     288           3 :   MPI_Comm       comm;
     289             : 
     290           3 :   PetscFunctionBegin;
     291           3 :   PetscCall(MatShellGetContext(A,&actx));
     292           3 :   PetscCall(MatGetSize(A,&M,&N));
     293           3 :   PetscCall(MatGetLocalSize(A,&m,&n));
     294             : 
     295           3 :   PetscCall(PetscNew(&bctx));
     296           3 :   bctx->h      = actx->h;
     297           3 :   bctx->kappa  = actx->kappa;
     298           3 :   bctx->lambda = actx->lambda;
     299           3 :   bctx->next   = actx->next;
     300           3 :   bctx->prev   = actx->prev;
     301             : 
     302           3 :   PetscCall(PetscObjectGetComm((PetscObject)A,&comm));
     303           3 :   PetscCall(MatCreateShell(comm,m,n,M,N,(void*)bctx,B));
     304           3 :   PetscCall(MatShellSetOperation(*B,MATOP_MULT,(void(*)(void))MatMult_Fun));
     305           3 :   PetscCall(MatShellSetOperation(*B,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Fun));
     306           3 :   PetscCall(MatShellSetOperation(*B,MATOP_DESTROY,(void(*)(void))MatDestroy_Fun));
     307           3 :   PetscCall(MatShellSetOperation(*B,MATOP_DUPLICATE,(void(*)(void))MatDuplicate_Fun));
     308           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     309             : }
     310             : 
     311             : /* ------------------------------------------------------------------- */
     312         210 : PetscErrorCode MatMult_Jac(Mat A,Vec x,Vec y)
     313             : {
     314         210 :   MatCtx            *ctx;
     315         210 :   PetscInt          i,n;
     316         210 :   const PetscScalar *px;
     317         210 :   PetscScalar       *py,c,de,oe,upper=0.0,lower=0.0;
     318         210 :   PetscReal         h;
     319         210 :   MPI_Comm          comm;
     320             : 
     321         210 :   PetscFunctionBeginUser;
     322         210 :   PetscCall(MatShellGetContext(A,&ctx));
     323         210 :   PetscCall(VecGetArrayRead(x,&px));
     324         210 :   PetscCall(VecGetArray(y,&py));
     325         210 :   PetscCall(VecGetLocalSize(x,&n));
     326             : 
     327         210 :   PetscCall(PetscObjectGetComm((PetscObject)A,&comm));
     328         210 :   PetscCallMPI(MPI_Sendrecv(px,1,MPIU_SCALAR,ctx->prev,0,&lower,1,MPIU_SCALAR,ctx->next,0,comm,MPI_STATUS_IGNORE));
     329         210 :   PetscCallMPI(MPI_Sendrecv(px+n-1,1,MPIU_SCALAR,ctx->next,0,&upper,1,MPIU_SCALAR,ctx->prev,0,comm,MPI_STATUS_IGNORE));
     330             : 
     331         210 :   h = ctx->h;
     332         210 :   c = ctx->kappa/(ctx->lambda-ctx->kappa);
     333         210 :   de = -2.0*h/3.0;    /* diagonal entry */
     334         210 :   oe = -h/6.0;        /* offdiagonal entry */
     335         210 :   py[0] = oe*upper + de*px[0] + oe*px[1];
     336       18094 :   for (i=1;i<n-1;i++) py[i] = oe*px[i-1] +de*px[i] + oe*px[i+1];
     337         210 :   if (ctx->next==MPI_PROC_NULL) de = -h/3.0-c*c;    /* diagonal entry of last row */
     338         210 :   py[n-1] = oe*px[n-2] + de*px[n-1] + oe*lower;
     339             : 
     340         210 :   PetscCall(VecRestoreArrayRead(x,&px));
     341         210 :   PetscCall(VecRestoreArray(y,&py));
     342         210 :   PetscFunctionReturn(PETSC_SUCCESS);
     343             : }
     344             : 
     345             : /* ------------------------------------------------------------------- */
     346           0 : PetscErrorCode MatGetDiagonal_Jac(Mat A,Vec diag)
     347             : {
     348           0 :   MatCtx         *ctx;
     349           0 :   PetscInt       n;
     350           0 :   PetscScalar    *pd,c;
     351           0 :   PetscReal      h;
     352             : 
     353           0 :   PetscFunctionBeginUser;
     354           0 :   PetscCall(MatShellGetContext(A,&ctx));
     355           0 :   PetscCall(VecGetLocalSize(diag,&n));
     356           0 :   h = ctx->h;
     357           0 :   c = ctx->kappa/(ctx->lambda-ctx->kappa);
     358           0 :   PetscCall(VecSet(diag,-2.0*h/3.0));
     359           0 :   PetscCall(VecGetArray(diag,&pd));
     360           0 :   pd[n-1] = -h/3.0-c*c;
     361           0 :   PetscCall(VecRestoreArray(diag,&pd));
     362           0 :   PetscFunctionReturn(PETSC_SUCCESS);
     363             : }
     364             : 
     365             : /* ------------------------------------------------------------------- */
     366           6 : PetscErrorCode MatDestroy_Jac(Mat A)
     367             : {
     368           6 :   MatCtx         *ctx;
     369             : 
     370           6 :   PetscFunctionBegin;
     371           6 :   PetscCall(MatShellGetContext(A,&ctx));
     372           6 :   PetscCall(PetscFree(ctx));
     373           6 :   PetscFunctionReturn(PETSC_SUCCESS);
     374             : }
     375             : 
     376             : /*TEST
     377             : 
     378             :    testset:
     379             :       nsize: {{1 2}}
     380             :       args: -terse
     381             :       requires: !single
     382             :       output_file: output/ex21_1.out
     383             :       filter: sed -e "s/[+-]0\.0*i//g" -e "s/+0i//g"
     384             :       test:
     385             :          suffix: 1_rii
     386             :          args: -nep_type rii -nep_target 4
     387             :       test:
     388             :          suffix: 1_slp
     389             :          args: -nep_type slp -nep_slp_pc_type jacobi -nep_slp_ksp_type bcgs -nep_target 10
     390             : 
     391             : TEST*/

Generated by: LCOV version 1.14