/* 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 This program tests the routine of computing the Jacobian by the finite difference method as well as PETSc with SUNDIALS. */ static char help[] = "Solve the convection-diffusion equation. \n\n"; #include "petscsys.h" #include "petscts.h" extern PetscErrorCode Monitor(TS,PetscInt,PetscReal,Vec,void *); extern PetscErrorCode Initial(Vec,void *); 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 */ } Data; /* two temporal functions */ extern PetscErrorCode FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*); extern PetscErrorCode FormFunction(SNES,Vec,Vec,void*); extern PetscErrorCode RHSFunction(TS,PetscReal,Vec,Vec,void*); extern PetscErrorCode RHSJacobian(TS,PetscReal,Vec,Mat*,Mat*,MatStructure *,void*); /* the initial function */ PetscReal f_ini(PetscReal x,PetscReal y) { PetscReal f; f=exp(-20.0*(pow(x-0.5,2.0)+pow(y-0.5,2.0))); return f; } /* #undef PETSC_HAVE_SUNDIALS */ #define linear_no_matrix 0 #define linear_no_time 1 #define linear 2 #define nonlinear_no_jacobian 3 #define nonlinear 4 #undef __FUNCT__ #define __FUNCT__ "main" int main(int argc,char **argv) { PetscErrorCode ierr; PetscInt time_steps = 100,steps; PetscMPIInt size; Vec global; PetscReal dt,ftime; TS ts; PetscViewer viewfile; MatStructure A_structure; Mat A = 0; TSProblemType tsproblem = TS_NONLINEAR; /* Need to be TS_NONLINEAR */ SNES snes; Vec x; Data data; PetscInt mn; #if defined(PETSC_HAVE_SUNDIALS) PC pc; PetscViewer viewer; char pcinfo[120],tsinfo[120]; #endif ierr = PetscInitialize(&argc,&argv,(char*)0,help);CHKERRQ(ierr); ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr); /* 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); ierr = PetscOptionsGetInt(PETSC_NULL,"-time",&time_steps,PETSC_NULL);CHKERRQ(ierr); /* set initial conditions */ ierr = VecCreate(PETSC_COMM_WORLD,&global);CHKERRQ(ierr); ierr = VecSetSizes(global,PETSC_DECIDE,mn);CHKERRQ(ierr); ierr = VecSetFromOptions(global);CHKERRQ(ierr); ierr = Initial(global,&data);CHKERRQ(ierr); ierr = VecDuplicate(global,&x);CHKERRQ(ierr); /* make timestep context */ ierr = TSCreate(PETSC_COMM_WORLD,&ts);CHKERRQ(ierr); ierr = TSSetProblemType(ts,tsproblem);CHKERRQ(ierr); ierr = TSMonitorSet(ts,Monitor,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); dt = 0.1; /* The user provides the RHS and Jacobian */ ierr = MatCreate(PETSC_COMM_WORLD,&A);CHKERRQ(ierr); ierr = MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,mn,mn);CHKERRQ(ierr); ierr = MatSetFromOptions(A);CHKERRQ(ierr); /* Create SNES context */ ierr = SNESCreate(PETSC_COMM_WORLD,&snes);CHKERRQ(ierr); /* setting the RHS function and the Jacobian's non-zero structutre */ ierr = SNESSetFunction(snes,global,FormFunction,&data);CHKERRQ(ierr); ierr = SNESSetJacobian(snes,A,A,FormJacobian,&data);CHKERRQ(ierr); /* set TSSundialsRHSFunction and TSSundialsRHSJacobian, so PETSc will pick up the RHS function from SNES and compute the Jacobian by FD */ /* ierr = TSSetRHSFunction(ts,TSSundialsSetRHSFunction,snes);CHKERRQ(ierr); ierr = TSSundialsSetRHSJacobian(ts,0.0,global,&A,&A,&A_structure,snes);CHKERRQ(ierr); ierr = TSSetRHSJacobian(ts,A,A,TSSundialsSetRHSJacobian,snes);CHKERRQ(ierr); */ ierr = TSSetRHSFunction(ts,RHSFunction,&data);CHKERRQ(ierr); ierr = RHSJacobian(ts,0.0,global,&A,&A,&A_structure,&data);CHKERRQ(ierr); ierr = TSSetRHSJacobian(ts,A,A,RHSJacobian,&data);CHKERRQ(ierr); /* Use SUNDIALS */ #if defined(PETSC_HAVE_SUNDIALS) ierr = TSSetType(ts,TS_SUNDIALS);CHKERRQ(ierr); #else ierr = TSSetType(ts,TS_EULER);CHKERRQ(ierr); #endif ierr = TSSetFromOptions(ts);CHKERRQ(ierr); ierr = TSSetInitialTimeStep(ts,0.0,dt);CHKERRQ(ierr); ierr = TSSetDuration(ts,time_steps,1);CHKERRQ(ierr); ierr = TSSetSolution(ts,global);CHKERRQ(ierr); /* Pick up a Petsc preconditioner */ /* one can always set method or preconditioner during the run time */ #if defined(PETSC_HAVE_SUNDIALS) ierr = TSSundialsGetPC(ts,&pc);CHKERRQ(ierr); ierr = PCSetType(pc,PCJACOBI);CHKERRQ(ierr); ierr = TSSundialsSetType(ts,SUNDIALS_BDF);CHKERRQ(ierr); /* ierr = TSSundialsSetMethodFromOptions(ts);CHKERRQ(ierr); */ #endif ierr = TSSetUp(ts);CHKERRQ(ierr); ierr = TSStep(ts,&steps,&ftime);CHKERRQ(ierr); ierr = TSGetSolution(ts,&global);CHKERRQ(ierr); ierr = PetscViewerASCIIOpen(PETSC_COMM_WORLD,"out.m",&viewfile);CHKERRQ(ierr); ierr = PetscViewerSetFormat(viewfile,PETSC_VIEWER_ASCII_MATLAB);CHKERRQ(ierr); ierr = VecView(global,viewfile);CHKERRQ(ierr); ierr = PetscViewerDestroy(viewfile);CHKERRQ(ierr); #if defined(PETSC_HAVE_SUNDIALS) /* extracts the PC from ts */ ierr = TSSundialsGetPC(ts,&pc);CHKERRQ(ierr); ierr = PetscViewerStringOpen(PETSC_COMM_WORLD,tsinfo,120,&viewer);CHKERRQ(ierr); ierr = TSView(ts,viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(viewer);CHKERRQ(ierr); ierr = PetscViewerStringOpen(PETSC_COMM_WORLD,pcinfo,120,&viewer);CHKERRQ(ierr); ierr = PCView(pc,viewer);CHKERRQ(ierr); ierr = PetscPrintf(PETSC_COMM_WORLD,"%d Procs,%s Preconditioner,%s\n", size,tsinfo,pcinfo);CHKERRQ(ierr); ierr = PetscViewerDestroy(viewer);CHKERRQ(ierr); #endif /* free the memories */ ierr = TSDestroy(ts);CHKERRQ(ierr); ierr = VecDestroy(global);CHKERRQ(ierr); ierr = VecDestroy(x);CHKERRQ(ierr); if (A) {ierr= MatDestroy(A);CHKERRQ(ierr);} ierr = SNESDestroy(snes);CHKERRQ(ierr); ierr = PetscFinalize();CHKERRQ(ierr); return 0; } /* -------------------------------------------------------------------*/ #undef __FUNCT__ #define __FUNCT__ "Initial" PetscErrorCode Initial(Vec global,void *ctx) { Data *data = (Data*)ctx; PetscInt m,row,col; PetscReal x,y,dx,dy; PetscScalar *localptr; PetscInt i,mybase,myend,locsize; PetscErrorCode ierr; /* make the local copies of parameters */ m = data->m; dx = data->dx; dy = data->dy; /* determine starting point of each processor */ ierr = VecGetOwnershipRange(global,&mybase,&myend);CHKERRQ(ierr); ierr = VecGetLocalSize(global,&locsize);CHKERRQ(ierr); /* Initialize the array */ ierr = VecGetArray(global,&localptr);CHKERRQ(ierr); 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); /* Get the length of parallel vector */ ierr = VecGetSize(globalin,&len);CHKERRQ(ierr); /* Set the index sets */ ierr = PetscMalloc(len*sizeof(PetscInt),&idx);CHKERRQ(ierr); for(i=0; im; n = data->n; mn = (data->m)*(data->n); 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; ierr = MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);CHKERRQ(ierr); 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; ierr = MatSetValues(A,1,&row,3,idx,v,INSERT_VALUES);CHKERRQ(ierr); for (i=1; i