1c4762a1bSJed Brown static char help[] = "Newton's method to solve a two-variable system that comes from the Rosenbrock function.\n\n"; 2c4762a1bSJed Brown 3c4762a1bSJed Brown /* 4c4762a1bSJed Brown Include "petscsnes.h" so that we can use SNES solvers. Note that this 5c4762a1bSJed Brown file automatically includes: 6c4762a1bSJed Brown petscsys.h - base PETSc routines petscvec.h - vectors 7c4762a1bSJed Brown petscmat.h - matrices 8c4762a1bSJed Brown petscis.h - index sets petscksp.h - Krylov subspace methods 9c4762a1bSJed Brown petscviewer.h - viewers petscpc.h - preconditioners 10c4762a1bSJed Brown petscksp.h - linear solvers 11c4762a1bSJed Brown */ 12c4762a1bSJed Brown #include <petscsnes.h> 13c4762a1bSJed Brown 14c4762a1bSJed Brown extern PetscErrorCode FormJacobian1(SNES, Vec, Mat, Mat, void *); 15c4762a1bSJed Brown extern PetscErrorCode FormFunction1(SNES, Vec, Vec, void *); 16c4762a1bSJed Brown 17d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv) 18d71ae5a4SJacob Faibussowitsch { 19c4762a1bSJed Brown SNES snes; /* nonlinear solver context */ 2026e0b2e4SStefano Zampini Vec x; /* solution vector */ 21c4762a1bSJed Brown Mat J; /* Jacobian matrix */ 22c4762a1bSJed Brown PetscInt its; 23c4762a1bSJed Brown PetscScalar *xx; 24c4762a1bSJed Brown SNESConvergedReason reason; 2526e0b2e4SStefano Zampini PetscBool test_ghost = PETSC_FALSE; 26c4762a1bSJed Brown 27327415f7SBarry Smith PetscFunctionBeginUser; 28c8025a54SPierre Jolivet PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 2926e0b2e4SStefano Zampini PetscCall(PetscOptionsGetBool(NULL, NULL, "-test_ghost", &test_ghost, NULL)); 30c4762a1bSJed Brown 31c4762a1bSJed Brown /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 32c4762a1bSJed Brown Create nonlinear solver context 33c4762a1bSJed Brown - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 349566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes)); 35c4762a1bSJed Brown 36c4762a1bSJed Brown /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 37c4762a1bSJed Brown Create matrix and vector data structures; set corresponding routines 38c4762a1bSJed Brown - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 39c4762a1bSJed Brown /* 40c4762a1bSJed Brown Create vectors for solution and nonlinear function 41c4762a1bSJed Brown */ 4226e0b2e4SStefano Zampini if (test_ghost) { 4326e0b2e4SStefano Zampini PetscInt gIdx[] = {0, 1}; 4426e0b2e4SStefano Zampini PetscInt nghost = 2; 4526e0b2e4SStefano Zampini 4626e0b2e4SStefano Zampini PetscCall(PetscOptionsGetInt(NULL, NULL, "-nghost", &nghost, NULL)); 4726e0b2e4SStefano Zampini PetscCall(VecCreateGhost(PETSC_COMM_WORLD, 2, PETSC_DECIDE, PetscMin(nghost, 2), gIdx, &x)); 4826e0b2e4SStefano Zampini } else { 499566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_WORLD, &x)); 5026e0b2e4SStefano Zampini PetscCall(VecSetSizes(x, 2, PETSC_DECIDE)); 519566063dSJacob Faibussowitsch PetscCall(VecSetFromOptions(x)); 5226e0b2e4SStefano Zampini } 53c4762a1bSJed Brown 54c4762a1bSJed Brown /* 55c4762a1bSJed Brown Create Jacobian matrix data structure 56c4762a1bSJed Brown */ 579566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_WORLD, &J)); 5826e0b2e4SStefano Zampini PetscCall(MatSetSizes(J, 2, 2, PETSC_DECIDE, PETSC_DECIDE)); 599566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(J)); 609566063dSJacob Faibussowitsch PetscCall(MatSetUp(J)); 61c4762a1bSJed Brown 62c4762a1bSJed Brown /* 63c4762a1bSJed Brown Set function evaluation routine and vector. 64c4762a1bSJed Brown */ 6526e0b2e4SStefano Zampini PetscCall(SNESSetFunction(snes, NULL, FormFunction1, &test_ghost)); 66c4762a1bSJed Brown 67c4762a1bSJed Brown /* 68c4762a1bSJed Brown Set Jacobian matrix data structure and Jacobian evaluation routine 69c4762a1bSJed Brown */ 7026e0b2e4SStefano Zampini PetscCall(SNESSetJacobian(snes, J, J, FormJacobian1, &test_ghost)); 71c4762a1bSJed Brown 72c4762a1bSJed Brown /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 73c4762a1bSJed Brown Customize nonlinear solver; set runtime options 74c4762a1bSJed Brown - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 759566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 76c4762a1bSJed Brown 77c4762a1bSJed Brown /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 78c4762a1bSJed Brown Evaluate initial guess; then solve nonlinear system 79c4762a1bSJed Brown - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 809566063dSJacob Faibussowitsch PetscCall(VecGetArray(x, &xx)); 819371c9d4SSatish Balay xx[0] = -1.2; 829371c9d4SSatish Balay xx[1] = 1.0; 839566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(x, &xx)); 84c4762a1bSJed Brown 85c4762a1bSJed Brown /* 86c4762a1bSJed Brown Note: The user should initialize the vector, x, with the initial guess 87c4762a1bSJed Brown for the nonlinear solver prior to calling SNESSolve(). In particular, 88c4762a1bSJed Brown to employ an initial guess of zero, the user should explicitly set 89c4762a1bSJed Brown this vector to zero by calling VecSet(). 90c4762a1bSJed Brown */ 91c4762a1bSJed Brown 929566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, NULL, x)); 9326e0b2e4SStefano Zampini PetscCall(VecViewFromOptions(x, NULL, "-sol_view")); 949566063dSJacob Faibussowitsch PetscCall(SNESGetIterationNumber(snes, &its)); 959566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes, &reason)); 96c4762a1bSJed Brown /* 97c4762a1bSJed Brown Some systems computes a residual that is identically zero, thus converging 98c4762a1bSJed Brown due to FNORM_ABS, others converge due to FNORM_RELATIVE. Here, we only 99c4762a1bSJed Brown report the reason if the iteration did not converge so that the tests are 100c4762a1bSJed Brown reproducible. 101c4762a1bSJed Brown */ 10263a3b9bcSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%s number of SNES iterations = %" PetscInt_FMT "\n", reason > 0 ? "CONVERGED" : SNESConvergedReasons[reason], its)); 103c4762a1bSJed Brown 104c4762a1bSJed Brown /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 105c4762a1bSJed Brown Free work space. All PETSc objects should be destroyed when they 106c4762a1bSJed Brown are no longer needed. 107c4762a1bSJed Brown - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 108c4762a1bSJed Brown 1099371c9d4SSatish Balay PetscCall(VecDestroy(&x)); 1109371c9d4SSatish Balay PetscCall(MatDestroy(&J)); 1119371c9d4SSatish Balay PetscCall(SNESDestroy(&snes)); 1129566063dSJacob Faibussowitsch PetscCall(PetscFinalize()); 113b122ec5aSJacob Faibussowitsch return 0; 114c4762a1bSJed Brown } 115c4762a1bSJed Brown 11626e0b2e4SStefano Zampini PetscErrorCode VecCheckGhosted(Vec X, PetscBool test_rev) 11726e0b2e4SStefano Zampini { 11826e0b2e4SStefano Zampini PetscFunctionBeginUser; 11926e0b2e4SStefano Zampini PetscCall(VecGhostUpdateBegin(X, INSERT_VALUES, SCATTER_FORWARD)); 12026e0b2e4SStefano Zampini PetscCall(VecGhostUpdateEnd(X, INSERT_VALUES, SCATTER_FORWARD)); 12126e0b2e4SStefano Zampini if (test_rev) { 12226e0b2e4SStefano Zampini PetscCall(VecGhostUpdateBegin(X, INSERT_VALUES, SCATTER_REVERSE)); 12326e0b2e4SStefano Zampini PetscCall(VecGhostUpdateEnd(X, INSERT_VALUES, SCATTER_REVERSE)); 12426e0b2e4SStefano Zampini } 12526e0b2e4SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 12626e0b2e4SStefano Zampini } 127c4762a1bSJed Brown 128*2a8381b2SBarry Smith PetscErrorCode FormFunction1(SNES snes, Vec x, Vec f, PetscCtx ctx) 129d71ae5a4SJacob Faibussowitsch { 130c4762a1bSJed Brown PetscScalar *ff; 131c4762a1bSJed Brown const PetscScalar *xx; 132c4762a1bSJed Brown 1333ba16761SJacob Faibussowitsch PetscFunctionBeginUser; 13426e0b2e4SStefano Zampini if (*(PetscBool *)ctx) { 13526e0b2e4SStefano Zampini PetscCall(VecCheckGhosted(x, PETSC_FALSE)); 13626e0b2e4SStefano Zampini PetscCall(VecCheckGhosted(f, PETSC_TRUE)); 13726e0b2e4SStefano Zampini } 13826e0b2e4SStefano Zampini 139c4762a1bSJed Brown /* 140c4762a1bSJed Brown Get pointers to vector data. 141c4762a1bSJed Brown - For default PETSc vectors, VecGetArray() returns a pointer to 142c4762a1bSJed Brown the data array. Otherwise, the routine is implementation dependent. 143c4762a1bSJed Brown - You MUST call VecRestoreArray() when you no longer need access to 144c4762a1bSJed Brown the array. 145c4762a1bSJed Brown */ 1469566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(x, &xx)); 1479566063dSJacob Faibussowitsch PetscCall(VecGetArray(f, &ff)); 148c4762a1bSJed Brown 149c4762a1bSJed Brown /* Compute function */ 150c4762a1bSJed Brown ff[0] = -2.0 + 2.0 * xx[0] + 400.0 * xx[0] * xx[0] * xx[0] - 400.0 * xx[0] * xx[1]; 151c4762a1bSJed Brown ff[1] = -200.0 * xx[0] * xx[0] + 200.0 * xx[1]; 152c4762a1bSJed Brown 153c4762a1bSJed Brown /* Restore vectors */ 1549566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(x, &xx)); 1559566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(f, &ff)); 1563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 157c4762a1bSJed Brown } 158c4762a1bSJed Brown 159*2a8381b2SBarry Smith PetscErrorCode FormJacobian1(SNES snes, Vec x, Mat jac, Mat B, PetscCtx ctx) 160d71ae5a4SJacob Faibussowitsch { 161c4762a1bSJed Brown const PetscScalar *xx; 162c4762a1bSJed Brown PetscScalar A[4]; 16326e0b2e4SStefano Zampini PetscInt idx[2]; 16426e0b2e4SStefano Zampini PetscMPIInt rank; 165c4762a1bSJed Brown 1663ba16761SJacob Faibussowitsch PetscFunctionBeginUser; 1673a7d0413SPierre Jolivet if (*(PetscBool *)ctx) PetscCall(VecCheckGhosted(x, PETSC_FALSE)); 168c4762a1bSJed Brown /* 169c4762a1bSJed Brown Get pointer to vector data 170c4762a1bSJed Brown */ 1719566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(x, &xx)); 172c4762a1bSJed Brown 173c4762a1bSJed Brown /* 174c4762a1bSJed Brown Compute Jacobian entries and insert into matrix. 175c4762a1bSJed Brown - Since this is such a small problem, we set all entries for 176c4762a1bSJed Brown the matrix at once. 177c4762a1bSJed Brown */ 178c4762a1bSJed Brown A[0] = 2.0 + 1200.0 * xx[0] * xx[0] - 400.0 * xx[1]; 179c4762a1bSJed Brown A[1] = -400.0 * xx[0]; 180c4762a1bSJed Brown A[2] = -400.0 * xx[0]; 181c4762a1bSJed Brown A[3] = 200; 18226e0b2e4SStefano Zampini 18326e0b2e4SStefano Zampini PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)x), &rank)); 18426e0b2e4SStefano Zampini idx[0] = 2 * rank; 18526e0b2e4SStefano Zampini idx[1] = 2 * rank + 1; 18626e0b2e4SStefano Zampini 1879566063dSJacob Faibussowitsch PetscCall(MatSetValues(B, 2, idx, 2, idx, A, INSERT_VALUES)); 188c4762a1bSJed Brown 189c4762a1bSJed Brown /* 190c4762a1bSJed Brown Restore vector 191c4762a1bSJed Brown */ 1929566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(x, &xx)); 193c4762a1bSJed Brown 194c4762a1bSJed Brown /* 195c4762a1bSJed Brown Assemble matrix 196c4762a1bSJed Brown */ 1979566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 1989566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 199c4762a1bSJed Brown if (jac != B) { 2009566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY)); 2019566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY)); 202c4762a1bSJed Brown } 2033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 204c4762a1bSJed Brown } 205c4762a1bSJed Brown 206c4762a1bSJed Brown /*TEST 207c4762a1bSJed Brown 208c4762a1bSJed Brown test: 20941ba4c6cSHeeho Park suffix: 1 21026e0b2e4SStefano Zampini args: -snes_monitor_short -snes_max_it 1000 -sol_view 211c4762a1bSJed Brown requires: !single 212c4762a1bSJed Brown 21341ba4c6cSHeeho Park test: 21441ba4c6cSHeeho Park suffix: 2 21526e0b2e4SStefano Zampini args: -snes_monitor_short -snes_max_it 1000 -snes_type newtontrdc -snes_trdc_use_cauchy false -sol_view 21626e0b2e4SStefano Zampini requires: !single 21726e0b2e4SStefano Zampini 21826e0b2e4SStefano Zampini test: 21926e0b2e4SStefano Zampini suffix: ghosts 22026e0b2e4SStefano Zampini nsize: {{1 2}} 22126e0b2e4SStefano Zampini args: -snes_max_it 4 -snes_type {{newtontr newtonls}} -nghost {{0 1 2}} -test_ghost 22241ba4c6cSHeeho Park requires: !single 22341ba4c6cSHeeho Park 224c4762a1bSJed Brown TEST*/ 225