1*55a74a43SLisandro Dalcin /* ------------------------------------------------------------------------ 2*55a74a43SLisandro Dalcin 3*55a74a43SLisandro Dalcin Solid Fuel Ignition (SFI) problem. This problem is modeled by the 4*55a74a43SLisandro Dalcin partial differential equation 5*55a74a43SLisandro Dalcin 6*55a74a43SLisandro Dalcin -Laplacian(u) - lambda * exp(u) = 0, 0 < x,y,z < 1, 7*55a74a43SLisandro Dalcin 8*55a74a43SLisandro Dalcin with boundary conditions 9*55a74a43SLisandro Dalcin 10*55a74a43SLisandro Dalcin u = 0 for x = 0, x = 1, y = 0, y = 1, z = 0, z = 1 11*55a74a43SLisandro Dalcin 12*55a74a43SLisandro Dalcin A finite difference approximation with the usual 7-point stencil 13*55a74a43SLisandro Dalcin is used to discretize the boundary value problem to obtain a 14*55a74a43SLisandro Dalcin nonlinear system of equations. The problem is solved in a 3D 15*55a74a43SLisandro Dalcin rectangular domain, using distributed arrays (DAs) to partition 16*55a74a43SLisandro Dalcin the parallel grid. 17*55a74a43SLisandro Dalcin 18*55a74a43SLisandro Dalcin ------------------------------------------------------------------------- */ 19*55a74a43SLisandro Dalcin 20*55a74a43SLisandro Dalcin #include "Bratu3Dimpl.h" 21*55a74a43SLisandro Dalcin 22*55a74a43SLisandro Dalcin PetscErrorCode FormInitGuess(DM da, Vec X, Params *p) 23*55a74a43SLisandro Dalcin { 24*55a74a43SLisandro Dalcin PetscInt i,j,k,Mx,My,Mz,xs,ys,zs,xm,ym,zm; 25*55a74a43SLisandro Dalcin PetscReal lambda,temp1,hx,hy,hz,tempk,tempj; 26*55a74a43SLisandro Dalcin PetscScalar ***x; 27*55a74a43SLisandro Dalcin 28*55a74a43SLisandro Dalcin PetscFunctionBegin; 29*55a74a43SLisandro Dalcin PetscCall(DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,&Mz,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE)); 30*55a74a43SLisandro Dalcin 31*55a74a43SLisandro Dalcin lambda = p->lambda_; 32*55a74a43SLisandro Dalcin hx = 1.0/(PetscReal)(Mx-1); 33*55a74a43SLisandro Dalcin hy = 1.0/(PetscReal)(My-1); 34*55a74a43SLisandro Dalcin hz = 1.0/(PetscReal)(Mz-1); 35*55a74a43SLisandro Dalcin temp1 = lambda/(lambda + 1.0); 36*55a74a43SLisandro Dalcin 37*55a74a43SLisandro Dalcin /* 38*55a74a43SLisandro Dalcin Get a pointer to vector data. 39*55a74a43SLisandro Dalcin 40*55a74a43SLisandro Dalcin - For default PETSc vectors, VecGetArray() returns a pointer to 41*55a74a43SLisandro Dalcin the data array. Otherwise, the routine is implementation 42*55a74a43SLisandro Dalcin dependent. 43*55a74a43SLisandro Dalcin 44*55a74a43SLisandro Dalcin - You MUST call VecRestoreArray() when you no longer need access 45*55a74a43SLisandro Dalcin to the array. 46*55a74a43SLisandro Dalcin */ 47*55a74a43SLisandro Dalcin PetscCall(DMDAVecGetArray(da,X,&x)); 48*55a74a43SLisandro Dalcin 49*55a74a43SLisandro Dalcin /* 50*55a74a43SLisandro Dalcin Get local grid boundaries (for 3-dimensional DMDA): 51*55a74a43SLisandro Dalcin 52*55a74a43SLisandro Dalcin - xs, ys, zs: starting grid indices (no ghost points) 53*55a74a43SLisandro Dalcin 54*55a74a43SLisandro Dalcin - xm, ym, zm: widths of local grid (no ghost points) 55*55a74a43SLisandro Dalcin */ 56*55a74a43SLisandro Dalcin PetscCall(DMDAGetCorners(da,&xs,&ys,&zs,&xm,&ym,&zm)); 57*55a74a43SLisandro Dalcin 58*55a74a43SLisandro Dalcin /* 59*55a74a43SLisandro Dalcin Compute initial guess over the locally owned part of the grid 60*55a74a43SLisandro Dalcin */ 61*55a74a43SLisandro Dalcin for (k=zs; k<zs+zm; k++) { 62*55a74a43SLisandro Dalcin tempk = (PetscReal)(PetscMin(k,Mz-k-1))*hz; 63*55a74a43SLisandro Dalcin for (j=ys; j<ys+ym; j++) { 64*55a74a43SLisandro Dalcin tempj = PetscMin((PetscReal)(PetscMin(j,My-j-1))*hy,tempk); 65*55a74a43SLisandro Dalcin for (i=xs; i<xs+xm; i++) { 66*55a74a43SLisandro Dalcin if (i == 0 || j == 0 || k == 0 || i == Mx-1 || j == My-1 || k == Mz-1) { 67*55a74a43SLisandro Dalcin /* boundary conditions are all zero Dirichlet */ 68*55a74a43SLisandro Dalcin x[k][j][i] = 0.0; 69*55a74a43SLisandro Dalcin } else { 70*55a74a43SLisandro Dalcin x[k][j][i] = temp1*sqrt(PetscMin((PetscReal)(PetscMin(i,Mx-i-1))*hx,tempj)); 71*55a74a43SLisandro Dalcin } 72*55a74a43SLisandro Dalcin } 73*55a74a43SLisandro Dalcin } 74*55a74a43SLisandro Dalcin } 75*55a74a43SLisandro Dalcin 76*55a74a43SLisandro Dalcin /* 77*55a74a43SLisandro Dalcin Restore vector 78*55a74a43SLisandro Dalcin */ 79*55a74a43SLisandro Dalcin PetscCall(DMDAVecRestoreArray(da,X,&x)); 80*55a74a43SLisandro Dalcin PetscFunctionReturn(PETSC_SUCCESS); 81*55a74a43SLisandro Dalcin } 82*55a74a43SLisandro Dalcin 83*55a74a43SLisandro Dalcin PetscErrorCode FormFunction(DM da, Vec X, Vec F, Params *p) 84*55a74a43SLisandro Dalcin { 85*55a74a43SLisandro Dalcin PetscInt i,j,k,Mx,My,Mz,xs,ys,zs,xm,ym,zm; 86*55a74a43SLisandro Dalcin PetscReal two = 2.0,lambda,hx,hy,hz,hxhzdhy,hyhzdhx,hxhydhz,sc; 87*55a74a43SLisandro Dalcin PetscScalar u_north,u_south,u_east,u_west,u_up,u_down,u,u_xx,u_yy,u_zz,***x,***f; 88*55a74a43SLisandro Dalcin Vec localX; 89*55a74a43SLisandro Dalcin 90*55a74a43SLisandro Dalcin PetscFunctionBegin; 91*55a74a43SLisandro Dalcin PetscCall(DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,&Mz,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE)); 92*55a74a43SLisandro Dalcin lambda = p->lambda_; 93*55a74a43SLisandro Dalcin hx = 1.0/(PetscReal)(Mx-1); 94*55a74a43SLisandro Dalcin hy = 1.0/(PetscReal)(My-1); 95*55a74a43SLisandro Dalcin hz = 1.0/(PetscReal)(Mz-1); 96*55a74a43SLisandro Dalcin sc = hx*hy*hz*lambda; 97*55a74a43SLisandro Dalcin hxhzdhy = hx*hz/hy; 98*55a74a43SLisandro Dalcin hyhzdhx = hy*hz/hx; 99*55a74a43SLisandro Dalcin hxhydhz = hx*hy/hz; 100*55a74a43SLisandro Dalcin 101*55a74a43SLisandro Dalcin /* 102*55a74a43SLisandro Dalcin 103*55a74a43SLisandro Dalcin */ 104*55a74a43SLisandro Dalcin PetscCall(DMGetLocalVector(da,&localX)); 105*55a74a43SLisandro Dalcin 106*55a74a43SLisandro Dalcin /* 107*55a74a43SLisandro Dalcin Scatter ghost points to local vector,using the 2-step process 108*55a74a43SLisandro Dalcin DMGlobalToLocalBegin(),DMGlobalToLocalEnd(). By placing code 109*55a74a43SLisandro Dalcin between these two statements, computations can be done while 110*55a74a43SLisandro Dalcin messages are in transition. 111*55a74a43SLisandro Dalcin */ 112*55a74a43SLisandro Dalcin PetscCall(DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX)); 113*55a74a43SLisandro Dalcin PetscCall(DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX)); 114*55a74a43SLisandro Dalcin 115*55a74a43SLisandro Dalcin /* 116*55a74a43SLisandro Dalcin Get pointers to vector data. 117*55a74a43SLisandro Dalcin */ 118*55a74a43SLisandro Dalcin PetscCall(DMDAVecGetArray(da,localX,&x)); 119*55a74a43SLisandro Dalcin PetscCall(DMDAVecGetArray(da,F,&f)); 120*55a74a43SLisandro Dalcin 121*55a74a43SLisandro Dalcin /* 122*55a74a43SLisandro Dalcin Get local grid boundaries. 123*55a74a43SLisandro Dalcin */ 124*55a74a43SLisandro Dalcin PetscCall(DMDAGetCorners(da,&xs,&ys,&zs,&xm,&ym,&zm)); 125*55a74a43SLisandro Dalcin 126*55a74a43SLisandro Dalcin /* 127*55a74a43SLisandro Dalcin Compute function over the locally owned part of the grid. 128*55a74a43SLisandro Dalcin */ 129*55a74a43SLisandro Dalcin for (k=zs; k<zs+zm; k++) { 130*55a74a43SLisandro Dalcin for (j=ys; j<ys+ym; j++) { 131*55a74a43SLisandro Dalcin for (i=xs; i<xs+xm; i++) { 132*55a74a43SLisandro Dalcin if (i == 0 || j == 0 || k == 0 || i == Mx-1 || j == My-1 || k == Mz-1) { 133*55a74a43SLisandro Dalcin /* boundary points */ 134*55a74a43SLisandro Dalcin f[k][j][i] = x[k][j][i] - 0.0; 135*55a74a43SLisandro Dalcin } else { 136*55a74a43SLisandro Dalcin /* interior grid points */ 137*55a74a43SLisandro Dalcin u = x[k][j][i]; 138*55a74a43SLisandro Dalcin u_east = x[k][j][i+1]; 139*55a74a43SLisandro Dalcin u_west = x[k][j][i-1]; 140*55a74a43SLisandro Dalcin u_north = x[k][j+1][i]; 141*55a74a43SLisandro Dalcin u_south = x[k][j-1][i]; 142*55a74a43SLisandro Dalcin u_up = x[k+1][j][i]; 143*55a74a43SLisandro Dalcin u_down = x[k-1][j][i]; 144*55a74a43SLisandro Dalcin u_xx = (-u_east + two*u - u_west)*hyhzdhx; 145*55a74a43SLisandro Dalcin u_yy = (-u_north + two*u - u_south)*hxhzdhy; 146*55a74a43SLisandro Dalcin u_zz = (-u_up + two*u - u_down)*hxhydhz; 147*55a74a43SLisandro Dalcin f[k][j][i] = u_xx + u_yy + u_zz - sc*PetscExpScalar(u); 148*55a74a43SLisandro Dalcin } 149*55a74a43SLisandro Dalcin } 150*55a74a43SLisandro Dalcin } 151*55a74a43SLisandro Dalcin } 152*55a74a43SLisandro Dalcin 153*55a74a43SLisandro Dalcin /* 154*55a74a43SLisandro Dalcin Restore vectors. 155*55a74a43SLisandro Dalcin */ 156*55a74a43SLisandro Dalcin PetscCall(DMDAVecRestoreArray(da,F,&f)); 157*55a74a43SLisandro Dalcin PetscCall(DMDAVecRestoreArray(da,localX,&x)); 158*55a74a43SLisandro Dalcin PetscCall(DMRestoreLocalVector(da,&localX)); 159*55a74a43SLisandro Dalcin PetscCall(PetscLogFlops(11.0*ym*xm)); 160*55a74a43SLisandro Dalcin PetscFunctionReturn(PETSC_SUCCESS); 161*55a74a43SLisandro Dalcin } 162*55a74a43SLisandro Dalcin 163*55a74a43SLisandro Dalcin PetscErrorCode FormJacobian(DM da, Vec X, Mat J, Params *p) 164*55a74a43SLisandro Dalcin { 165*55a74a43SLisandro Dalcin PetscInt i,j,k,Mx,My,Mz,xs,ys,zs,xm,ym,zm; 166*55a74a43SLisandro Dalcin PetscReal lambda,hx,hy,hz,hxhzdhy,hyhzdhx,hxhydhz,sc; 167*55a74a43SLisandro Dalcin PetscScalar v[7],***x; 168*55a74a43SLisandro Dalcin MatStencil col[7],row; 169*55a74a43SLisandro Dalcin Vec localX; 170*55a74a43SLisandro Dalcin 171*55a74a43SLisandro Dalcin PetscFunctionBegin; 172*55a74a43SLisandro Dalcin PetscCall(DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,&Mz,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE)); 173*55a74a43SLisandro Dalcin lambda = p->lambda_; 174*55a74a43SLisandro Dalcin hx = 1.0/(PetscReal)(Mx-1); 175*55a74a43SLisandro Dalcin hy = 1.0/(PetscReal)(My-1); 176*55a74a43SLisandro Dalcin hz = 1.0/(PetscReal)(Mz-1); 177*55a74a43SLisandro Dalcin sc = hx*hy*hz*lambda; 178*55a74a43SLisandro Dalcin hxhzdhy = hx*hz/hy; 179*55a74a43SLisandro Dalcin hyhzdhx = hy*hz/hx; 180*55a74a43SLisandro Dalcin hxhydhz = hx*hy/hz; 181*55a74a43SLisandro Dalcin 182*55a74a43SLisandro Dalcin /* 183*55a74a43SLisandro Dalcin 184*55a74a43SLisandro Dalcin */ 185*55a74a43SLisandro Dalcin PetscCall(DMGetLocalVector(da,&localX)); 186*55a74a43SLisandro Dalcin 187*55a74a43SLisandro Dalcin /* 188*55a74a43SLisandro Dalcin Scatter ghost points to local vector, using the 2-step process 189*55a74a43SLisandro Dalcin DMGlobalToLocalBegin(), DMGlobalToLocalEnd(). By placing code 190*55a74a43SLisandro Dalcin between these two statements, computations can be done while 191*55a74a43SLisandro Dalcin messages are in transition. 192*55a74a43SLisandro Dalcin */ 193*55a74a43SLisandro Dalcin PetscCall(DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX)); 194*55a74a43SLisandro Dalcin PetscCall(DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX)); 195*55a74a43SLisandro Dalcin 196*55a74a43SLisandro Dalcin /* 197*55a74a43SLisandro Dalcin Get pointer to vector data. 198*55a74a43SLisandro Dalcin */ 199*55a74a43SLisandro Dalcin PetscCall(DMDAVecGetArray(da,localX,&x)); 200*55a74a43SLisandro Dalcin 201*55a74a43SLisandro Dalcin /* 202*55a74a43SLisandro Dalcin Get local grid boundaries. 203*55a74a43SLisandro Dalcin */ 204*55a74a43SLisandro Dalcin PetscCall(DMDAGetCorners(da,&xs,&ys,&zs,&xm,&ym,&zm)); 205*55a74a43SLisandro Dalcin 206*55a74a43SLisandro Dalcin /* 207*55a74a43SLisandro Dalcin Compute entries for the locally owned part of the Jacobian. 208*55a74a43SLisandro Dalcin 209*55a74a43SLisandro Dalcin - Currently, all PETSc parallel matrix formats are partitioned by 210*55a74a43SLisandro Dalcin contiguous chunks of rows across the processors. 211*55a74a43SLisandro Dalcin 212*55a74a43SLisandro Dalcin - Each processor needs to insert only elements that it owns 213*55a74a43SLisandro Dalcin locally (but any non-local elements will be sent to the 214*55a74a43SLisandro Dalcin appropriate processor during matrix assembly). 215*55a74a43SLisandro Dalcin 216*55a74a43SLisandro Dalcin - Here, we set all entries for a particular row at once. 217*55a74a43SLisandro Dalcin 218*55a74a43SLisandro Dalcin - We can set matrix entries either using either 219*55a74a43SLisandro Dalcin MatSetValuesLocal() or MatSetValues(), as discussed above. 220*55a74a43SLisandro Dalcin */ 221*55a74a43SLisandro Dalcin for (k=zs; k<zs+zm; k++) { 222*55a74a43SLisandro Dalcin for (j=ys; j<ys+ym; j++) { 223*55a74a43SLisandro Dalcin for (i=xs; i<xs+xm; i++) { 224*55a74a43SLisandro Dalcin row.k = k; row.j = j; row.i = i; 225*55a74a43SLisandro Dalcin /* boundary points */ 226*55a74a43SLisandro Dalcin if (i == 0 || j == 0 || k == 0|| i == Mx-1 || j == My-1 || k == Mz-1) { 227*55a74a43SLisandro Dalcin v[0] = 1.0; 228*55a74a43SLisandro Dalcin PetscCall(MatSetValuesStencil(J,1,&row,1,&row,v,INSERT_VALUES)); 229*55a74a43SLisandro Dalcin } else { 230*55a74a43SLisandro Dalcin /* interior grid points */ 231*55a74a43SLisandro Dalcin v[0] = -hxhydhz; col[0].k=k-1;col[0].j=j; col[0].i = i; 232*55a74a43SLisandro Dalcin v[1] = -hxhzdhy; col[1].k=k; col[1].j=j-1;col[1].i = i; 233*55a74a43SLisandro Dalcin v[2] = -hyhzdhx; col[2].k=k; col[2].j=j; col[2].i = i-1; 234*55a74a43SLisandro Dalcin v[3] = 2.0*(hyhzdhx+hxhzdhy+hxhydhz)-sc*PetscExpScalar(x[k][j][i]);col[3].k=row.k;col[3].j=row.j;col[3].i = row.i; 235*55a74a43SLisandro Dalcin v[4] = -hyhzdhx; col[4].k=k; col[4].j=j; col[4].i = i+1; 236*55a74a43SLisandro Dalcin v[5] = -hxhzdhy; col[5].k=k; col[5].j=j+1;col[5].i = i; 237*55a74a43SLisandro Dalcin v[6] = -hxhydhz; col[6].k=k+1;col[6].j=j; col[6].i = i; 238*55a74a43SLisandro Dalcin PetscCall(MatSetValuesStencil(J,1,&row,7,col,v,INSERT_VALUES)); 239*55a74a43SLisandro Dalcin } 240*55a74a43SLisandro Dalcin } 241*55a74a43SLisandro Dalcin } 242*55a74a43SLisandro Dalcin } 243*55a74a43SLisandro Dalcin PetscCall(DMDAVecRestoreArray(da,localX,&x)); 244*55a74a43SLisandro Dalcin PetscCall(DMRestoreLocalVector(da,&localX)); 245*55a74a43SLisandro Dalcin 246*55a74a43SLisandro Dalcin /* 247*55a74a43SLisandro Dalcin Assemble matrix, using the 2-step process: MatAssemblyBegin(), 248*55a74a43SLisandro Dalcin MatAssemblyEnd(). 249*55a74a43SLisandro Dalcin */ 250*55a74a43SLisandro Dalcin PetscCall(MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY)); 251*55a74a43SLisandro Dalcin PetscCall(MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY)); 252*55a74a43SLisandro Dalcin 253*55a74a43SLisandro Dalcin /* 254*55a74a43SLisandro Dalcin Tell the matrix we will never add a new nonzero location to the 255*55a74a43SLisandro Dalcin matrix. If we do, it will generate an error. 256*55a74a43SLisandro Dalcin */ 257*55a74a43SLisandro Dalcin PetscCall(MatSetOption(J,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE)); 258*55a74a43SLisandro Dalcin PetscFunctionReturn(PETSC_SUCCESS); 259*55a74a43SLisandro Dalcin } 260