1*c2fc9fa9SBarry Smith 2*c2fc9fa9SBarry Smith #include <../src/snes/impls/vi/ss/vissimpl.h> /*I "petscsnes.h" I*/ 3*c2fc9fa9SBarry Smith #include <../include/private/kspimpl.h> 4*c2fc9fa9SBarry Smith #include <../include/private/matimpl.h> 5*c2fc9fa9SBarry Smith #include <../include/private/dmimpl.h> 6*c2fc9fa9SBarry Smith 7*c2fc9fa9SBarry Smith 8*c2fc9fa9SBarry Smith /* 9*c2fc9fa9SBarry Smith SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem. 10*c2fc9fa9SBarry Smith 11*c2fc9fa9SBarry Smith Input Parameter: 12*c2fc9fa9SBarry Smith . phi - the semismooth function 13*c2fc9fa9SBarry Smith 14*c2fc9fa9SBarry Smith Output Parameter: 15*c2fc9fa9SBarry Smith . merit - the merit function 16*c2fc9fa9SBarry Smith . phinorm - ||phi|| 17*c2fc9fa9SBarry Smith 18*c2fc9fa9SBarry Smith Notes: 19*c2fc9fa9SBarry Smith The merit function for the mixed complementarity problem is defined as 20*c2fc9fa9SBarry Smith merit = 0.5*phi^T*phi 21*c2fc9fa9SBarry Smith */ 22*c2fc9fa9SBarry Smith #undef __FUNCT__ 23*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESVIComputeMeritFunction" 24*c2fc9fa9SBarry Smith static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal* merit,PetscReal* phinorm) 25*c2fc9fa9SBarry Smith { 26*c2fc9fa9SBarry Smith PetscErrorCode ierr; 27*c2fc9fa9SBarry Smith 28*c2fc9fa9SBarry Smith PetscFunctionBegin; 29*c2fc9fa9SBarry Smith ierr = VecNormBegin(phi,NORM_2,phinorm);CHKERRQ(ierr); 30*c2fc9fa9SBarry Smith ierr = VecNormEnd(phi,NORM_2,phinorm);CHKERRQ(ierr); 31*c2fc9fa9SBarry Smith 32*c2fc9fa9SBarry Smith *merit = 0.5*(*phinorm)*(*phinorm); 33*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 34*c2fc9fa9SBarry Smith } 35*c2fc9fa9SBarry Smith 36*c2fc9fa9SBarry Smith PETSC_STATIC_INLINE PetscScalar Phi(PetscScalar a,PetscScalar b) 37*c2fc9fa9SBarry Smith { 38*c2fc9fa9SBarry Smith return a + b - PetscSqrtScalar(a*a + b*b); 39*c2fc9fa9SBarry Smith } 40*c2fc9fa9SBarry Smith 41*c2fc9fa9SBarry Smith PETSC_STATIC_INLINE PetscScalar DPhi(PetscScalar a,PetscScalar b) 42*c2fc9fa9SBarry Smith { 43*c2fc9fa9SBarry Smith if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return 1.0 - a/ PetscSqrtScalar(a*a + b*b); 44*c2fc9fa9SBarry Smith else return .5; 45*c2fc9fa9SBarry Smith } 46*c2fc9fa9SBarry Smith 47*c2fc9fa9SBarry Smith /* 48*c2fc9fa9SBarry Smith SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form. 49*c2fc9fa9SBarry Smith 50*c2fc9fa9SBarry Smith Input Parameters: 51*c2fc9fa9SBarry Smith . snes - the SNES context 52*c2fc9fa9SBarry Smith . x - current iterate 53*c2fc9fa9SBarry Smith . functx - user defined function context 54*c2fc9fa9SBarry Smith 55*c2fc9fa9SBarry Smith Output Parameters: 56*c2fc9fa9SBarry Smith . phi - Semismooth function 57*c2fc9fa9SBarry Smith 58*c2fc9fa9SBarry Smith */ 59*c2fc9fa9SBarry Smith #undef __FUNCT__ 60*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESVIComputeFunction" 61*c2fc9fa9SBarry Smith static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void* functx) 62*c2fc9fa9SBarry Smith { 63*c2fc9fa9SBarry Smith PetscErrorCode ierr; 64*c2fc9fa9SBarry Smith SNES_VISS *vi = (SNES_VISS*)snes->data; 65*c2fc9fa9SBarry Smith Vec Xl = snes->xl,Xu = snes->xu,F = snes->vec_func; 66*c2fc9fa9SBarry Smith PetscScalar *phi_arr,*x_arr,*f_arr,*l,*u; 67*c2fc9fa9SBarry Smith PetscInt i,nlocal; 68*c2fc9fa9SBarry Smith 69*c2fc9fa9SBarry Smith PetscFunctionBegin; 70*c2fc9fa9SBarry Smith ierr = (*vi->computeuserfunction)(snes,X,F,functx);CHKERRQ(ierr); 71*c2fc9fa9SBarry Smith ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr); 72*c2fc9fa9SBarry Smith ierr = VecGetArray(X,&x_arr);CHKERRQ(ierr); 73*c2fc9fa9SBarry Smith ierr = VecGetArray(F,&f_arr);CHKERRQ(ierr); 74*c2fc9fa9SBarry Smith ierr = VecGetArray(Xl,&l);CHKERRQ(ierr); 75*c2fc9fa9SBarry Smith ierr = VecGetArray(Xu,&u);CHKERRQ(ierr); 76*c2fc9fa9SBarry Smith ierr = VecGetArray(phi,&phi_arr);CHKERRQ(ierr); 77*c2fc9fa9SBarry Smith 78*c2fc9fa9SBarry Smith for (i=0;i < nlocal;i++) { 79*c2fc9fa9SBarry Smith if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) { /* no constraints on variable */ 80*c2fc9fa9SBarry Smith phi_arr[i] = f_arr[i]; 81*c2fc9fa9SBarry Smith } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) { /* upper bound on variable only */ 82*c2fc9fa9SBarry Smith phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]); 83*c2fc9fa9SBarry Smith } else if (PetscRealPart(u[i]) >= SNES_VI_INF) { /* lower bound on variable only */ 84*c2fc9fa9SBarry Smith phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]); 85*c2fc9fa9SBarry Smith } else if (l[i] == u[i]) { 86*c2fc9fa9SBarry Smith phi_arr[i] = l[i] - x_arr[i]; 87*c2fc9fa9SBarry Smith } else { /* both bounds on variable */ 88*c2fc9fa9SBarry Smith phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i])); 89*c2fc9fa9SBarry Smith } 90*c2fc9fa9SBarry Smith } 91*c2fc9fa9SBarry Smith 92*c2fc9fa9SBarry Smith ierr = VecRestoreArray(X,&x_arr);CHKERRQ(ierr); 93*c2fc9fa9SBarry Smith ierr = VecRestoreArray(F,&f_arr);CHKERRQ(ierr); 94*c2fc9fa9SBarry Smith ierr = VecRestoreArray(Xl,&l);CHKERRQ(ierr); 95*c2fc9fa9SBarry Smith ierr = VecRestoreArray(Xu,&u);CHKERRQ(ierr); 96*c2fc9fa9SBarry Smith ierr = VecRestoreArray(phi,&phi_arr);CHKERRQ(ierr); 97*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 98*c2fc9fa9SBarry Smith } 99*c2fc9fa9SBarry Smith 100*c2fc9fa9SBarry Smith /* 101*c2fc9fa9SBarry Smith SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the 102*c2fc9fa9SBarry Smith the semismooth jacobian. 103*c2fc9fa9SBarry Smith */ 104*c2fc9fa9SBarry Smith #undef __FUNCT__ 105*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESVIComputeBsubdifferentialVectors" 106*c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db) 107*c2fc9fa9SBarry Smith { 108*c2fc9fa9SBarry Smith PetscErrorCode ierr; 109*c2fc9fa9SBarry Smith PetscScalar *l,*u,*x,*f,*da,*db,da1,da2,db1,db2; 110*c2fc9fa9SBarry Smith PetscInt i,nlocal; 111*c2fc9fa9SBarry Smith 112*c2fc9fa9SBarry Smith PetscFunctionBegin; 113*c2fc9fa9SBarry Smith 114*c2fc9fa9SBarry Smith ierr = VecGetArray(X,&x);CHKERRQ(ierr); 115*c2fc9fa9SBarry Smith ierr = VecGetArray(F,&f);CHKERRQ(ierr); 116*c2fc9fa9SBarry Smith ierr = VecGetArray(snes->xl,&l);CHKERRQ(ierr); 117*c2fc9fa9SBarry Smith ierr = VecGetArray(snes->xu,&u);CHKERRQ(ierr); 118*c2fc9fa9SBarry Smith ierr = VecGetArray(Da,&da);CHKERRQ(ierr); 119*c2fc9fa9SBarry Smith ierr = VecGetArray(Db,&db);CHKERRQ(ierr); 120*c2fc9fa9SBarry Smith ierr = VecGetLocalSize(X,&nlocal);CHKERRQ(ierr); 121*c2fc9fa9SBarry Smith 122*c2fc9fa9SBarry Smith for (i=0;i< nlocal;i++) { 123*c2fc9fa9SBarry Smith if ((PetscRealPart(l[i]) <= SNES_VI_NINF) && (PetscRealPart(u[i]) >= SNES_VI_INF)) {/* no constraints on variable */ 124*c2fc9fa9SBarry Smith da[i] = 0; 125*c2fc9fa9SBarry Smith db[i] = 1; 126*c2fc9fa9SBarry Smith } else if (PetscRealPart(l[i]) <= SNES_VI_NINF) { /* upper bound on variable only */ 127*c2fc9fa9SBarry Smith da[i] = DPhi(u[i] - x[i], -f[i]); 128*c2fc9fa9SBarry Smith db[i] = DPhi(-f[i],u[i] - x[i]); 129*c2fc9fa9SBarry Smith } else if (PetscRealPart(u[i]) >= SNES_VI_INF) { /* lower bound on variable only */ 130*c2fc9fa9SBarry Smith da[i] = DPhi(x[i] - l[i], f[i]); 131*c2fc9fa9SBarry Smith db[i] = DPhi(f[i],x[i] - l[i]); 132*c2fc9fa9SBarry Smith } else if (l[i] == u[i]) { /* fixed variable */ 133*c2fc9fa9SBarry Smith da[i] = 1; 134*c2fc9fa9SBarry Smith db[i] = 0; 135*c2fc9fa9SBarry Smith } else { /* upper and lower bounds on variable */ 136*c2fc9fa9SBarry Smith da1 = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i])); 137*c2fc9fa9SBarry Smith db1 = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]); 138*c2fc9fa9SBarry Smith da2 = DPhi(u[i] - x[i], -f[i]); 139*c2fc9fa9SBarry Smith db2 = DPhi(-f[i],u[i] - x[i]); 140*c2fc9fa9SBarry Smith da[i] = da1 + db1*da2; 141*c2fc9fa9SBarry Smith db[i] = db1*db2; 142*c2fc9fa9SBarry Smith } 143*c2fc9fa9SBarry Smith } 144*c2fc9fa9SBarry Smith 145*c2fc9fa9SBarry Smith ierr = VecRestoreArray(X,&x);CHKERRQ(ierr); 146*c2fc9fa9SBarry Smith ierr = VecRestoreArray(F,&f);CHKERRQ(ierr); 147*c2fc9fa9SBarry Smith ierr = VecRestoreArray(snes->xl,&l);CHKERRQ(ierr); 148*c2fc9fa9SBarry Smith ierr = VecRestoreArray(snes->xu,&u);CHKERRQ(ierr); 149*c2fc9fa9SBarry Smith ierr = VecRestoreArray(Da,&da);CHKERRQ(ierr); 150*c2fc9fa9SBarry Smith ierr = VecRestoreArray(Db,&db);CHKERRQ(ierr); 151*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 152*c2fc9fa9SBarry Smith } 153*c2fc9fa9SBarry Smith 154*c2fc9fa9SBarry Smith /* 155*c2fc9fa9SBarry Smith SNESVIComputeJacobian - Computes the jacobian of the semismooth function.The Jacobian for the semismooth function is an element of the B-subdifferential of the Fischer-Burmeister function for complementarity problems. 156*c2fc9fa9SBarry Smith 157*c2fc9fa9SBarry Smith Input Parameters: 158*c2fc9fa9SBarry Smith . Da - Diagonal shift vector for the semismooth jacobian. 159*c2fc9fa9SBarry Smith . Db - Row scaling vector for the semismooth jacobian. 160*c2fc9fa9SBarry Smith 161*c2fc9fa9SBarry Smith Output Parameters: 162*c2fc9fa9SBarry Smith . jac - semismooth jacobian 163*c2fc9fa9SBarry Smith . jac_pre - optional preconditioning matrix 164*c2fc9fa9SBarry Smith 165*c2fc9fa9SBarry Smith Notes: 166*c2fc9fa9SBarry Smith The semismooth jacobian matrix is given by 167*c2fc9fa9SBarry Smith jac = Da + Db*jacfun 168*c2fc9fa9SBarry Smith where Db is the row scaling matrix stored as a vector, 169*c2fc9fa9SBarry Smith Da is the diagonal perturbation matrix stored as a vector 170*c2fc9fa9SBarry Smith and jacfun is the jacobian of the original nonlinear function. 171*c2fc9fa9SBarry Smith */ 172*c2fc9fa9SBarry Smith #undef __FUNCT__ 173*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESVIComputeJacobian" 174*c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db) 175*c2fc9fa9SBarry Smith { 176*c2fc9fa9SBarry Smith PetscErrorCode ierr; 177*c2fc9fa9SBarry Smith 178*c2fc9fa9SBarry Smith /* Do row scaling and add diagonal perturbation */ 179*c2fc9fa9SBarry Smith ierr = MatDiagonalScale(jac,Db,PETSC_NULL);CHKERRQ(ierr); 180*c2fc9fa9SBarry Smith ierr = MatDiagonalSet(jac,Da,ADD_VALUES);CHKERRQ(ierr); 181*c2fc9fa9SBarry Smith if (jac != jac_pre) { /* If jac and jac_pre are different */ 182*c2fc9fa9SBarry Smith ierr = MatDiagonalScale(jac_pre,Db,PETSC_NULL); 183*c2fc9fa9SBarry Smith ierr = MatDiagonalSet(jac_pre,Da,ADD_VALUES);CHKERRQ(ierr); 184*c2fc9fa9SBarry Smith } 185*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 186*c2fc9fa9SBarry Smith } 187*c2fc9fa9SBarry Smith 188*c2fc9fa9SBarry Smith /* 189*c2fc9fa9SBarry Smith SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi. 190*c2fc9fa9SBarry Smith 191*c2fc9fa9SBarry Smith Input Parameters: 192*c2fc9fa9SBarry Smith phi - semismooth function. 193*c2fc9fa9SBarry Smith H - semismooth jacobian 194*c2fc9fa9SBarry Smith 195*c2fc9fa9SBarry Smith Output Parameters: 196*c2fc9fa9SBarry Smith dpsi - merit function gradient 197*c2fc9fa9SBarry Smith 198*c2fc9fa9SBarry Smith Notes: 199*c2fc9fa9SBarry Smith The merit function gradient is computed as follows 200*c2fc9fa9SBarry Smith dpsi = H^T*phi 201*c2fc9fa9SBarry Smith */ 202*c2fc9fa9SBarry Smith #undef __FUNCT__ 203*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESVIComputeMeritFunctionGradient" 204*c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi) 205*c2fc9fa9SBarry Smith { 206*c2fc9fa9SBarry Smith PetscErrorCode ierr; 207*c2fc9fa9SBarry Smith 208*c2fc9fa9SBarry Smith PetscFunctionBegin; 209*c2fc9fa9SBarry Smith ierr = MatMultTranspose(H,phi,dpsi);CHKERRQ(ierr); 210*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 211*c2fc9fa9SBarry Smith } 212*c2fc9fa9SBarry Smith 213*c2fc9fa9SBarry Smith 214*c2fc9fa9SBarry Smith 215*c2fc9fa9SBarry Smith /* 216*c2fc9fa9SBarry Smith SNESSolve_VISS - Solves the complementarity problem with a semismooth Newton 217*c2fc9fa9SBarry Smith method using a line search. 218*c2fc9fa9SBarry Smith 219*c2fc9fa9SBarry Smith Input Parameters: 220*c2fc9fa9SBarry Smith . snes - the SNES context 221*c2fc9fa9SBarry Smith 222*c2fc9fa9SBarry Smith Output Parameter: 223*c2fc9fa9SBarry Smith . outits - number of iterations until termination 224*c2fc9fa9SBarry Smith 225*c2fc9fa9SBarry Smith Application Interface Routine: SNESSolve() 226*c2fc9fa9SBarry Smith 227*c2fc9fa9SBarry Smith Notes: 228*c2fc9fa9SBarry Smith This implements essentially a semismooth Newton method with a 229*c2fc9fa9SBarry Smith line search. The default line search does not do any line seach 230*c2fc9fa9SBarry Smith but rather takes a full newton step. 231*c2fc9fa9SBarry Smith */ 232*c2fc9fa9SBarry Smith #undef __FUNCT__ 233*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESSolve_VISS" 234*c2fc9fa9SBarry Smith PetscErrorCode SNESSolve_VISS(SNES snes) 235*c2fc9fa9SBarry Smith { 236*c2fc9fa9SBarry Smith SNES_VISS *vi = (SNES_VISS*)snes->data; 237*c2fc9fa9SBarry Smith PetscErrorCode ierr; 238*c2fc9fa9SBarry Smith PetscInt maxits,i,lits; 239*c2fc9fa9SBarry Smith PetscBool lssucceed; 240*c2fc9fa9SBarry Smith MatStructure flg = DIFFERENT_NONZERO_PATTERN; 241*c2fc9fa9SBarry Smith PetscReal gnorm,xnorm=0,ynorm; 242*c2fc9fa9SBarry Smith Vec Y,X,F,G,W; 243*c2fc9fa9SBarry Smith KSPConvergedReason kspreason; 244*c2fc9fa9SBarry Smith 245*c2fc9fa9SBarry Smith PetscFunctionBegin; 246*c2fc9fa9SBarry Smith vi->computeuserfunction = snes->ops->computefunction; 247*c2fc9fa9SBarry Smith snes->ops->computefunction = SNESVIComputeFunction; 248*c2fc9fa9SBarry Smith 249*c2fc9fa9SBarry Smith snes->numFailures = 0; 250*c2fc9fa9SBarry Smith snes->numLinearSolveFailures = 0; 251*c2fc9fa9SBarry Smith snes->reason = SNES_CONVERGED_ITERATING; 252*c2fc9fa9SBarry Smith 253*c2fc9fa9SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 254*c2fc9fa9SBarry Smith X = snes->vec_sol; /* solution vector */ 255*c2fc9fa9SBarry Smith F = snes->vec_func; /* residual vector */ 256*c2fc9fa9SBarry Smith Y = snes->work[0]; /* work vectors */ 257*c2fc9fa9SBarry Smith G = snes->work[1]; 258*c2fc9fa9SBarry Smith W = snes->work[2]; 259*c2fc9fa9SBarry Smith 260*c2fc9fa9SBarry Smith ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 261*c2fc9fa9SBarry Smith snes->iter = 0; 262*c2fc9fa9SBarry Smith snes->norm = 0.0; 263*c2fc9fa9SBarry Smith ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 264*c2fc9fa9SBarry Smith 265*c2fc9fa9SBarry Smith ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr); 266*c2fc9fa9SBarry Smith ierr = SNESComputeFunction(snes,X,vi->phi);CHKERRQ(ierr); 267*c2fc9fa9SBarry Smith if (snes->domainerror) { 268*c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 269*c2fc9fa9SBarry Smith snes->ops->computefunction = vi->computeuserfunction; 270*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 271*c2fc9fa9SBarry Smith } 272*c2fc9fa9SBarry Smith /* Compute Merit function */ 273*c2fc9fa9SBarry Smith ierr = SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm);CHKERRQ(ierr); 274*c2fc9fa9SBarry Smith 275*c2fc9fa9SBarry Smith ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm <- ||x|| */ 276*c2fc9fa9SBarry Smith ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr); 277*c2fc9fa9SBarry Smith if (PetscIsInfOrNanReal(vi->merit)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 278*c2fc9fa9SBarry Smith 279*c2fc9fa9SBarry Smith ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 280*c2fc9fa9SBarry Smith snes->norm = vi->phinorm; 281*c2fc9fa9SBarry Smith ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 282*c2fc9fa9SBarry Smith SNESLogConvHistory(snes,vi->phinorm,0); 283*c2fc9fa9SBarry Smith ierr = SNESMonitor(snes,0,vi->phinorm);CHKERRQ(ierr); 284*c2fc9fa9SBarry Smith 285*c2fc9fa9SBarry Smith /* set parameter for default relative tolerance convergence test */ 286*c2fc9fa9SBarry Smith snes->ttol = vi->phinorm*snes->rtol; 287*c2fc9fa9SBarry Smith /* test convergence */ 288*c2fc9fa9SBarry Smith ierr = (*snes->ops->converged)(snes,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 289*c2fc9fa9SBarry Smith if (snes->reason) { 290*c2fc9fa9SBarry Smith snes->ops->computefunction = vi->computeuserfunction; 291*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 292*c2fc9fa9SBarry Smith } 293*c2fc9fa9SBarry Smith 294*c2fc9fa9SBarry Smith for (i=0; i<maxits; i++) { 295*c2fc9fa9SBarry Smith 296*c2fc9fa9SBarry Smith /* Call general purpose update function */ 297*c2fc9fa9SBarry Smith if (snes->ops->update) { 298*c2fc9fa9SBarry Smith ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 299*c2fc9fa9SBarry Smith } 300*c2fc9fa9SBarry Smith 301*c2fc9fa9SBarry Smith /* Solve J Y = Phi, where J is the semismooth jacobian */ 302*c2fc9fa9SBarry Smith /* Get the nonlinear function jacobian */ 303*c2fc9fa9SBarry Smith ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 304*c2fc9fa9SBarry Smith /* Get the diagonal shift and row scaling vectors */ 305*c2fc9fa9SBarry Smith ierr = SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db);CHKERRQ(ierr); 306*c2fc9fa9SBarry Smith /* Compute the semismooth jacobian */ 307*c2fc9fa9SBarry Smith ierr = SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db);CHKERRQ(ierr); 308*c2fc9fa9SBarry Smith /* Compute the merit function gradient */ 309*c2fc9fa9SBarry Smith ierr = SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi);CHKERRQ(ierr); 310*c2fc9fa9SBarry Smith ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 311*c2fc9fa9SBarry Smith ierr = SNES_KSPSolve(snes,snes->ksp,vi->phi,Y);CHKERRQ(ierr); 312*c2fc9fa9SBarry Smith ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 313*c2fc9fa9SBarry Smith 314*c2fc9fa9SBarry Smith if (kspreason < 0) { 315*c2fc9fa9SBarry Smith if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 316*c2fc9fa9SBarry Smith ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 317*c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 318*c2fc9fa9SBarry Smith break; 319*c2fc9fa9SBarry Smith } 320*c2fc9fa9SBarry Smith } 321*c2fc9fa9SBarry Smith ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 322*c2fc9fa9SBarry Smith snes->linear_its += lits; 323*c2fc9fa9SBarry Smith ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr); 324*c2fc9fa9SBarry Smith /* 325*c2fc9fa9SBarry Smith if (snes->ops->precheckstep) { 326*c2fc9fa9SBarry Smith PetscBool changed_y = PETSC_FALSE; 327*c2fc9fa9SBarry Smith ierr = (*snes->ops->precheckstep)(snes,X,Y,snes->precheck,&changed_y);CHKERRQ(ierr); 328*c2fc9fa9SBarry Smith } 329*c2fc9fa9SBarry Smith 330*c2fc9fa9SBarry Smith if (PetscLogPrintInfo){ 331*c2fc9fa9SBarry Smith ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr); 332*c2fc9fa9SBarry Smith } 333*c2fc9fa9SBarry Smith */ 334*c2fc9fa9SBarry Smith /* Compute a (scaled) negative update in the line search routine: 335*c2fc9fa9SBarry Smith Y <- X - lambda*Y 336*c2fc9fa9SBarry Smith and evaluate G = function(Y) (depends on the line search). 337*c2fc9fa9SBarry Smith */ 338*c2fc9fa9SBarry Smith ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr); 339*c2fc9fa9SBarry Smith ynorm = 1; gnorm = vi->phinorm; 340*c2fc9fa9SBarry Smith ierr = (*snes->ops->linesearch)(snes,snes->lsP,X,vi->phi,Y,vi->phinorm,xnorm,G,W,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr); 341*c2fc9fa9SBarry Smith ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)vi->phinorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr); 342*c2fc9fa9SBarry Smith if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 343*c2fc9fa9SBarry Smith if (snes->domainerror) { 344*c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 345*c2fc9fa9SBarry Smith snes->ops->computefunction = vi->computeuserfunction; 346*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 347*c2fc9fa9SBarry Smith } 348*c2fc9fa9SBarry Smith if (!lssucceed) { 349*c2fc9fa9SBarry Smith if (++snes->numFailures >= snes->maxFailures) { 350*c2fc9fa9SBarry Smith PetscBool ismin; 351*c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_LINE_SEARCH; 352*c2fc9fa9SBarry Smith ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,G,W,gnorm,&ismin);CHKERRQ(ierr); 353*c2fc9fa9SBarry Smith if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 354*c2fc9fa9SBarry Smith break; 355*c2fc9fa9SBarry Smith } 356*c2fc9fa9SBarry Smith } 357*c2fc9fa9SBarry Smith /* Update function and solution vectors */ 358*c2fc9fa9SBarry Smith vi->phinorm = gnorm; 359*c2fc9fa9SBarry Smith vi->merit = 0.5*vi->phinorm*vi->phinorm; 360*c2fc9fa9SBarry Smith ierr = VecCopy(G,vi->phi);CHKERRQ(ierr); 361*c2fc9fa9SBarry Smith ierr = VecCopy(W,X);CHKERRQ(ierr); 362*c2fc9fa9SBarry Smith /* Monitor convergence */ 363*c2fc9fa9SBarry Smith ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 364*c2fc9fa9SBarry Smith snes->iter = i+1; 365*c2fc9fa9SBarry Smith snes->norm = vi->phinorm; 366*c2fc9fa9SBarry Smith ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 367*c2fc9fa9SBarry Smith SNESLogConvHistory(snes,snes->norm,lits); 368*c2fc9fa9SBarry Smith ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 369*c2fc9fa9SBarry Smith /* Test for convergence, xnorm = || X || */ 370*c2fc9fa9SBarry Smith if (snes->ops->converged != SNESSkipConverged) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); } 371*c2fc9fa9SBarry Smith ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 372*c2fc9fa9SBarry Smith if (snes->reason) break; 373*c2fc9fa9SBarry Smith } 374*c2fc9fa9SBarry Smith if (i == maxits) { 375*c2fc9fa9SBarry Smith ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr); 376*c2fc9fa9SBarry Smith if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 377*c2fc9fa9SBarry Smith } 378*c2fc9fa9SBarry Smith snes->ops->computefunction = vi->computeuserfunction; 379*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 380*c2fc9fa9SBarry Smith } 381*c2fc9fa9SBarry Smith 382*c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */ 383*c2fc9fa9SBarry Smith /* 384*c2fc9fa9SBarry Smith SNESSetUp_VISS - Sets up the internal data structures for the later use 385*c2fc9fa9SBarry Smith of the SNES nonlinear solver. 386*c2fc9fa9SBarry Smith 387*c2fc9fa9SBarry Smith Input Parameter: 388*c2fc9fa9SBarry Smith . snes - the SNES context 389*c2fc9fa9SBarry Smith . x - the solution vector 390*c2fc9fa9SBarry Smith 391*c2fc9fa9SBarry Smith Application Interface Routine: SNESSetUp() 392*c2fc9fa9SBarry Smith 393*c2fc9fa9SBarry Smith Notes: 394*c2fc9fa9SBarry Smith For basic use of the SNES solvers, the user need not explicitly call 395*c2fc9fa9SBarry Smith SNESSetUp(), since these actions will automatically occur during 396*c2fc9fa9SBarry Smith the call to SNESSolve(). 397*c2fc9fa9SBarry Smith */ 398*c2fc9fa9SBarry Smith #undef __FUNCT__ 399*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESSetUp_VISS" 400*c2fc9fa9SBarry Smith PetscErrorCode SNESSetUp_VISS(SNES snes) 401*c2fc9fa9SBarry Smith { 402*c2fc9fa9SBarry Smith PetscErrorCode ierr; 403*c2fc9fa9SBarry Smith SNES_VISS *vi = (SNES_VISS*) snes->data; 404*c2fc9fa9SBarry Smith 405*c2fc9fa9SBarry Smith PetscFunctionBegin; 406*c2fc9fa9SBarry Smith ierr = SNESSetUp_VI(snes);CHKERRQ(ierr); 407*c2fc9fa9SBarry Smith ierr = VecDuplicate(snes->vec_sol, &vi->dpsi);CHKERRQ(ierr); 408*c2fc9fa9SBarry Smith ierr = VecDuplicate(snes->vec_sol, &vi->phi);CHKERRQ(ierr); 409*c2fc9fa9SBarry Smith ierr = VecDuplicate(snes->vec_sol, &vi->Da);CHKERRQ(ierr); 410*c2fc9fa9SBarry Smith ierr = VecDuplicate(snes->vec_sol, &vi->Db);CHKERRQ(ierr); 411*c2fc9fa9SBarry Smith ierr = VecDuplicate(snes->vec_sol, &vi->z);CHKERRQ(ierr); 412*c2fc9fa9SBarry Smith ierr = VecDuplicate(snes->vec_sol, &vi->t);CHKERRQ(ierr); 413*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 414*c2fc9fa9SBarry Smith } 415*c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */ 416*c2fc9fa9SBarry Smith #undef __FUNCT__ 417*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESReset_VISS" 418*c2fc9fa9SBarry Smith PetscErrorCode SNESReset_VISS(SNES snes) 419*c2fc9fa9SBarry Smith { 420*c2fc9fa9SBarry Smith SNES_VISS *vi = (SNES_VISS*) snes->data; 421*c2fc9fa9SBarry Smith PetscErrorCode ierr; 422*c2fc9fa9SBarry Smith 423*c2fc9fa9SBarry Smith PetscFunctionBegin; 424*c2fc9fa9SBarry Smith ierr = SNESReset_VI(snes);CHKERRQ(ierr); 425*c2fc9fa9SBarry Smith ierr = VecDestroy(&vi->dpsi);CHKERRQ(ierr); 426*c2fc9fa9SBarry Smith ierr = VecDestroy(&vi->phi);CHKERRQ(ierr); 427*c2fc9fa9SBarry Smith ierr = VecDestroy(&vi->Da);CHKERRQ(ierr); 428*c2fc9fa9SBarry Smith ierr = VecDestroy(&vi->Db);CHKERRQ(ierr); 429*c2fc9fa9SBarry Smith ierr = VecDestroy(&vi->z);CHKERRQ(ierr); 430*c2fc9fa9SBarry Smith ierr = VecDestroy(&vi->t);CHKERRQ(ierr); 431*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 432*c2fc9fa9SBarry Smith } 433*c2fc9fa9SBarry Smith 434*c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */ 435*c2fc9fa9SBarry Smith /* 436*c2fc9fa9SBarry Smith SNESSetFromOptions_VISS - Sets various parameters for the SNESVI method. 437*c2fc9fa9SBarry Smith 438*c2fc9fa9SBarry Smith Input Parameter: 439*c2fc9fa9SBarry Smith . snes - the SNES context 440*c2fc9fa9SBarry Smith 441*c2fc9fa9SBarry Smith Application Interface Routine: SNESSetFromOptions() 442*c2fc9fa9SBarry Smith */ 443*c2fc9fa9SBarry Smith #undef __FUNCT__ 444*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESSetFromOptions_VISS" 445*c2fc9fa9SBarry Smith static PetscErrorCode SNESSetFromOptions_VISS(SNES snes) 446*c2fc9fa9SBarry Smith { 447*c2fc9fa9SBarry Smith PetscErrorCode ierr; 448*c2fc9fa9SBarry Smith 449*c2fc9fa9SBarry Smith PetscFunctionBegin; 450*c2fc9fa9SBarry Smith ierr = SNESSetFromOptions_VI(snes);CHKERRQ(ierr); 451*c2fc9fa9SBarry Smith ierr = PetscOptionsHead("SNES semismooth method options");CHKERRQ(ierr); 452*c2fc9fa9SBarry Smith ierr = PetscOptionsTail();CHKERRQ(ierr); 453*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 454*c2fc9fa9SBarry Smith } 455*c2fc9fa9SBarry Smith 456*c2fc9fa9SBarry Smith 457*c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */ 458*c2fc9fa9SBarry Smith /*MC 459*c2fc9fa9SBarry Smith SNESVISS - Semi-smooth solver for variational inequalities based on Newton's method 460*c2fc9fa9SBarry Smith 461*c2fc9fa9SBarry Smith Level: beginner 462*c2fc9fa9SBarry Smith 463*c2fc9fa9SBarry Smith .seealso: SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(), 464*c2fc9fa9SBarry Smith SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(), 465*c2fc9fa9SBarry Smith SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams() 466*c2fc9fa9SBarry Smith 467*c2fc9fa9SBarry Smith M*/ 468*c2fc9fa9SBarry Smith EXTERN_C_BEGIN 469*c2fc9fa9SBarry Smith #undef __FUNCT__ 470*c2fc9fa9SBarry Smith #define __FUNCT__ "SNESCreate_VISS" 471*c2fc9fa9SBarry Smith PetscErrorCode SNESCreate_VISS(SNES snes) 472*c2fc9fa9SBarry Smith { 473*c2fc9fa9SBarry Smith PetscErrorCode ierr; 474*c2fc9fa9SBarry Smith SNES_VISS *vi; 475*c2fc9fa9SBarry Smith 476*c2fc9fa9SBarry Smith PetscFunctionBegin; 477*c2fc9fa9SBarry Smith snes->ops->reset = SNESReset_VISS; 478*c2fc9fa9SBarry Smith snes->ops->setup = SNESSetUp_VISS; 479*c2fc9fa9SBarry Smith snes->ops->solve = SNESSolve_VISS; 480*c2fc9fa9SBarry Smith snes->ops->destroy = SNESDestroy_VI; 481*c2fc9fa9SBarry Smith snes->ops->setfromoptions = SNESSetFromOptions_VISS; 482*c2fc9fa9SBarry Smith snes->ops->view = PETSC_NULL; 483*c2fc9fa9SBarry Smith 484*c2fc9fa9SBarry Smith snes->usesksp = PETSC_TRUE; 485*c2fc9fa9SBarry Smith snes->usespc = PETSC_FALSE; 486*c2fc9fa9SBarry Smith 487*c2fc9fa9SBarry Smith ierr = PetscNewLog(snes,SNES_VISS,&vi);CHKERRQ(ierr); 488*c2fc9fa9SBarry Smith snes->data = (void*)vi; 489*c2fc9fa9SBarry Smith snes->ls_alpha = 1.e-4; 490*c2fc9fa9SBarry Smith snes->maxstep = 1.e8; 491*c2fc9fa9SBarry Smith snes->steptol = 1.e-12; 492*c2fc9fa9SBarry Smith 493*c2fc9fa9SBarry Smith ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetType_C","SNESLineSearchSetType_VI",SNESLineSearchSetType_VI);CHKERRQ(ierr); 494*c2fc9fa9SBarry Smith ierr = SNESLineSearchSetType(snes, SNES_LS_CUBIC);CHKERRQ(ierr); 495*c2fc9fa9SBarry Smith 496*c2fc9fa9SBarry Smith PetscFunctionReturn(0); 497*c2fc9fa9SBarry Smith } 498*c2fc9fa9SBarry Smith EXTERN_C_END 499*c2fc9fa9SBarry Smith 500