1c2fc9fa9SBarry Smith 2c2fc9fa9SBarry Smith #include <../src/snes/impls/vi/ss/vissimpl.h> /*I "petscsnes.h" I*/ 3c2fc9fa9SBarry Smith 4c2fc9fa9SBarry Smith /* 5c2fc9fa9SBarry Smith SNESVIComputeMeritFunction - Evaluates the merit function for the mixed complementarity problem. 6c2fc9fa9SBarry Smith 7c2fc9fa9SBarry Smith Input Parameter: 8c2fc9fa9SBarry Smith . phi - the semismooth function 9c2fc9fa9SBarry Smith 10c2fc9fa9SBarry Smith Output Parameter: 11c2fc9fa9SBarry Smith . merit - the merit function 12c2fc9fa9SBarry Smith . phinorm - ||phi|| 13c2fc9fa9SBarry Smith 14c2fc9fa9SBarry Smith Notes: 15c2fc9fa9SBarry Smith The merit function for the mixed complementarity problem is defined as 16c2fc9fa9SBarry Smith merit = 0.5*phi^T*phi 17c2fc9fa9SBarry Smith */ 18c2fc9fa9SBarry Smith static PetscErrorCode SNESVIComputeMeritFunction(Vec phi, PetscReal *merit,PetscReal *phinorm) 19c2fc9fa9SBarry Smith { 20c2fc9fa9SBarry Smith PetscFunctionBegin; 219566063dSJacob Faibussowitsch PetscCall(VecNormBegin(phi,NORM_2,phinorm)); 229566063dSJacob Faibussowitsch PetscCall(VecNormEnd(phi,NORM_2,phinorm)); 23c2fc9fa9SBarry Smith 24c2fc9fa9SBarry Smith *merit = 0.5*(*phinorm)*(*phinorm); 25c2fc9fa9SBarry Smith PetscFunctionReturn(0); 26c2fc9fa9SBarry Smith } 27c2fc9fa9SBarry Smith 289fbee547SJacob Faibussowitsch static inline PetscScalar Phi(PetscScalar a,PetscScalar b) 29c2fc9fa9SBarry Smith { 30c2fc9fa9SBarry Smith return a + b - PetscSqrtScalar(a*a + b*b); 31c2fc9fa9SBarry Smith } 32c2fc9fa9SBarry Smith 339fbee547SJacob Faibussowitsch static inline PetscScalar DPhi(PetscScalar a,PetscScalar b) 34c2fc9fa9SBarry Smith { 35c2fc9fa9SBarry Smith if ((PetscAbsScalar(a) >= 1.e-6) || (PetscAbsScalar(b) >= 1.e-6)) return 1.0 - a/ PetscSqrtScalar(a*a + b*b); 36c2fc9fa9SBarry Smith else return .5; 37c2fc9fa9SBarry Smith } 38c2fc9fa9SBarry Smith 39c2fc9fa9SBarry Smith /* 40c2fc9fa9SBarry Smith SNESVIComputeFunction - Reformulates a system of nonlinear equations in mixed complementarity form to a system of nonlinear equations in semismooth form. 41c2fc9fa9SBarry Smith 42c2fc9fa9SBarry Smith Input Parameters: 43c2fc9fa9SBarry Smith . snes - the SNES context 44d5f1b7e6SEd Bueler . X - current iterate 45c2fc9fa9SBarry Smith . functx - user defined function context 46c2fc9fa9SBarry Smith 47c2fc9fa9SBarry Smith Output Parameters: 48c2fc9fa9SBarry Smith . phi - Semismooth function 49c2fc9fa9SBarry Smith 50c2fc9fa9SBarry Smith */ 51c2fc9fa9SBarry Smith static PetscErrorCode SNESVIComputeFunction(SNES snes,Vec X,Vec phi,void *functx) 52c2fc9fa9SBarry Smith { 53f450aa47SBarry Smith SNES_VINEWTONSSLS *vi = (SNES_VINEWTONSSLS*)snes->data; 54c2fc9fa9SBarry Smith Vec Xl = snes->xl,Xu = snes->xu,F = snes->vec_func; 555edff71fSBarry Smith PetscScalar *phi_arr,*f_arr,*l,*u; 565edff71fSBarry Smith const PetscScalar *x_arr; 57c2fc9fa9SBarry Smith PetscInt i,nlocal; 58c2fc9fa9SBarry Smith 59c2fc9fa9SBarry Smith PetscFunctionBegin; 609566063dSJacob Faibussowitsch PetscCall((*vi->computeuserfunction)(snes,X,F,functx)); 619566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X,&nlocal)); 629566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(X,&x_arr)); 639566063dSJacob Faibussowitsch PetscCall(VecGetArray(F,&f_arr)); 649566063dSJacob Faibussowitsch PetscCall(VecGetArray(Xl,&l)); 659566063dSJacob Faibussowitsch PetscCall(VecGetArray(Xu,&u)); 669566063dSJacob Faibussowitsch PetscCall(VecGetArray(phi,&phi_arr)); 67c2fc9fa9SBarry Smith 68c2fc9fa9SBarry Smith for (i=0; i < nlocal; i++) { 69e270355aSBarry Smith if ((PetscRealPart(l[i]) <= PETSC_NINFINITY) && (PetscRealPart(u[i]) >= PETSC_INFINITY)) { /* no constraints on variable */ 70c2fc9fa9SBarry Smith phi_arr[i] = f_arr[i]; 71e270355aSBarry Smith } else if (PetscRealPart(l[i]) <= PETSC_NINFINITY) { /* upper bound on variable only */ 72c2fc9fa9SBarry Smith phi_arr[i] = -Phi(u[i] - x_arr[i],-f_arr[i]); 73e270355aSBarry Smith } else if (PetscRealPart(u[i]) >= PETSC_INFINITY) { /* lower bound on variable only */ 74c2fc9fa9SBarry Smith phi_arr[i] = Phi(x_arr[i] - l[i],f_arr[i]); 75c2fc9fa9SBarry Smith } else if (l[i] == u[i]) { 76c2fc9fa9SBarry Smith phi_arr[i] = l[i] - x_arr[i]; 77c2fc9fa9SBarry Smith } else { /* both bounds on variable */ 78c2fc9fa9SBarry Smith phi_arr[i] = Phi(x_arr[i] - l[i],-Phi(u[i] - x_arr[i],-f_arr[i])); 79c2fc9fa9SBarry Smith } 80c2fc9fa9SBarry Smith } 81c2fc9fa9SBarry Smith 829566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(X,&x_arr)); 839566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F,&f_arr)); 849566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Xl,&l)); 859566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Xu,&u)); 869566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(phi,&phi_arr)); 87c2fc9fa9SBarry Smith PetscFunctionReturn(0); 88c2fc9fa9SBarry Smith } 89c2fc9fa9SBarry Smith 90c2fc9fa9SBarry Smith /* 91c2fc9fa9SBarry Smith SNESVIComputeBsubdifferentialVectors - Computes the diagonal shift (Da) and row scaling (Db) vectors needed for the 92c2fc9fa9SBarry Smith the semismooth jacobian. 93c2fc9fa9SBarry Smith */ 94c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeBsubdifferentialVectors(SNES snes,Vec X,Vec F,Mat jac,Vec Da,Vec Db) 95c2fc9fa9SBarry Smith { 96c2fc9fa9SBarry Smith PetscScalar *l,*u,*x,*f,*da,*db,da1,da2,db1,db2; 97c2fc9fa9SBarry Smith PetscInt i,nlocal; 98c2fc9fa9SBarry Smith 99c2fc9fa9SBarry Smith PetscFunctionBegin; 1009566063dSJacob Faibussowitsch PetscCall(VecGetArray(X,&x)); 1019566063dSJacob Faibussowitsch PetscCall(VecGetArray(F,&f)); 1029566063dSJacob Faibussowitsch PetscCall(VecGetArray(snes->xl,&l)); 1039566063dSJacob Faibussowitsch PetscCall(VecGetArray(snes->xu,&u)); 1049566063dSJacob Faibussowitsch PetscCall(VecGetArray(Da,&da)); 1059566063dSJacob Faibussowitsch PetscCall(VecGetArray(Db,&db)); 1069566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X,&nlocal)); 107c2fc9fa9SBarry Smith 108c2fc9fa9SBarry Smith for (i=0; i< nlocal; i++) { 109e270355aSBarry Smith if ((PetscRealPart(l[i]) <= PETSC_NINFINITY) && (PetscRealPart(u[i]) >= PETSC_INFINITY)) { /* no constraints on variable */ 110c2fc9fa9SBarry Smith da[i] = 0; 111c2fc9fa9SBarry Smith db[i] = 1; 112e270355aSBarry Smith } else if (PetscRealPart(l[i]) <= PETSC_NINFINITY) { /* upper bound on variable only */ 113c2fc9fa9SBarry Smith da[i] = DPhi(u[i] - x[i], -f[i]); 114c2fc9fa9SBarry Smith db[i] = DPhi(-f[i],u[i] - x[i]); 115e270355aSBarry Smith } else if (PetscRealPart(u[i]) >= PETSC_INFINITY) { /* lower bound on variable only */ 116c2fc9fa9SBarry Smith da[i] = DPhi(x[i] - l[i], f[i]); 117c2fc9fa9SBarry Smith db[i] = DPhi(f[i],x[i] - l[i]); 118c2fc9fa9SBarry Smith } else if (l[i] == u[i]) { /* fixed variable */ 119c2fc9fa9SBarry Smith da[i] = 1; 120c2fc9fa9SBarry Smith db[i] = 0; 121c2fc9fa9SBarry Smith } else { /* upper and lower bounds on variable */ 122c2fc9fa9SBarry Smith da1 = DPhi(x[i] - l[i], -Phi(u[i] - x[i], -f[i])); 123c2fc9fa9SBarry Smith db1 = DPhi(-Phi(u[i] - x[i], -f[i]),x[i] - l[i]); 124c2fc9fa9SBarry Smith da2 = DPhi(u[i] - x[i], -f[i]); 125c2fc9fa9SBarry Smith db2 = DPhi(-f[i],u[i] - x[i]); 126c2fc9fa9SBarry Smith da[i] = da1 + db1*da2; 127c2fc9fa9SBarry Smith db[i] = db1*db2; 128c2fc9fa9SBarry Smith } 129c2fc9fa9SBarry Smith } 130c2fc9fa9SBarry Smith 1319566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(X,&x)); 1329566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F,&f)); 1339566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(snes->xl,&l)); 1349566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(snes->xu,&u)); 1359566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Da,&da)); 1369566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Db,&db)); 137c2fc9fa9SBarry Smith PetscFunctionReturn(0); 138c2fc9fa9SBarry Smith } 139c2fc9fa9SBarry Smith 140c2fc9fa9SBarry Smith /* 141c2fc9fa9SBarry 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. 142c2fc9fa9SBarry Smith 143c2fc9fa9SBarry Smith Input Parameters: 144c2fc9fa9SBarry Smith . Da - Diagonal shift vector for the semismooth jacobian. 145c2fc9fa9SBarry Smith . Db - Row scaling vector for the semismooth jacobian. 146c2fc9fa9SBarry Smith 147c2fc9fa9SBarry Smith Output Parameters: 148c2fc9fa9SBarry Smith . jac - semismooth jacobian 149c2fc9fa9SBarry Smith . jac_pre - optional preconditioning matrix 150c2fc9fa9SBarry Smith 151c2fc9fa9SBarry Smith Notes: 152c2fc9fa9SBarry Smith The semismooth jacobian matrix is given by 153c2fc9fa9SBarry Smith jac = Da + Db*jacfun 154c2fc9fa9SBarry Smith where Db is the row scaling matrix stored as a vector, 155c2fc9fa9SBarry Smith Da is the diagonal perturbation matrix stored as a vector 156c2fc9fa9SBarry Smith and jacfun is the jacobian of the original nonlinear function. 157c2fc9fa9SBarry Smith */ 158c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeJacobian(Mat jac, Mat jac_pre,Vec Da, Vec Db) 159c2fc9fa9SBarry Smith { 160c2fc9fa9SBarry Smith 161c2fc9fa9SBarry Smith /* Do row scaling and add diagonal perturbation */ 162362febeeSStefano Zampini PetscFunctionBegin; 1639566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(jac,Db,NULL)); 1649566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet(jac,Da,ADD_VALUES)); 165c2fc9fa9SBarry Smith if (jac != jac_pre) { /* If jac and jac_pre are different */ 1669566063dSJacob Faibussowitsch PetscCall(MatDiagonalScale(jac_pre,Db,NULL)); 1679566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet(jac_pre,Da,ADD_VALUES)); 168c2fc9fa9SBarry Smith } 169c2fc9fa9SBarry Smith PetscFunctionReturn(0); 170c2fc9fa9SBarry Smith } 171c2fc9fa9SBarry Smith 172c2fc9fa9SBarry Smith /* 173c2fc9fa9SBarry Smith SNESVIComputeMeritFunctionGradient - Computes the gradient of the merit function psi. 174c2fc9fa9SBarry Smith 175c2fc9fa9SBarry Smith Input Parameters: 176c2fc9fa9SBarry Smith phi - semismooth function. 177c2fc9fa9SBarry Smith H - semismooth jacobian 178c2fc9fa9SBarry Smith 179c2fc9fa9SBarry Smith Output Parameters: 180c2fc9fa9SBarry Smith dpsi - merit function gradient 181c2fc9fa9SBarry Smith 182c2fc9fa9SBarry Smith Notes: 183c2fc9fa9SBarry Smith The merit function gradient is computed as follows 184c2fc9fa9SBarry Smith dpsi = H^T*phi 185c2fc9fa9SBarry Smith */ 186c2fc9fa9SBarry Smith PetscErrorCode SNESVIComputeMeritFunctionGradient(Mat H, Vec phi, Vec dpsi) 187c2fc9fa9SBarry Smith { 188c2fc9fa9SBarry Smith PetscFunctionBegin; 1899566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(H,phi,dpsi)); 190c2fc9fa9SBarry Smith PetscFunctionReturn(0); 191c2fc9fa9SBarry Smith } 192c2fc9fa9SBarry Smith 193c2fc9fa9SBarry Smith /* 194f450aa47SBarry Smith SNESSolve_VINEWTONSSLS - Solves the complementarity problem with a semismooth Newton 195c2fc9fa9SBarry Smith method using a line search. 196c2fc9fa9SBarry Smith 197c2fc9fa9SBarry Smith Input Parameters: 198c2fc9fa9SBarry Smith . snes - the SNES context 199c2fc9fa9SBarry Smith 200c2fc9fa9SBarry Smith Application Interface Routine: SNESSolve() 201c2fc9fa9SBarry Smith 202c2fc9fa9SBarry Smith Notes: 203c2fc9fa9SBarry Smith This implements essentially a semismooth Newton method with a 204d5f1b7e6SEd Bueler line search. The default line search does not do any line search 205d5f1b7e6SEd Bueler but rather takes a full Newton step. 206016d19f9SBarry Smith 20704d7464bSBarry Smith Developer Note: the code in this file should be slightly modified so that this routine need not exist and the SNESSolve_NEWTONLS() routine is called directly with the appropriate wrapped function and Jacobian evaluations 208016d19f9SBarry Smith 209c2fc9fa9SBarry Smith */ 210f450aa47SBarry Smith PetscErrorCode SNESSolve_VINEWTONSSLS(SNES snes) 211c2fc9fa9SBarry Smith { 212f450aa47SBarry Smith SNES_VINEWTONSSLS *vi = (SNES_VINEWTONSSLS*)snes->data; 213c2fc9fa9SBarry Smith PetscInt maxits,i,lits; 214422a814eSBarry Smith SNESLineSearchReason lssucceed; 215c2fc9fa9SBarry Smith PetscReal gnorm,xnorm=0,ynorm; 2169bd66eb0SPeter Brune Vec Y,X,F; 217c2fc9fa9SBarry Smith KSPConvergedReason kspreason; 2186cab3a1bSJed Brown DM dm; 219942e3340SBarry Smith DMSNES sdm; 220c2fc9fa9SBarry Smith 221c2fc9fa9SBarry Smith PetscFunctionBegin; 2229566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes,&dm)); 2239566063dSJacob Faibussowitsch PetscCall(DMGetDMSNES(dm,&sdm)); 2241aa26658SKarl Rupp 22522c6f798SBarry Smith vi->computeuserfunction = sdm->ops->computefunction; 22622c6f798SBarry Smith sdm->ops->computefunction = SNESVIComputeFunction; 227c2fc9fa9SBarry Smith 228c2fc9fa9SBarry Smith snes->numFailures = 0; 229c2fc9fa9SBarry Smith snes->numLinearSolveFailures = 0; 230c2fc9fa9SBarry Smith snes->reason = SNES_CONVERGED_ITERATING; 231c2fc9fa9SBarry Smith 232c2fc9fa9SBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 233c2fc9fa9SBarry Smith X = snes->vec_sol; /* solution vector */ 234c2fc9fa9SBarry Smith F = snes->vec_func; /* residual vector */ 235c2fc9fa9SBarry Smith Y = snes->work[0]; /* work vectors */ 236c2fc9fa9SBarry Smith 2379566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 238c2fc9fa9SBarry Smith snes->iter = 0; 239c2fc9fa9SBarry Smith snes->norm = 0.0; 2409566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 241c2fc9fa9SBarry Smith 2429566063dSJacob Faibussowitsch PetscCall(SNESVIProjectOntoBounds(snes,X)); 2439566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes,X,vi->phi)); 244c2fc9fa9SBarry Smith if (snes->domainerror) { 245c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 24622c6f798SBarry Smith sdm->ops->computefunction = vi->computeuserfunction; 247c2fc9fa9SBarry Smith PetscFunctionReturn(0); 248c2fc9fa9SBarry Smith } 249c2fc9fa9SBarry Smith /* Compute Merit function */ 2509566063dSJacob Faibussowitsch PetscCall(SNESVIComputeMeritFunction(vi->phi,&vi->merit,&vi->phinorm)); 251c2fc9fa9SBarry Smith 2529566063dSJacob Faibussowitsch PetscCall(VecNormBegin(X,NORM_2,&xnorm)); /* xnorm <- ||x|| */ 2539566063dSJacob Faibussowitsch PetscCall(VecNormEnd(X,NORM_2,&xnorm)); 254422a814eSBarry Smith SNESCheckFunctionNorm(snes,vi->merit); 255c2fc9fa9SBarry Smith 2569566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 257c2fc9fa9SBarry Smith snes->norm = vi->phinorm; 2589566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 2599566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes,vi->phinorm,0)); 2609566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes,0,vi->phinorm)); 261c2fc9fa9SBarry Smith 262c2fc9fa9SBarry Smith /* test convergence */ 263*dbbe0bcdSBarry Smith PetscUseTypeMethod(snes,converged ,0,0.0,0.0,vi->phinorm,&snes->reason,snes->cnvP); 264c2fc9fa9SBarry Smith if (snes->reason) { 26522c6f798SBarry Smith sdm->ops->computefunction = vi->computeuserfunction; 266c2fc9fa9SBarry Smith PetscFunctionReturn(0); 267c2fc9fa9SBarry Smith } 268c2fc9fa9SBarry Smith 269c2fc9fa9SBarry Smith for (i=0; i<maxits; i++) { 270c2fc9fa9SBarry Smith 271c2fc9fa9SBarry Smith /* Call general purpose update function */ 272*dbbe0bcdSBarry Smith PetscTryTypeMethod(snes,update, snes->iter); 273c2fc9fa9SBarry Smith 274c2fc9fa9SBarry Smith /* Solve J Y = Phi, where J is the semismooth jacobian */ 275b9600128SPeter Brune 276b9600128SPeter Brune /* Get the jacobian -- note that the function must be the original function for snes_fd and snes_fd_color to work for this*/ 27722c6f798SBarry Smith sdm->ops->computefunction = vi->computeuserfunction; 2789566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre)); 27907b62357SFande Kong SNESCheckJacobianDomainerror(snes); 28022c6f798SBarry Smith sdm->ops->computefunction = SNESVIComputeFunction; 281b9600128SPeter Brune 282c2fc9fa9SBarry Smith /* Get the diagonal shift and row scaling vectors */ 2839566063dSJacob Faibussowitsch PetscCall(SNESVIComputeBsubdifferentialVectors(snes,X,F,snes->jacobian,vi->Da,vi->Db)); 284c2fc9fa9SBarry Smith /* Compute the semismooth jacobian */ 2859566063dSJacob Faibussowitsch PetscCall(SNESVIComputeJacobian(snes->jacobian,snes->jacobian_pre,vi->Da,vi->Db)); 286c2fc9fa9SBarry Smith /* Compute the merit function gradient */ 2879566063dSJacob Faibussowitsch PetscCall(SNESVIComputeMeritFunctionGradient(snes->jacobian,vi->phi,vi->dpsi)); 2889566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre)); 2899566063dSJacob Faibussowitsch PetscCall(KSPSolve(snes->ksp,vi->phi,Y)); 2909566063dSJacob Faibussowitsch PetscCall(KSPGetConvergedReason(snes->ksp,&kspreason)); 291c2fc9fa9SBarry Smith 292c2fc9fa9SBarry Smith if (kspreason < 0) { 293c2fc9fa9SBarry Smith if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 29463a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(snes,"iter=%" PetscInt_FMT ", number linear solve failures %" PetscInt_FMT " greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures)); 295c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 296c2fc9fa9SBarry Smith break; 297c2fc9fa9SBarry Smith } 298c2fc9fa9SBarry Smith } 2999566063dSJacob Faibussowitsch PetscCall(KSPGetIterationNumber(snes->ksp,&lits)); 300c2fc9fa9SBarry Smith snes->linear_its += lits; 30163a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(snes,"iter=%" PetscInt_FMT ", linear solve iterations=%" PetscInt_FMT "\n",snes->iter,lits)); 302c2fc9fa9SBarry Smith /* 3036b2b7091SBarry Smith if (snes->ops->precheck) { 304c2fc9fa9SBarry Smith PetscBool changed_y = PETSC_FALSE; 305*dbbe0bcdSBarry Smith PetscUseTypeMethod(snes,precheck ,X,Y,snes->precheck,&changed_y); 306c2fc9fa9SBarry Smith } 307c2fc9fa9SBarry Smith 3081baa6e33SBarry Smith if (PetscLogPrintInfo) PetscCall(SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W)); 309c2fc9fa9SBarry Smith */ 310c2fc9fa9SBarry Smith /* Compute a (scaled) negative update in the line search routine: 311c2fc9fa9SBarry Smith Y <- X - lambda*Y 312c2fc9fa9SBarry Smith and evaluate G = function(Y) (depends on the line search). 313c2fc9fa9SBarry Smith */ 3149566063dSJacob Faibussowitsch PetscCall(VecCopy(Y,snes->vec_sol_update)); 315c2fc9fa9SBarry Smith ynorm = 1; gnorm = vi->phinorm; 3169566063dSJacob Faibussowitsch PetscCall(SNESLineSearchApply(snes->linesearch, X, vi->phi, &gnorm, Y)); 3179566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed)); 3189566063dSJacob Faibussowitsch PetscCall(SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm)); 3199566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)vi->phinorm,(double)gnorm,(double)ynorm,(int)lssucceed)); 320c2fc9fa9SBarry Smith if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 321c2fc9fa9SBarry Smith if (snes->domainerror) { 322c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 32322c6f798SBarry Smith sdm->ops->computefunction = vi->computeuserfunction; 324c2fc9fa9SBarry Smith PetscFunctionReturn(0); 325c2fc9fa9SBarry Smith } 326422a814eSBarry Smith if (lssucceed) { 327c2fc9fa9SBarry Smith if (++snes->numFailures >= snes->maxFailures) { 328c2fc9fa9SBarry Smith PetscBool ismin; 329c2fc9fa9SBarry Smith snes->reason = SNES_DIVERGED_LINE_SEARCH; 3309566063dSJacob Faibussowitsch PetscCall(SNESVICheckLocalMin_Private(snes,snes->jacobian,vi->phi,X,gnorm,&ismin)); 331c2fc9fa9SBarry Smith if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 332c2fc9fa9SBarry Smith break; 333c2fc9fa9SBarry Smith } 334c2fc9fa9SBarry Smith } 335c2fc9fa9SBarry Smith /* Update function and solution vectors */ 336c2fc9fa9SBarry Smith vi->phinorm = gnorm; 337c2fc9fa9SBarry Smith vi->merit = 0.5*vi->phinorm*vi->phinorm; 338c2fc9fa9SBarry Smith /* Monitor convergence */ 3399566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes)); 340c2fc9fa9SBarry Smith snes->iter = i+1; 341c2fc9fa9SBarry Smith snes->norm = vi->phinorm; 342c1e67a49SFande Kong snes->xnorm = xnorm; 343c1e67a49SFande Kong snes->ynorm = ynorm; 3449566063dSJacob Faibussowitsch PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes)); 3459566063dSJacob Faibussowitsch PetscCall(SNESLogConvergenceHistory(snes,snes->norm,lits)); 3469566063dSJacob Faibussowitsch PetscCall(SNESMonitor(snes,snes->iter,snes->norm)); 347c2fc9fa9SBarry Smith /* Test for convergence, xnorm = || X || */ 3489566063dSJacob Faibussowitsch if (snes->ops->converged != SNESConvergedSkip) PetscCall(VecNorm(X,NORM_2,&xnorm)); 349*dbbe0bcdSBarry Smith PetscUseTypeMethod(snes,converged ,snes->iter,xnorm,ynorm,vi->phinorm,&snes->reason,snes->cnvP); 350c2fc9fa9SBarry Smith if (snes->reason) break; 351c2fc9fa9SBarry Smith } 352c2fc9fa9SBarry Smith if (i == maxits) { 35363a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(snes,"Maximum number of iterations has been reached: %" PetscInt_FMT "\n",maxits)); 354c2fc9fa9SBarry Smith if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 355c2fc9fa9SBarry Smith } 35622c6f798SBarry Smith sdm->ops->computefunction = vi->computeuserfunction; 357c2fc9fa9SBarry Smith PetscFunctionReturn(0); 358c2fc9fa9SBarry Smith } 359c2fc9fa9SBarry Smith 360c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */ 361c2fc9fa9SBarry Smith /* 362f450aa47SBarry Smith SNESSetUp_VINEWTONSSLS - Sets up the internal data structures for the later use 363c2fc9fa9SBarry Smith of the SNES nonlinear solver. 364c2fc9fa9SBarry Smith 365c2fc9fa9SBarry Smith Input Parameter: 366c2fc9fa9SBarry Smith . snes - the SNES context 367c2fc9fa9SBarry Smith 368c2fc9fa9SBarry Smith Application Interface Routine: SNESSetUp() 369c2fc9fa9SBarry Smith 370c2fc9fa9SBarry Smith Notes: 371c2fc9fa9SBarry Smith For basic use of the SNES solvers, the user need not explicitly call 372c2fc9fa9SBarry Smith SNESSetUp(), since these actions will automatically occur during 373c2fc9fa9SBarry Smith the call to SNESSolve(). 374c2fc9fa9SBarry Smith */ 375f450aa47SBarry Smith PetscErrorCode SNESSetUp_VINEWTONSSLS(SNES snes) 376c2fc9fa9SBarry Smith { 377f450aa47SBarry Smith SNES_VINEWTONSSLS *vi = (SNES_VINEWTONSSLS*) snes->data; 378c2fc9fa9SBarry Smith 379c2fc9fa9SBarry Smith PetscFunctionBegin; 3809566063dSJacob Faibussowitsch PetscCall(SNESSetUp_VI(snes)); 3819566063dSJacob Faibussowitsch PetscCall(VecDuplicate(snes->vec_sol, &vi->dpsi)); 3829566063dSJacob Faibussowitsch PetscCall(VecDuplicate(snes->vec_sol, &vi->phi)); 3839566063dSJacob Faibussowitsch PetscCall(VecDuplicate(snes->vec_sol, &vi->Da)); 3849566063dSJacob Faibussowitsch PetscCall(VecDuplicate(snes->vec_sol, &vi->Db)); 3859566063dSJacob Faibussowitsch PetscCall(VecDuplicate(snes->vec_sol, &vi->z)); 3869566063dSJacob Faibussowitsch PetscCall(VecDuplicate(snes->vec_sol, &vi->t)); 387c2fc9fa9SBarry Smith PetscFunctionReturn(0); 388c2fc9fa9SBarry Smith } 389c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */ 390f450aa47SBarry Smith PetscErrorCode SNESReset_VINEWTONSSLS(SNES snes) 391c2fc9fa9SBarry Smith { 392f450aa47SBarry Smith SNES_VINEWTONSSLS *vi = (SNES_VINEWTONSSLS*) snes->data; 393c2fc9fa9SBarry Smith 394c2fc9fa9SBarry Smith PetscFunctionBegin; 3959566063dSJacob Faibussowitsch PetscCall(SNESReset_VI(snes)); 3969566063dSJacob Faibussowitsch PetscCall(VecDestroy(&vi->dpsi)); 3979566063dSJacob Faibussowitsch PetscCall(VecDestroy(&vi->phi)); 3989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&vi->Da)); 3999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&vi->Db)); 4009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&vi->z)); 4019566063dSJacob Faibussowitsch PetscCall(VecDestroy(&vi->t)); 402c2fc9fa9SBarry Smith PetscFunctionReturn(0); 403c2fc9fa9SBarry Smith } 404c2fc9fa9SBarry Smith 405c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */ 406c2fc9fa9SBarry Smith /* 407f450aa47SBarry Smith SNESSetFromOptions_VINEWTONSSLS - Sets various parameters for the SNESVI method. 408c2fc9fa9SBarry Smith 409c2fc9fa9SBarry Smith Input Parameter: 410c2fc9fa9SBarry Smith . snes - the SNES context 411c2fc9fa9SBarry Smith 412c2fc9fa9SBarry Smith Application Interface Routine: SNESSetFromOptions() 413c2fc9fa9SBarry Smith */ 414*dbbe0bcdSBarry Smith static PetscErrorCode SNESSetFromOptions_VINEWTONSSLS(SNES snes,PetscOptionItems *PetscOptionsObject) 415c2fc9fa9SBarry Smith { 416c2fc9fa9SBarry Smith PetscFunctionBegin; 417*dbbe0bcdSBarry Smith PetscCall(SNESSetFromOptions_VI(snes,PetscOptionsObject)); 418d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject,"SNES semismooth method options"); 419d0609cedSBarry Smith PetscOptionsHeadEnd(); 420c2fc9fa9SBarry Smith PetscFunctionReturn(0); 421c2fc9fa9SBarry Smith } 422c2fc9fa9SBarry Smith 423c2fc9fa9SBarry Smith /* -------------------------------------------------------------------------- */ 424c2fc9fa9SBarry Smith /*MC 425f450aa47SBarry Smith SNESVINEWTONSSLS - Semi-smooth solver for variational inequalities based on Newton's method 426c2fc9fa9SBarry Smith 42761589011SJed Brown Options Database: 428d5f1b7e6SEd Bueler + -snes_type <vinewtonssls,vinewtonrsls> a semi-smooth solver, a reduced space active set method 42961589011SJed Brown - -snes_vi_monitor - prints the number of active constraints at each iteration. 43061589011SJed Brown 431c2fc9fa9SBarry Smith Level: beginner 432c2fc9fa9SBarry Smith 433b80f3ac1SShri Abhyankar References: 434606c0280SSatish Balay + * - T. S. Munson, F. Facchinei, M. C. Ferris, A. Fischer, and C. Kanzow. The semismooth 435b80f3ac1SShri Abhyankar algorithm for large scale complementarity problems. INFORMS Journal on Computing, 13 (2001). 436606c0280SSatish Balay - * - T. S. Munson, and S. Benson. Flexible Complementarity Solvers for Large Scale 437d5f1b7e6SEd Bueler Applications, Optimization Methods and Software, 21 (2006). 438b80f3ac1SShri Abhyankar 439c2e3fba1SPatrick Sanan .seealso: `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESVINEWTONRSLS`, `SNESNEWTONTR`, `SNESLineSearchSetType()`, `SNESLineSearchSetPostCheck()`, `SNESLineSearchSetPreCheck()` 440c2fc9fa9SBarry Smith 441c2fc9fa9SBarry Smith M*/ 4428cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONSSLS(SNES snes) 443c2fc9fa9SBarry Smith { 444f450aa47SBarry Smith SNES_VINEWTONSSLS *vi; 445d8d34be6SBarry Smith SNESLineSearch linesearch; 446c2fc9fa9SBarry Smith 447c2fc9fa9SBarry Smith PetscFunctionBegin; 448f450aa47SBarry Smith snes->ops->reset = SNESReset_VINEWTONSSLS; 449f450aa47SBarry Smith snes->ops->setup = SNESSetUp_VINEWTONSSLS; 450f450aa47SBarry Smith snes->ops->solve = SNESSolve_VINEWTONSSLS; 451c2fc9fa9SBarry Smith snes->ops->destroy = SNESDestroy_VI; 452f450aa47SBarry Smith snes->ops->setfromoptions = SNESSetFromOptions_VINEWTONSSLS; 4530298fd71SBarry Smith snes->ops->view = NULL; 454c2fc9fa9SBarry Smith 455c2fc9fa9SBarry Smith snes->usesksp = PETSC_TRUE; 456efd4aadfSBarry Smith snes->usesnpc = PETSC_FALSE; 457c2fc9fa9SBarry Smith 4589566063dSJacob Faibussowitsch PetscCall(SNESGetLineSearch(snes, &linesearch)); 459ec786807SJed Brown if (!((PetscObject)linesearch)->type_name) { 4609566063dSJacob Faibussowitsch PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBT)); 4619566063dSJacob Faibussowitsch PetscCall(SNESLineSearchBTSetAlpha(linesearch, 0.0)); 462ec786807SJed Brown } 463d8d34be6SBarry Smith 4644fc747eaSLawrence Mitchell snes->alwayscomputesfinalresidual = PETSC_FALSE; 4654fc747eaSLawrence Mitchell 4669566063dSJacob Faibussowitsch PetscCall(PetscNewLog(snes,&vi)); 467c2fc9fa9SBarry Smith snes->data = (void*)vi; 468c2fc9fa9SBarry Smith 4699566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESVISetVariableBounds_C",SNESVISetVariableBounds_VI)); 4709566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)snes,"SNESVISetComputeVariableBounds_C",SNESVISetComputeVariableBounds_VI)); 471c2fc9fa9SBarry Smith PetscFunctionReturn(0); 472c2fc9fa9SBarry Smith } 473