LCOV - code coverage report
Current view: top level - src/petscsolver - PETScDiffusionFDM.C (source / functions) Hit Total Coverage
Test: idaholab/moose external_petsc_solver: #31405 (292dce) with base fef103 Lines: 118 120 98.3 %
Date: 2025-09-04 07:53:02 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include <PETScDiffusionFDM.h>
      11             : 
      12             : /*
      13             :    u_t = uxx + uyy
      14             :    0 < x < 1, 0 < y < 1;
      15             :    At t=0: u(x,y) = exp(c*r*r*r), if r=PetscSqrtReal((x-.5)*(x-.5) + (y-.5)*(y-.5)) < .125
      16             :            u(x,y) = 0.0           if r >= .125
      17             : 
      18             : 
      19             :    Boundary conditions:
      20             :    Drichlet BC:
      21             :    At x=0, x=1, y=0, y=1: u = 0.0
      22             : 
      23             :    Neumann BC:
      24             :    At x=0, x=1: du(x,y,t)/dx = 0
      25             :    At y=0, y=1: du(x,y,t)/dy = 0
      26             : */
      27             : 
      28             : PetscErrorCode
      29         370 : PETScExternalSolverCreate(MPI_Comm comm, TS * ts)
      30             : {
      31             :   DM da;
      32             : 
      33             :   PetscFunctionBeginUser;
      34             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      35             :      Create distributed array (DMDA) to manage parallel grid and vectors
      36             :   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
      37         370 :   LibmeshPetscCallQ(DMDACreate2d(comm,
      38             :                                  DM_BOUNDARY_NONE,
      39             :                                  DM_BOUNDARY_NONE,
      40             :                                  DMDA_STENCIL_STAR,
      41             :                                  11,
      42             :                                  11,
      43             :                                  PETSC_DECIDE,
      44             :                                  PETSC_DECIDE,
      45             :                                  1,
      46             :                                  1,
      47             :                                  NULL,
      48             :                                  NULL,
      49             :                                  &da));
      50         370 :   LibmeshPetscCallQ(DMSetFromOptions(da));
      51         370 :   LibmeshPetscCallQ(DMSetUp(da));
      52             : 
      53             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      54             :      Create timestepping solver context
      55             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
      56         370 :   LibmeshPetscCallQ(TSCreate(comm, ts));
      57         370 :   LibmeshPetscCallQ(TSSetProblemType(*ts, TS_NONLINEAR));
      58         370 :   LibmeshPetscCallQ(TSSetType(*ts, TSBEULER));
      59         370 :   LibmeshPetscCallQ(TSSetDM(*ts, da));
      60         370 :   LibmeshPetscCallQ(DMDestroy(&da));
      61         370 :   LibmeshPetscCallQ(TSSetIFunction(*ts, NULL, FormIFunction, nullptr));
      62             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      63             :    Set Jacobian evaluation routine
      64             :   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
      65         370 :   LibmeshPetscCallQ(TSSetIJacobian(*ts, NULL, NULL, FormIJacobian, NULL));
      66             :   /*
      67             :    * Make it consistent with the original solver
      68             :    * This can be changed during runtime via -ts_dt
      69             :    */
      70         370 :   LibmeshPetscCallQ(TSSetTimeStep(*ts, 0.2));
      71         370 :   LibmeshPetscCallQ(TSSetFromOptions(*ts));
      72         370 :   PetscFunctionReturn(PETSC_SUCCESS);
      73             : }
      74             : 
      75             : PetscErrorCode
      76         749 : PETScExternalSolverDestroy(TS ts)
      77             : {
      78             :   PetscFunctionBeginUser;
      79         749 :   LibmeshPetscCallQ(TSDestroy(&ts));
      80         749 :   PetscFunctionReturn(PETSC_SUCCESS);
      81             : }
      82             : 
      83             : /*
      84             :  * This is a modified version of PETSc/src/ts/examples/tutorials/ex15.c
      85             :  * to demonstrate how MOOSE interact with an external solver package
      86             :  */
      87             : PetscErrorCode
      88        5925 : externalPETScDiffusionFDMSolve(
      89             :     TS ts, Vec u0, Vec u, PetscReal dt, PetscReal time, PetscBool * converged)
      90             : {
      91             :   TSConvergedReason reason;
      92             : #if !PETSC_VERSION_LESS_THAN(3, 8, 0)
      93             :   PetscInt current_step;
      94             : #endif
      95             :   DM da;
      96             : 
      97             :   PetscFunctionBeginUser;
      98             :   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
      99             :   PetscValidType(ts, 1);
     100             :   PetscValidHeaderSpecific(u0, VEC_CLASSID, 2);
     101             :   PetscValidType(u0, 2);
     102             :   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
     103             :   PetscValidType(u, 3);
     104             : #if PETSC_VERSION_LESS_THAN(3, 19, 3)
     105             :   PetscValidPointer(converged, 6);
     106             : #else
     107             :   PetscAssertPointer(converged, 6);
     108             : #endif
     109             : 
     110        5925 :   LibmeshPetscCallQ(TSGetDM(ts, &da));
     111             : 
     112             : #if !PETSC_VERSION_LESS_THAN(3, 7, 0)
     113        5925 :   LibmeshPetscCallQ(PetscOptionsSetValue(NULL, "-ts_monitor", NULL));
     114        5925 :   LibmeshPetscCallQ(PetscOptionsSetValue(NULL, "-snes_monitor", NULL));
     115        5925 :   LibmeshPetscCallQ(PetscOptionsSetValue(NULL, "-ksp_monitor", NULL));
     116             : #else
     117             :   LibmeshPetscCallQ(PetscOptionsSetValue("-ts_monitor", NULL));
     118             :   LibmeshPetscCallQ(PetscOptionsSetValue("-snes_monitor", NULL));
     119             :   LibmeshPetscCallQ(PetscOptionsSetValue("-ksp_monitor", NULL));
     120             : #endif
     121             : 
     122             :   /*ierr = TSSetMaxTime(ts,1.0);CHKERRQ(ierr);*/
     123        5925 :   LibmeshPetscCallQ(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
     124             : 
     125        5925 :   LibmeshPetscCallQ(VecCopy(u0, u));
     126             : 
     127        5925 :   LibmeshPetscCallQ(TSSetSolution(ts, u));
     128        5925 :   LibmeshPetscCallQ(TSSetTimeStep(ts, dt));
     129        5925 :   LibmeshPetscCallQ(TSSetTime(ts, time - dt));
     130             : #if !PETSC_VERSION_LESS_THAN(3, 8, 0)
     131        5925 :   LibmeshPetscCallQ(TSGetStepNumber(ts, &current_step));
     132        5925 :   LibmeshPetscCallQ(TSSetMaxSteps(ts, current_step + 1));
     133             : #else
     134             :   SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "Require PETSc-3.8.x or higher ");
     135             : #endif
     136             :   /*  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     137             :    Sets various TS parameters from user options
     138             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     139        5925 :   LibmeshPetscCallQ(TSSetFromOptions(ts));
     140             :   /*
     141             :    * Let the passed-in dt take the priority
     142             :    */
     143        5925 :   LibmeshPetscCallQ(TSSetTimeStep(ts, dt));
     144             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     145             :      Solve nonlinear system
     146             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     147        5925 :   LibmeshPetscCallQ(TSSolve(ts, u));
     148             : 
     149        5925 :   LibmeshPetscCallQ(TSGetConvergedReason(ts, &reason));
     150        5925 :   *converged = reason > 0 ? PETSC_TRUE : PETSC_FALSE;
     151             : 
     152        5925 :   PetscFunctionReturn(PETSC_SUCCESS);
     153             : }
     154             : 
     155             : /* --------------------------------------------------------------------- */
     156             : /*
     157             :   FormIFunction = Udot - RHSFunction
     158             : */
     159             : PetscErrorCode
     160       17775 : FormIFunction(TS ts, PetscReal /*t*/, Vec U, Vec Udot, Vec F, void * /*ctx*/)
     161             : {
     162             :   DM da;
     163             :   PetscInt i, j, Mx, My, xs, ys, xm, ym;
     164             :   PetscReal hx, hy, sx, sy;
     165             :   PetscScalar u, uxx, uyy, **uarray, **f, **udot;
     166             :   Vec localU;
     167             :   MPI_Comm comm;
     168             : 
     169             :   PetscFunctionBeginUser;
     170       17775 :   LibmeshPetscCallQ(PetscObjectGetComm((PetscObject)ts, &comm));
     171       17775 :   LibmeshPetscCallQ(TSGetDM(ts, &da));
     172       17775 :   LibmeshPetscCallQ(DMGetLocalVector(da, &localU));
     173       17775 :   LibmeshPetscCallQ(DMDAGetInfo(da,
     174             :                                 PETSC_IGNORE,
     175             :                                 &Mx,
     176             :                                 &My,
     177             :                                 PETSC_IGNORE,
     178             :                                 PETSC_IGNORE,
     179             :                                 PETSC_IGNORE,
     180             :                                 PETSC_IGNORE,
     181             :                                 PETSC_IGNORE,
     182             :                                 PETSC_IGNORE,
     183             :                                 PETSC_IGNORE,
     184             :                                 PETSC_IGNORE,
     185             :                                 PETSC_IGNORE,
     186             :                                 PETSC_IGNORE));
     187             : 
     188       17775 :   hx = 1.0 / (PetscReal)(Mx - 1);
     189       17775 :   sx = 1.0 / (hx * hx);
     190       17775 :   hy = 1.0 / (PetscReal)(My - 1);
     191       17775 :   sy = 1.0 / (hy * hy);
     192             : 
     193             :   /*
     194             :      Scatter ghost points to local vector,using the 2-step process
     195             :         DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
     196             :      By placing code between these two statements, computations can be
     197             :      done while messages are in transition.
     198             :   */
     199       17775 :   LibmeshPetscCallQ(DMGlobalToLocalBegin(da, U, INSERT_VALUES, localU));
     200       17775 :   LibmeshPetscCallQ(DMGlobalToLocalEnd(da, U, INSERT_VALUES, localU));
     201             : 
     202             :   /* Get pointers to vector data */
     203       17775 :   LibmeshPetscCallQ(DMDAVecGetArrayRead(da, localU, &uarray));
     204       17775 :   LibmeshPetscCallQ(DMDAVecGetArray(da, F, &f));
     205       17775 :   LibmeshPetscCallQ(DMDAVecGetArray(da, Udot, &udot));
     206             : 
     207             :   /* Get local grid boundaries */
     208       17775 :   LibmeshPetscCallQ(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
     209             : 
     210             :   /* Compute function over the locally owned part of the grid */
     211      124596 :   for (j = ys; j < ys + ym; j++)
     212             :   {
     213     1149720 :     for (i = xs; i < xs + xm; i++)
     214             :     {
     215             :       /* Boundary conditions */
     216     1042899 :       if (i == 0 || j == 0 || i == Mx - 1 || j == My - 1)
     217             :       {
     218      344760 :         if (PETSC_TRUE)
     219             :         {                         /* Drichlet BC */
     220      344760 :           f[j][i] = uarray[j][i]; /* F = U */
     221             :         }
     222             :         else
     223             :         { /* Neumann BC */
     224             :           if (i == 0 && j == 0)
     225             :           { /* SW corner */
     226             :             f[j][i] = uarray[j][i] - uarray[j + 1][i + 1];
     227             :           }
     228             :           else if (i == Mx - 1 && j == 0)
     229             :           { /* SE corner */
     230             :             f[j][i] = uarray[j][i] - uarray[j + 1][i - 1];
     231             :           }
     232             :           else if (i == 0 && j == My - 1)
     233             :           { /* NW corner */
     234             :             f[j][i] = uarray[j][i] - uarray[j - 1][i + 1];
     235             :           }
     236             :           else if (i == Mx - 1 && j == My - 1)
     237             :           { /* NE corner */
     238             :             f[j][i] = uarray[j][i] - uarray[j - 1][i - 1];
     239             :           }
     240             :           else if (i == 0)
     241             :           { /* Left */
     242             :             f[j][i] = uarray[j][i] - uarray[j][i + 1];
     243             :           }
     244             :           else if (i == Mx - 1)
     245             :           { /* Right */
     246             :             f[j][i] = uarray[j][i] - uarray[j][i - 1];
     247             :           }
     248             :           else if (j == 0)
     249             :           { /* Bottom */
     250             :             f[j][i] = uarray[j][i] - uarray[j + 1][i];
     251             :           }
     252             :           else if (j == My - 1)
     253             :           { /* Top */
     254             :             f[j][i] = uarray[j][i] - uarray[j - 1][i];
     255             :           }
     256             :         }
     257             :       }
     258             :       else
     259             :       { /* Interior */
     260      698139 :         u = uarray[j][i];
     261             :         /* 5-point stencil */
     262      698139 :         uxx = (-2.0 * u + uarray[j][i - 1] + uarray[j][i + 1]);
     263      698139 :         uyy = (-2.0 * u + uarray[j - 1][i] + uarray[j + 1][i]);
     264             :         if (PETSC_FALSE)
     265             :         {
     266             :           /* 9-point stencil: assume hx=hy */
     267             :           uxx = 2.0 * uxx / 3.0 + (0.5 * (uarray[j - 1][i - 1] + uarray[j - 1][i + 1] +
     268             :                                           uarray[j + 1][i - 1] + uarray[j + 1][i + 1]) -
     269             :                                    2.0 * u) /
     270             :                                       6.0;
     271             :           uyy = 2.0 * uyy / 3.0 + (0.5 * (uarray[j - 1][i - 1] + uarray[j - 1][i + 1] +
     272             :                                           uarray[j + 1][i - 1] + uarray[j + 1][i + 1]) -
     273             :                                    2.0 * u) /
     274             :                                       6.0;
     275             :         }
     276      698139 :         f[j][i] = udot[j][i] - (uxx * sx + uyy * sy);
     277             :       }
     278             :     }
     279             :   }
     280             : 
     281             :   /* Restore vectors */
     282       17775 :   LibmeshPetscCallQ(DMDAVecRestoreArrayRead(da, localU, &uarray));
     283       17775 :   LibmeshPetscCallQ(DMDAVecRestoreArray(da, F, &f));
     284       17775 :   LibmeshPetscCallQ(DMDAVecRestoreArray(da, Udot, &udot));
     285       17775 :   LibmeshPetscCallQ(DMRestoreLocalVector(da, &localU));
     286       17775 :   LibmeshPetscCallQ(PetscLogFlops(11.0 * ym * xm));
     287       17775 :   PetscFunctionReturn(PETSC_SUCCESS);
     288             : }
     289             : 
     290             : /* --------------------------------------------------------------------- */
     291             : /*
     292             :   FormIJacobian() - Compute IJacobian = dF/dU + a dF/dUdot
     293             :   This routine is not used with option '-use_coloring'
     294             : */
     295             : PetscErrorCode
     296       11850 : FormIJacobian(
     297             :     TS ts, PetscReal /*t*/, Vec /*U*/, Vec /*Udot*/, PetscReal a, Mat J, Mat Jpre, void * /*ctx*/)
     298             : {
     299             :   PetscInt i, j, Mx, My, xs, ys, xm, ym, nc;
     300             :   DM da;
     301             :   MatStencil col[5], row;
     302             :   PetscScalar vals[5], hx, hy, sx, sy;
     303             : 
     304             :   PetscFunctionBeginUser;
     305       11850 :   LibmeshPetscCallQ(TSGetDM(ts, &da));
     306       11850 :   LibmeshPetscCallQ(DMDAGetInfo(da,
     307             :                                 PETSC_IGNORE,
     308             :                                 &Mx,
     309             :                                 &My,
     310             :                                 PETSC_IGNORE,
     311             :                                 PETSC_IGNORE,
     312             :                                 PETSC_IGNORE,
     313             :                                 PETSC_IGNORE,
     314             :                                 PETSC_IGNORE,
     315             :                                 PETSC_IGNORE,
     316             :                                 PETSC_IGNORE,
     317             :                                 PETSC_IGNORE,
     318             :                                 PETSC_IGNORE,
     319             :                                 PETSC_IGNORE));
     320       11850 :   LibmeshPetscCallQ(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
     321             : 
     322       11850 :   hx = 1.0 / (PetscReal)(Mx - 1);
     323       11850 :   sx = 1.0 / (hx * hx);
     324       11850 :   hy = 1.0 / (PetscReal)(My - 1);
     325       11850 :   sy = 1.0 / (hy * hy);
     326             : 
     327       83064 :   for (j = ys; j < ys + ym; j++)
     328             :   {
     329      766480 :     for (i = xs; i < xs + xm; i++)
     330             :     {
     331             :       nc = 0;
     332      695266 :       row.j = j;
     333      695266 :       row.i = i;
     334      695266 :       if (PETSC_TRUE && (i == 0 || i == Mx - 1 || j == 0 || j == My - 1))
     335             :       {
     336      229840 :         col[nc].j = j;
     337      229840 :         col[nc].i = i;
     338      229840 :         vals[nc++] = 1.0;
     339             :       }
     340             :       else if (PETSC_FALSE && i == 0)
     341             :       { /* Left Neumann */
     342             :         col[nc].j = j;
     343             :         col[nc].i = i;
     344             :         vals[nc++] = 1.0;
     345             :         col[nc].j = j;
     346             :         col[nc].i = i + 1;
     347             :         vals[nc++] = -1.0;
     348             :       }
     349             :       else if (PETSC_FALSE && i == Mx - 1)
     350             :       { /* Right Neumann */
     351             :         col[nc].j = j;
     352             :         col[nc].i = i;
     353             :         vals[nc++] = 1.0;
     354             :         col[nc].j = j;
     355             :         col[nc].i = i - 1;
     356             :         vals[nc++] = -1.0;
     357             :       }
     358             :       else if (PETSC_FALSE && j == 0)
     359             :       { /* Bottom Neumann */
     360             :         col[nc].j = j;
     361             :         col[nc].i = i;
     362             :         vals[nc++] = 1.0;
     363             :         col[nc].j = j + 1;
     364             :         col[nc].i = i;
     365             :         vals[nc++] = -1.0;
     366             :       }
     367             :       else if (PETSC_FALSE && j == My - 1)
     368             :       { /* Top Neumann */
     369             :         col[nc].j = j;
     370             :         col[nc].i = i;
     371             :         vals[nc++] = 1.0;
     372             :         col[nc].j = j - 1;
     373             :         col[nc].i = i;
     374             :         vals[nc++] = -1.0;
     375             :       }
     376             :       else
     377             :       { /* Interior */
     378      465426 :         col[nc].j = j - 1;
     379      465426 :         col[nc].i = i;
     380      465426 :         vals[nc++] = -sy;
     381      465426 :         col[nc].j = j;
     382      465426 :         col[nc].i = i - 1;
     383      465426 :         vals[nc++] = -sx;
     384      465426 :         col[nc].j = j;
     385      465426 :         col[nc].i = i;
     386      465426 :         vals[nc++] = 2.0 * (sx + sy) + a;
     387      465426 :         col[nc].j = j;
     388      465426 :         col[nc].i = i + 1;
     389      465426 :         vals[nc++] = -sx;
     390      465426 :         col[nc].j = j + 1;
     391      465426 :         col[nc].i = i;
     392      465426 :         vals[nc++] = -sy;
     393             :       }
     394      695266 :       LibmeshPetscCallQ(MatSetValuesStencil(Jpre, 1, &row, nc, col, vals, INSERT_VALUES));
     395             :     }
     396             :   }
     397       11850 :   LibmeshPetscCallQ(MatAssemblyBegin(Jpre, MAT_FINAL_ASSEMBLY));
     398       11850 :   LibmeshPetscCallQ(MatAssemblyEnd(Jpre, MAT_FINAL_ASSEMBLY));
     399       11850 :   if (J != Jpre)
     400             :   {
     401           0 :     LibmeshPetscCallQ(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
     402           0 :     LibmeshPetscCallQ(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
     403             :   }
     404             : 
     405       11850 :   PetscFunctionReturn(PETSC_SUCCESS);
     406             : }
     407             : 
     408             : /* ------------------------------------------------------------------- */
     409             : PetscErrorCode
     410         370 : FormInitialSolution(TS ts, Vec U, void * /*ptr*/)
     411             : {
     412             :   DM da;
     413             :   PetscReal c = -30.0;
     414             :   PetscInt i, j, xs, ys, xm, ym, Mx, My;
     415             :   PetscScalar ** u;
     416             :   PetscReal hx, hy, x, y, r;
     417             : 
     418             :   PetscFunctionBeginUser;
     419         370 :   LibmeshPetscCallQ(TSGetDM(ts, &da));
     420         370 :   LibmeshPetscCallQ(DMDAGetInfo(da,
     421             :                                 PETSC_IGNORE,
     422             :                                 &Mx,
     423             :                                 &My,
     424             :                                 PETSC_IGNORE,
     425             :                                 PETSC_IGNORE,
     426             :                                 PETSC_IGNORE,
     427             :                                 PETSC_IGNORE,
     428             :                                 PETSC_IGNORE,
     429             :                                 PETSC_IGNORE,
     430             :                                 PETSC_IGNORE,
     431             :                                 PETSC_IGNORE,
     432             :                                 PETSC_IGNORE,
     433             :                                 PETSC_IGNORE));
     434             : 
     435         370 :   hx = 1.0 / (PetscReal)(Mx - 1);
     436         370 :   hy = 1.0 / (PetscReal)(My - 1);
     437             : 
     438             :   /* Get pointers to vector data */
     439         370 :   LibmeshPetscCallQ(DMDAVecGetArray(da, U, &u));
     440             : 
     441             :   /* Get local grid boundaries */
     442         370 :   LibmeshPetscCallQ(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL));
     443             : 
     444             :   /* Compute function over the locally owned part of the grid */
     445        2482 :   for (j = ys; j < ys + ym; j++)
     446             :   {
     447        2112 :     y = j * hy;
     448       22440 :     for (i = xs; i < xs + xm; i++)
     449             :     {
     450       20328 :       x = i * hx;
     451       20328 :       r = PetscSqrtReal((x - .5) * (x - .5) + (y - .5) * (y - .5));
     452       20328 :       if (r < .125)
     453         840 :         u[j][i] = PetscExpReal(c * r * r * r);
     454             :       else
     455       19488 :         u[j][i] = 0.0;
     456             :     }
     457             :   }
     458             : 
     459             :   /* Restore vectors */
     460         370 :   LibmeshPetscCallQ(DMDAVecRestoreArray(da, U, &u));
     461         370 :   PetscFunctionReturn(PETSC_SUCCESS);
     462             : }

Generated by: LCOV version 1.14