1 /* 2 Include "petscsnes.h" so that we can use SNES solvers. Note that this 3 file automatically includes: 4 petscsys.h - base PETSc routines petscvec.h - vectors 5 petscmat.h - matrices 6 petscis.h - index sets petscksp.h - Krylov subspace methods 7 petscviewer.h - viewers petscpc.h - preconditioners 8 petscksp.h - linear solvers 9 */ 10 #include <petscsnes.h> 11 #include <petscao.h> 12 13 static char help[] = "An Unstructured Grid Example.\n\ 14 This example demonstrates how to solve a nonlinear system in parallel\n\ 15 with SNES for an unstructured mesh. The mesh and partitioning information\n\ 16 is read in an application defined ordering,which is later transformed\n\ 17 into another convenient ordering (called the local ordering). The local\n\ 18 ordering, apart from being efficient on cpu cycles and memory, allows\n\ 19 the use of the SPMD model of parallel programming. After partitioning\n\ 20 is done, scatters are created between local (sequential)and global\n\ 21 (distributed) vectors. Finally, we set up the nonlinear solver context\n\ 22 in the usual way as a structured grid (see\n\ 23 petsc/src/snes/tutorials/ex5.c).\n\ 24 This example also illustrates the use of parallel matrix coloring.\n\ 25 The command line options include:\n\ 26 -vert <Nv>, where Nv is the global number of nodes\n\ 27 -elem <Ne>, where Ne is the global number of elements\n\ 28 -nl_par <lambda>, where lambda is the multiplier for the non linear term (u*u) term\n\ 29 -lin_par <alpha>, where alpha is the multiplier for the linear term (u)\n\ 30 -fd_jacobian_coloring -mat_coloring_type lf\n"; 31 32 /* ------------------------------------------------------------------------ 33 34 PDE Solved : L(u) + lambda*u*u + alpha*u = 0 where L(u) is the Laplacian. 35 36 The Laplacian is approximated in the following way: each edge is given a weight 37 of one meaning that the diagonal term will have the weight equal to the degree 38 of a node. The off-diagonal terms will get a weight of -1. 39 40 -----------------------------------------------------------------------*/ 41 42 #define MAX_ELEM 500 /* Maximum number of elements */ 43 #define MAX_VERT 100 /* Maximum number of vertices */ 44 #define MAX_VERT_ELEM 3 /* Vertices per element */ 45 46 /* 47 Application-defined context for problem specific data 48 */ 49 typedef struct { 50 PetscInt Nvglobal, Nvlocal; /* global and local number of vertices */ 51 PetscInt Neglobal, Nelocal; /* global and local number of vertices */ 52 PetscInt AdjM[MAX_VERT][50]; /* adjacency list of a vertex */ 53 PetscInt itot[MAX_VERT]; /* total number of neighbors for a vertex */ 54 PetscInt icv[MAX_ELEM][MAX_VERT_ELEM]; /* vertices belonging to an element */ 55 PetscInt v2p[MAX_VERT]; /* processor number for a vertex */ 56 PetscInt *locInd, *gloInd; /* local and global orderings for a node */ 57 Vec localX, localF; /* local solution (u) and f(u) vectors */ 58 PetscReal non_lin_param; /* nonlinear parameter for the PDE */ 59 PetscReal lin_param; /* linear parameter for the PDE */ 60 VecScatter scatter; /* scatter context for the local and 61 distributed vectors */ 62 } AppCtx; 63 64 /* 65 User-defined routines 66 */ 67 PetscErrorCode FormJacobian(SNES, Vec, Mat, Mat, void *); 68 PetscErrorCode FormFunction(SNES, Vec, Vec, void *); 69 PetscErrorCode FormInitialGuess(AppCtx *, Vec); 70 71 int main(int argc, char **argv) 72 { 73 SNES snes; /* SNES context */ 74 SNESType type = SNESNEWTONLS; /* default nonlinear solution method */ 75 Vec x, r; /* solution, residual vectors */ 76 Mat Jac; /* Jacobian matrix */ 77 AppCtx user; /* user-defined application context */ 78 AO ao; /* Application Ordering object */ 79 IS isglobal, islocal; /* global and local index sets */ 80 PetscMPIInt rank, size; /* rank of a process, number of processors */ 81 PetscInt rstart; /* starting index of PETSc ordering for a processor */ 82 PetscInt nfails; /* number of unsuccessful Newton steps */ 83 PetscInt bs = 1; /* block size for multicomponent systems */ 84 PetscInt nvertices; /* number of local plus ghost nodes of a processor */ 85 PetscInt *pordering; /* PETSc ordering */ 86 PetscInt *vertices; /* list of all vertices (incl. ghost ones) on a processor */ 87 PetscInt *verticesmask; 88 PetscInt *tmp; 89 PetscInt i, j, jstart, inode, nb, nbrs, Nvneighborstotal = 0; 90 PetscInt its, N; 91 PetscScalar *xx; 92 char str[256], form[256], part_name[256]; 93 FILE *fptr, *fptr1; 94 ISLocalToGlobalMapping isl2g; 95 int dtmp; 96 #if defined(UNUSED_VARIABLES) 97 PetscDraw draw; /* drawing context */ 98 PetscScalar *ff, *gg; 99 PetscReal tiny = 1.0e-10, zero = 0.0, one = 1.0, big = 1.0e+10; 100 PetscInt *tmp1, *tmp2; 101 #endif 102 MatFDColoring matfdcoloring = 0; 103 PetscBool fd_jacobian_coloring = PETSC_FALSE; 104 105 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 106 Initialize program 107 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 108 109 PetscFunctionBeginUser; 110 PetscCall(PetscInitialize(&argc, &argv, "options.inf", help)); 111 PetscCallMPI(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 112 PetscCallMPI(MPI_Comm_size(MPI_COMM_WORLD, &size)); 113 114 /* The current input file options.inf is for 2 proc run only */ 115 PetscCheck(size == 2, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "This example currently runs on 2 procs only."); 116 117 /* 118 Initialize problem parameters 119 */ 120 user.Nvglobal = 16; /* Global # of vertices */ 121 user.Neglobal = 18; /* Global # of elements */ 122 123 PetscCall(PetscOptionsGetInt(NULL, NULL, "-vert", &user.Nvglobal, NULL)); 124 PetscCall(PetscOptionsGetInt(NULL, NULL, "-elem", &user.Neglobal, NULL)); 125 126 user.non_lin_param = 0.06; 127 128 PetscCall(PetscOptionsGetReal(NULL, NULL, "-nl_par", &user.non_lin_param, NULL)); 129 130 user.lin_param = -1.0; 131 132 PetscCall(PetscOptionsGetReal(NULL, NULL, "-lin_par", &user.lin_param, NULL)); 133 134 user.Nvlocal = 0; 135 user.Nelocal = 0; 136 137 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 138 Read the mesh and partitioning information 139 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 140 141 /* 142 Read the mesh and partitioning information from 'adj.in'. 143 The file format is as follows. 144 For each line the first entry is the processor rank where the 145 current node belongs. The second entry is the number of 146 neighbors of a node. The rest of the line is the adjacency 147 list of a node. Currently this file is set up to work on two 148 processors. 149 150 This is not a very good example of reading input. In the future, 151 we will put an example that shows the style that should be 152 used in a real application, where partitioning will be done 153 dynamically by calling partitioning routines (at present, we have 154 a ready interface to ParMeTiS). 155 */ 156 fptr = fopen("adj.in", "r"); 157 PetscCheck(fptr, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Could not open adj.in"); 158 159 /* 160 Each processor writes to the file output.<rank> where rank is the 161 processor's rank. 162 */ 163 snprintf(part_name, PETSC_STATIC_ARRAY_LENGTH(part_name), "output.%d", rank); 164 fptr1 = fopen(part_name, "w"); 165 PetscCheck(fptr1, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Could no open output file"); 166 PetscCall(PetscMalloc1(user.Nvglobal, &user.gloInd)); 167 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Rank is %d\n", rank)); 168 for (inode = 0; inode < user.Nvglobal; inode++) { 169 PetscCheck(fgets(str, 256, fptr), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "fgets read failed"); 170 sscanf(str, "%d", &dtmp); 171 user.v2p[inode] = dtmp; 172 if (user.v2p[inode] == rank) { 173 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Node %" PetscInt_FMT " belongs to processor %" PetscInt_FMT "\n", inode, user.v2p[inode])); 174 175 user.gloInd[user.Nvlocal] = inode; 176 sscanf(str, "%*d %d", &dtmp); 177 nbrs = dtmp; 178 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Number of neighbors for the vertex %" PetscInt_FMT " is %" PetscInt_FMT "\n", inode, nbrs)); 179 180 user.itot[user.Nvlocal] = nbrs; 181 Nvneighborstotal += nbrs; 182 for (i = 0; i < user.itot[user.Nvlocal]; i++) { 183 form[0] = '\0'; 184 for (j = 0; j < i + 2; j++) PetscCall(PetscStrlcat(form, "%*d ", sizeof(form))); 185 PetscCall(PetscStrlcat(form, "%d", sizeof(form))); 186 187 sscanf(str, form, &dtmp); 188 user.AdjM[user.Nvlocal][i] = dtmp; 189 190 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "%" PetscInt_FMT " ", user.AdjM[user.Nvlocal][i])); 191 } 192 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 193 user.Nvlocal++; 194 } 195 } 196 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Total # of Local Vertices is %" PetscInt_FMT " \n", user.Nvlocal)); 197 198 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 199 Create different orderings 200 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 201 202 /* 203 Create the local ordering list for vertices. First a list using the PETSc global 204 ordering is created. Then we use the AO object to get the PETSc-to-application and 205 application-to-PETSc mappings. Each vertex also gets a local index (stored in the 206 locInd array). 207 */ 208 PetscCallMPI(MPI_Scan(&user.Nvlocal, &rstart, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD)); 209 rstart -= user.Nvlocal; 210 PetscCall(PetscMalloc1(user.Nvlocal, &pordering)); 211 212 for (i = 0; i < user.Nvlocal; i++) pordering[i] = rstart + i; 213 214 /* 215 Create the AO object 216 */ 217 PetscCall(AOCreateBasic(MPI_COMM_WORLD, user.Nvlocal, user.gloInd, pordering, &ao)); 218 PetscCall(PetscFree(pordering)); 219 220 /* 221 Keep the global indices for later use 222 */ 223 PetscCall(PetscMalloc1(user.Nvlocal, &user.locInd)); 224 PetscCall(PetscMalloc1(Nvneighborstotal, &tmp)); 225 226 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 227 Demonstrate the use of AO functionality 228 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 229 230 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Before AOApplicationToPetsc, local indices are : \n")); 231 for (i = 0; i < user.Nvlocal; i++) { 232 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, " %" PetscInt_FMT " ", user.gloInd[i])); 233 234 user.locInd[i] = user.gloInd[i]; 235 } 236 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 237 jstart = 0; 238 for (i = 0; i < user.Nvlocal; i++) { 239 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Neghbors of local vertex %" PetscInt_FMT " are : ", user.gloInd[i])); 240 for (j = 0; j < user.itot[i]; j++) { 241 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "%" PetscInt_FMT " ", user.AdjM[i][j])); 242 243 tmp[j + jstart] = user.AdjM[i][j]; 244 } 245 jstart += user.itot[i]; 246 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 247 } 248 249 /* 250 Now map the vlocal and neighbor lists to the PETSc ordering 251 */ 252 PetscCall(AOApplicationToPetsc(ao, user.Nvlocal, user.locInd)); 253 PetscCall(AOApplicationToPetsc(ao, Nvneighborstotal, tmp)); 254 PetscCall(AODestroy(&ao)); 255 256 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "After AOApplicationToPetsc, local indices are : \n")); 257 for (i = 0; i < user.Nvlocal; i++) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, " %" PetscInt_FMT " ", user.locInd[i])); 258 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 259 260 jstart = 0; 261 for (i = 0; i < user.Nvlocal; i++) { 262 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Neghbors of local vertex %" PetscInt_FMT " are : ", user.locInd[i])); 263 for (j = 0; j < user.itot[i]; j++) { 264 user.AdjM[i][j] = tmp[j + jstart]; 265 266 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "%" PetscInt_FMT " ", user.AdjM[i][j])); 267 } 268 jstart += user.itot[i]; 269 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 270 } 271 272 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 273 Extract the ghost vertex information for each processor 274 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 275 /* 276 Next, we need to generate a list of vertices required for this processor 277 and a local numbering scheme for all vertices required on this processor. 278 vertices - integer array of all vertices needed on this processor in PETSc 279 global numbering; this list consists of first the "locally owned" 280 vertices followed by the ghost vertices. 281 verticesmask - integer array that for each global vertex lists its local 282 vertex number (in vertices) + 1. If the global vertex is not 283 represented on this processor, then the corresponding 284 entry in verticesmask is zero 285 286 Note: vertices and verticesmask are both Nvglobal in length; this may 287 sound terribly non-scalable, but in fact is not so bad for a reasonable 288 number of processors. Importantly, it allows us to use NO SEARCHING 289 in setting up the data structures. 290 */ 291 PetscCall(PetscMalloc1(user.Nvglobal, &vertices)); 292 PetscCall(PetscCalloc1(user.Nvglobal, &verticesmask)); 293 nvertices = 0; 294 295 /* 296 First load "owned vertices" into list 297 */ 298 for (i = 0; i < user.Nvlocal; i++) { 299 vertices[nvertices++] = user.locInd[i]; 300 verticesmask[user.locInd[i]] = nvertices; 301 } 302 303 /* 304 Now load ghost vertices into list 305 */ 306 for (i = 0; i < user.Nvlocal; i++) { 307 for (j = 0; j < user.itot[i]; j++) { 308 nb = user.AdjM[i][j]; 309 if (!verticesmask[nb]) { 310 vertices[nvertices++] = nb; 311 verticesmask[nb] = nvertices; 312 } 313 } 314 } 315 316 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 317 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "The array vertices is :\n")); 318 for (i = 0; i < nvertices; i++) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "%" PetscInt_FMT " ", vertices[i])); 319 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 320 321 /* 322 Map the vertices listed in the neighbors to the local numbering from 323 the global ordering that they contained initially. 324 */ 325 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 326 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "After mapping neighbors in the local contiguous ordering\n")); 327 for (i = 0; i < user.Nvlocal; i++) { 328 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Neghbors of local vertex %" PetscInt_FMT " are :\n", i)); 329 for (j = 0; j < user.itot[i]; j++) { 330 nb = user.AdjM[i][j]; 331 user.AdjM[i][j] = verticesmask[nb] - 1; 332 333 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "%" PetscInt_FMT " ", user.AdjM[i][j])); 334 } 335 PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "\n")); 336 } 337 338 N = user.Nvglobal; 339 340 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 341 Create vector and matrix data structures 342 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 343 344 /* 345 Create vector data structures 346 */ 347 PetscCall(VecCreate(MPI_COMM_WORLD, &x)); 348 PetscCall(VecSetSizes(x, user.Nvlocal, N)); 349 PetscCall(VecSetFromOptions(x)); 350 PetscCall(VecDuplicate(x, &r)); 351 PetscCall(VecCreateSeq(MPI_COMM_SELF, bs * nvertices, &user.localX)); 352 PetscCall(VecDuplicate(user.localX, &user.localF)); 353 354 /* 355 Create the scatter between the global representation and the 356 local representation 357 */ 358 PetscCall(ISCreateStride(MPI_COMM_SELF, bs * nvertices, 0, 1, &islocal)); 359 PetscCall(ISCreateBlock(MPI_COMM_SELF, bs, nvertices, vertices, PETSC_COPY_VALUES, &isglobal)); 360 PetscCall(VecScatterCreate(x, isglobal, user.localX, islocal, &user.scatter)); 361 PetscCall(ISDestroy(&isglobal)); 362 PetscCall(ISDestroy(&islocal)); 363 364 /* 365 Create matrix data structure; Just to keep the example simple, we have not done any 366 preallocation of memory for the matrix. In real application code with big matrices, 367 preallocation should always be done to expedite the matrix creation. 368 */ 369 PetscCall(MatCreate(MPI_COMM_WORLD, &Jac)); 370 PetscCall(MatSetSizes(Jac, PETSC_DECIDE, PETSC_DECIDE, N, N)); 371 PetscCall(MatSetFromOptions(Jac)); 372 PetscCall(MatSetUp(Jac)); 373 374 /* 375 The following routine allows us to set the matrix values in local ordering 376 */ 377 PetscCall(ISLocalToGlobalMappingCreate(MPI_COMM_SELF, bs, nvertices, vertices, PETSC_COPY_VALUES, &isl2g)); 378 PetscCall(MatSetLocalToGlobalMapping(Jac, isl2g, isl2g)); 379 380 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 381 Create nonlinear solver context 382 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 383 384 PetscCall(SNESCreate(MPI_COMM_WORLD, &snes)); 385 PetscCall(SNESSetType(snes, type)); 386 387 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 388 Set routines for function and Jacobian evaluation 389 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 390 PetscCall(SNESSetFunction(snes, r, FormFunction, (void *)&user)); 391 392 PetscCall(PetscOptionsGetBool(NULL, NULL, "-fd_jacobian_coloring", &fd_jacobian_coloring, 0)); 393 if (!fd_jacobian_coloring) { 394 PetscCall(SNESSetJacobian(snes, Jac, Jac, FormJacobian, (void *)&user)); 395 } else { /* Use matfdcoloring */ 396 ISColoring iscoloring; 397 MatColoring mc; 398 399 /* Get the data structure of Jac */ 400 PetscCall(FormJacobian(snes, x, Jac, Jac, &user)); 401 /* Create coloring context */ 402 PetscCall(MatColoringCreate(Jac, &mc)); 403 PetscCall(MatColoringSetType(mc, MATCOLORINGSL)); 404 PetscCall(MatColoringSetFromOptions(mc)); 405 PetscCall(MatColoringApply(mc, &iscoloring)); 406 PetscCall(MatColoringDestroy(&mc)); 407 PetscCall(MatFDColoringCreate(Jac, iscoloring, &matfdcoloring)); 408 PetscCall(MatFDColoringSetFunction(matfdcoloring, (PetscErrorCode (*)(void))FormFunction, &user)); 409 PetscCall(MatFDColoringSetFromOptions(matfdcoloring)); 410 PetscCall(MatFDColoringSetUp(Jac, iscoloring, matfdcoloring)); 411 /* PetscCall(MatFDColoringView(matfdcoloring,PETSC_VIEWER_STDOUT_WORLD)); */ 412 PetscCall(SNESSetJacobian(snes, Jac, Jac, SNESComputeJacobianDefaultColor, matfdcoloring)); 413 PetscCall(ISColoringDestroy(&iscoloring)); 414 } 415 416 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 417 Customize nonlinear solver; set runtime options 418 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 419 420 PetscCall(SNESSetFromOptions(snes)); 421 422 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 423 Evaluate initial guess; then solve nonlinear system 424 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 425 426 /* 427 Note: The user should initialize the vector, x, with the initial guess 428 for the nonlinear solver prior to calling SNESSolve(). In particular, 429 to employ an initial guess of zero, the user should explicitly set 430 this vector to zero by calling VecSet(). 431 */ 432 PetscCall(FormInitialGuess(&user, x)); 433 434 /* 435 Print the initial guess 436 */ 437 PetscCall(VecGetArray(x, &xx)); 438 for (inode = 0; inode < user.Nvlocal; inode++) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Initial Solution at node %" PetscInt_FMT " is %f \n", inode, (double)PetscRealPart(xx[inode]))); 439 PetscCall(VecRestoreArray(x, &xx)); 440 441 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 442 Now solve the nonlinear system 443 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 444 445 PetscCall(SNESSolve(snes, NULL, x)); 446 PetscCall(SNESGetIterationNumber(snes, &its)); 447 PetscCall(SNESGetNonlinearStepFailures(snes, &nfails)); 448 449 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 450 Print the output : solution vector and other information 451 Each processor writes to the file output.<rank> where rank is the 452 processor's rank. 453 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 454 455 PetscCall(VecGetArray(x, &xx)); 456 for (inode = 0; inode < user.Nvlocal; inode++) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fptr1, "Solution at node %" PetscInt_FMT " is %f \n", inode, (double)PetscRealPart(xx[inode]))); 457 PetscCall(VecRestoreArray(x, &xx)); 458 fclose(fptr1); 459 PetscCall(PetscPrintf(MPI_COMM_WORLD, "number of SNES iterations = %" PetscInt_FMT ", ", its)); 460 PetscCall(PetscPrintf(MPI_COMM_WORLD, "number of unsuccessful steps = %" PetscInt_FMT "\n", nfails)); 461 462 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 463 Free work space. All PETSc objects should be destroyed when they 464 are no longer needed. 465 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 466 PetscCall(PetscFree(user.gloInd)); 467 PetscCall(PetscFree(user.locInd)); 468 PetscCall(PetscFree(vertices)); 469 PetscCall(PetscFree(verticesmask)); 470 PetscCall(PetscFree(tmp)); 471 PetscCall(VecScatterDestroy(&user.scatter)); 472 PetscCall(ISLocalToGlobalMappingDestroy(&isl2g)); 473 PetscCall(VecDestroy(&x)); 474 PetscCall(VecDestroy(&r)); 475 PetscCall(VecDestroy(&user.localX)); 476 PetscCall(VecDestroy(&user.localF)); 477 PetscCall(SNESDestroy(&snes)); 478 PetscCall(MatDestroy(&Jac)); 479 /* PetscCall(PetscDrawDestroy(draw));*/ 480 if (fd_jacobian_coloring) PetscCall(MatFDColoringDestroy(&matfdcoloring)); 481 PetscCall(PetscFinalize()); 482 return 0; 483 } 484 /* -------------------- Form initial approximation ----------------- */ 485 486 /* 487 FormInitialGuess - Forms initial approximation. 488 489 Input Parameters: 490 user - user-defined application context 491 X - vector 492 493 Output Parameter: 494 X - vector 495 */ 496 PetscErrorCode FormInitialGuess(AppCtx *user, Vec X) 497 { 498 PetscInt Nvlocal; 499 PetscInt *gloInd; 500 PetscScalar *x; 501 #if defined(UNUSED_VARIABLES) 502 PetscReal temp1, temp, hx, hy, hxdhy, hydhx, sc; 503 PetscInt Neglobal, Nvglobal, j, row; 504 PetscReal alpha, lambda; 505 506 Nvglobal = user->Nvglobal; 507 Neglobal = user->Neglobal; 508 lambda = user->non_lin_param; 509 alpha = user->lin_param; 510 #endif 511 512 PetscFunctionBeginUser; 513 Nvlocal = user->Nvlocal; 514 gloInd = user->gloInd; 515 516 /* 517 Get a pointer to vector data. 518 - For default PETSc vectors, VecGetArray() returns a pointer to 519 the data array. Otherwise, the routine is implementation dependent. 520 - You MUST call VecRestoreArray() when you no longer need access to 521 the array. 522 */ 523 PetscCall(VecGetArray(X, &x)); 524 525 /* 526 Compute initial guess over the locally owned part of the grid 527 */ 528 for (PetscInt i = 0; i < Nvlocal; i++) x[i] = (PetscReal)gloInd[i]; 529 530 /* 531 Restore vector 532 */ 533 PetscCall(VecRestoreArray(X, &x)); 534 PetscFunctionReturn(PETSC_SUCCESS); 535 } 536 /* -------------------- Evaluate Function F(x) --------------------- */ 537 /* 538 FormFunction - Evaluates nonlinear function, F(x). 539 540 Input Parameters: 541 . snes - the SNES context 542 . X - input vector 543 . ptr - optional user-defined context, as set by SNESSetFunction() 544 545 Output Parameter: 546 . F - function vector 547 */ 548 PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *ptr) 549 { 550 AppCtx *user = (AppCtx *)ptr; 551 PetscInt Nvlocal; 552 PetscReal alpha, lambda; 553 PetscScalar *x, *f; 554 VecScatter scatter; 555 Vec localX = user->localX; 556 #if defined(UNUSED_VARIABLES) 557 PetscScalar ut, ub, ul, ur, u, *g, sc, uyy, uxx; 558 PetscReal hx, hy, hxdhy, hydhx; 559 PetscReal two = 2.0, one = 1.0; 560 PetscInt Nvglobal, Neglobal, row; 561 PetscInt *gloInd; 562 563 Nvglobal = user->Nvglobal; 564 Neglobal = user->Neglobal; 565 gloInd = user->gloInd; 566 #endif 567 568 PetscFunctionBeginUser; 569 Nvlocal = user->Nvlocal; 570 lambda = user->non_lin_param; 571 alpha = user->lin_param; 572 scatter = user->scatter; 573 574 /* 575 PDE : L(u) + lambda*u*u +alpha*u = 0 where L(u) is the approximate Laplacian as 576 described in the beginning of this code 577 578 First scatter the distributed vector X into local vector localX (that includes 579 values for ghost nodes. If we wish,we can put some other work between 580 VecScatterBegin() and VecScatterEnd() to overlap the communication with 581 computation. 582 */ 583 PetscCall(VecScatterBegin(scatter, X, localX, INSERT_VALUES, SCATTER_FORWARD)); 584 PetscCall(VecScatterEnd(scatter, X, localX, INSERT_VALUES, SCATTER_FORWARD)); 585 586 /* 587 Get pointers to vector data 588 */ 589 PetscCall(VecGetArray(localX, &x)); 590 PetscCall(VecGetArray(F, &f)); 591 592 /* 593 Now compute the f(x). As mentioned earlier, the computed Laplacian is just an 594 approximate one chosen for illustrative purpose only. Another point to notice 595 is that this is a local (completely parallel) calculation. In practical application 596 codes, function calculation time is a dominat portion of the overall execution time. 597 */ 598 for (PetscInt i = 0; i < Nvlocal; i++) { 599 f[i] = (user->itot[i] - alpha) * x[i] - lambda * x[i] * x[i]; 600 for (PetscInt j = 0; j < user->itot[i]; j++) f[i] -= x[user->AdjM[i][j]]; 601 } 602 603 /* 604 Restore vectors 605 */ 606 PetscCall(VecRestoreArray(localX, &x)); 607 PetscCall(VecRestoreArray(F, &f)); 608 /* PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD)); */ 609 PetscFunctionReturn(PETSC_SUCCESS); 610 } 611 612 /* -------------------- Evaluate Jacobian F'(x) -------------------- */ 613 /* 614 FormJacobian - Evaluates Jacobian matrix. 615 616 Input Parameters: 617 . snes - the SNES context 618 . X - input vector 619 . ptr - optional user-defined context, as set by SNESSetJacobian() 620 621 Output Parameters: 622 . A - Jacobian matrix 623 . B - optionally different preconditioning matrix 624 625 */ 626 PetscErrorCode FormJacobian(SNES snes, Vec X, Mat J, Mat jac, void *ptr) 627 { 628 AppCtx *user = (AppCtx *)ptr; 629 PetscInt Nvlocal, col[50]; 630 PetscScalar alpha, lambda, value[50]; 631 Vec localX = user->localX; 632 VecScatter scatter; 633 PetscScalar *x; 634 #if defined(UNUSED_VARIABLES) 635 PetscScalar two = 2.0, one = 1.0; 636 PetscInt row, Nvglobal, Neglobal; 637 PetscInt *gloInd; 638 639 Nvglobal = user->Nvglobal; 640 Neglobal = user->Neglobal; 641 gloInd = user->gloInd; 642 #endif 643 644 PetscFunctionBeginUser; 645 /*printf("Entering into FormJacobian \n");*/ 646 Nvlocal = user->Nvlocal; 647 lambda = user->non_lin_param; 648 alpha = user->lin_param; 649 scatter = user->scatter; 650 651 /* 652 PDE : L(u) + lambda*u*u +alpha*u = 0 where L(u) is the approximate Laplacian as 653 described in the beginning of this code 654 655 First scatter the distributed vector X into local vector localX (that includes 656 values for ghost nodes. If we wish, we can put some other work between 657 VecScatterBegin() and VecScatterEnd() to overlap the communication with 658 computation. 659 */ 660 PetscCall(VecScatterBegin(scatter, X, localX, INSERT_VALUES, SCATTER_FORWARD)); 661 PetscCall(VecScatterEnd(scatter, X, localX, INSERT_VALUES, SCATTER_FORWARD)); 662 663 /* 664 Get pointer to vector data 665 */ 666 PetscCall(VecGetArray(localX, &x)); 667 668 for (PetscInt i = 0; i < Nvlocal; i++) { 669 col[0] = i; 670 value[0] = user->itot[i] - 2.0 * lambda * x[i] - alpha; 671 for (PetscInt j = 0; j < user->itot[i]; j++) { 672 col[j + 1] = user->AdjM[i][j]; 673 value[j + 1] = -1.0; 674 } 675 676 /* 677 Set the matrix values in the local ordering. Note that in order to use this 678 feature we must call the routine MatSetLocalToGlobalMapping() after the 679 matrix has been created. 680 */ 681 PetscCall(MatSetValuesLocal(jac, 1, &i, 1 + user->itot[i], col, value, INSERT_VALUES)); 682 } 683 684 /* 685 Assemble matrix, using the 2-step process: 686 MatAssemblyBegin(), MatAssemblyEnd(). 687 Between these two calls, the pointer to vector data has been restored to 688 demonstrate the use of overlapping communicationn with computation. 689 */ 690 PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY)); 691 PetscCall(VecRestoreArray(localX, &x)); 692 PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY)); 693 694 /* 695 Tell the matrix we will never add a new nonzero location to the 696 matrix. If we do, it will generate an error. 697 */ 698 PetscCall(MatSetOption(jac, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE)); 699 /* MatView(jac,PETSC_VIEWER_STDOUT_SELF); */ 700 PetscFunctionReturn(PETSC_SUCCESS); 701 } 702 703 /*TEST 704 705 build: 706 requires: !complex 707 708 test: 709 nsize: 2 710 args: -snes_monitor_short 711 localrunfiles: options.inf adj.in 712 713 test: 714 suffix: 2 715 nsize: 2 716 args: -snes_monitor_short -fd_jacobian_coloring 717 localrunfiles: options.inf adj.in 718 719 TEST*/ 720