/* The Problem: Solve the convection-diffusion equation: u_t+a*(u_x+u_y)=epsilon*(u_xx+u_yy) u=0 at x=0, y=0 u_x=0 at x=1 u_y=0 at y=1 u = exp(-20.0*(pow(x-0.5,2.0)+pow(y-0.5,2.0))) at t=0 This program tests the routine of computing the Jacobian by the finite difference method as well as PETSc. */ static char help[] = "Solve the convection-diffusion equation. \n\n"; #include typedef struct { PetscInt m; /* the number of mesh points in x-direction */ PetscInt n; /* the number of mesh points in y-direction */ PetscReal dx; /* the grid space in x-direction */ PetscReal dy; /* the grid space in y-direction */ PetscReal a; /* the convection coefficient */ PetscReal epsilon; /* the diffusion coefficient */ PetscReal tfinal; } Data; extern PetscErrorCode Monitor(TS,PetscInt,PetscReal,Vec,void*); extern PetscErrorCode Initial(Vec,void*); extern PetscErrorCode RHSFunction(TS,PetscReal,Vec,Vec,void*); extern PetscErrorCode RHSJacobian(TS,PetscReal,Vec,Mat,Mat,void*); extern PetscErrorCode PostStep(TS); int main(int argc,char **argv) { PetscInt time_steps=100,iout,NOUT=1; Vec global; PetscReal dt,ftime,ftime_original; TS ts; PetscViewer viewfile; Mat J = 0; Vec x; Data data; PetscInt mn; PetscBool flg; MatColoring mc; ISColoring iscoloring; MatFDColoring matfdcoloring = 0; PetscBool fd_jacobian_coloring = PETSC_FALSE; SNES snes; KSP ksp; PC pc; PetscCall(PetscInitialize(&argc,&argv,(char*)0,help)); /* set data */ data.m = 9; data.n = 9; data.a = 1.0; data.epsilon = 0.1; data.dx = 1.0/(data.m+1.0); data.dy = 1.0/(data.n+1.0); mn = (data.m)*(data.n); PetscCall(PetscOptionsGetInt(NULL,NULL,"-time",&time_steps,NULL)); /* set initial conditions */ PetscCall(VecCreate(PETSC_COMM_WORLD,&global)); PetscCall(VecSetSizes(global,PETSC_DECIDE,mn)); PetscCall(VecSetFromOptions(global)); PetscCall(Initial(global,&data)); PetscCall(VecDuplicate(global,&x)); /* create timestep context */ PetscCall(TSCreate(PETSC_COMM_WORLD,&ts)); PetscCall(TSMonitorSet(ts,Monitor,&data,NULL)); PetscCall(TSSetType(ts,TSEULER)); dt = 0.1; ftime_original = data.tfinal = 1.0; PetscCall(TSSetTimeStep(ts,dt)); PetscCall(TSSetMaxSteps(ts,time_steps)); PetscCall(TSSetMaxTime(ts,ftime_original)); PetscCall(TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER)); PetscCall(TSSetSolution(ts,global)); /* set user provided RHSFunction and RHSJacobian */ PetscCall(TSSetRHSFunction(ts,NULL,RHSFunction,&data)); PetscCall(MatCreate(PETSC_COMM_WORLD,&J)); PetscCall(MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,mn,mn)); PetscCall(MatSetFromOptions(J)); PetscCall(MatSeqAIJSetPreallocation(J,5,NULL)); PetscCall(MatMPIAIJSetPreallocation(J,5,NULL,5,NULL)); PetscCall(PetscOptionsHasName(NULL,NULL,"-ts_fd",&flg)); if (!flg) { PetscCall(TSSetRHSJacobian(ts,J,J,RHSJacobian,&data)); } else { PetscCall(TSGetSNES(ts,&snes)); PetscCall(PetscOptionsHasName(NULL,NULL,"-fd_color",&fd_jacobian_coloring)); if (fd_jacobian_coloring) { /* Use finite differences with coloring */ /* Get data structure of J */ PetscBool pc_diagonal; PetscCall(PetscOptionsHasName(NULL,NULL,"-pc_diagonal",&pc_diagonal)); if (pc_diagonal) { /* the preconditioner of J is a diagonal matrix */ PetscInt rstart,rend,i; PetscScalar zero=0.0; PetscCall(MatGetOwnershipRange(J,&rstart,&rend)); for (i=rstart; im; dx = data->dx; dy = data->dy; /* determine starting point of each processor */ PetscCall(VecGetOwnershipRange(global,&mybase,&myend)); PetscCall(VecGetLocalSize(global,&locsize)); /* Initialize the array */ PetscCall(VecGetArrayWrite(global,&localptr)); for (i=0; im; n = data->n; mn = m*n; dx = data->dx; dy = data->dy; a = data->a; epsilon = data->epsilon; xc = -2.0*epsilon*(1.0/(dx*dx)+1.0/(dy*dy)); xl = 0.5*a/dx+epsilon/(dx*dx); xr = -0.5*a/dx+epsilon/(dx*dx); yl = 0.5*a/dy+epsilon/(dy*dy); yr = -0.5*a/dy+epsilon/(dy*dy); row = 0; v[0] = xc; v[1] = xr; v[2] = yr; idx[0] = 0; idx[1] = 2; idx[2] = m; PetscCall(MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES)); row = m-1; v[0] = 2.0*xl; v[1] = xc; v[2] = yr; idx[0] = m-2; idx[1] = m-1; idx[2] = m-1+m; PetscCall(MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES)); for (i=1; im; n = data->n; mn = m*n; dx = data->dx; dy = data->dy; a = data->a; epsilon = data->epsilon; xc = -2.0*epsilon*(1.0/(dx*dx)+1.0/(dy*dy)); xl = 0.5*a/dx+epsilon/(dx*dx); xr = -0.5*a/dx+epsilon/(dx*dx); yl = 0.5*a/dy+epsilon/(dy*dy); yr = -0.5*a/dy+epsilon/(dy*dy); /* Get the length of parallel vector */ PetscCall(VecGetSize(globalin,&len)); /* Set the index sets */ PetscCall(PetscMalloc1(len,&idx)); for (i=0; i