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