1 2 #include <../src/snes/impls/vi/rs/virsimpl.h> /*I "petscsnes.h" I*/ 3 #include <petsc/private/kspimpl.h> 4 #include <petsc/private/matimpl.h> 5 #include <petsc/private/dmimpl.h> 6 #include <petsc/private/vecimpl.h> 7 8 #undef __FUNCT__ 9 #define __FUNCT__ "SNESVIGetInactiveSet" 10 /* 11 SNESVIGetInactiveSet - Gets the global indices for the inactive set variables (these correspond to the degrees of freedom the linear 12 system is solved on) 13 14 Input parameter 15 . snes - the SNES context 16 17 Output parameter 18 . inact - inactive set index set 19 20 */ 21 PetscErrorCode SNESVIGetInactiveSet(SNES snes,IS *inact) 22 { 23 SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data; 24 25 PetscFunctionBegin; 26 *inact = vi->IS_inact; 27 PetscFunctionReturn(0); 28 } 29 30 /* 31 Provides a wrapper to a DM to allow it to be used to generated the interpolation/restriction from the DM for the smaller matrices and vectors 32 defined by the reduced space method. 33 34 Simple calls the regular DM interpolation and restricts it to operation on the variables not associated with active constraints. 35 36 <*/ 37 typedef struct { 38 PetscInt n; /* size of vectors in the reduced DM space */ 39 IS inactive; 40 41 PetscErrorCode (*createinterpolation)(DM,DM,Mat*,Vec*); /* DM's original routines */ 42 PetscErrorCode (*coarsen)(DM, MPI_Comm, DM*); 43 PetscErrorCode (*createglobalvector)(DM,Vec*); 44 45 DM dm; /* when destroying this object we need to reset the above function into the base DM */ 46 } DM_SNESVI; 47 48 #undef __FUNCT__ 49 #define __FUNCT__ "DMCreateGlobalVector_SNESVI" 50 /* 51 DMCreateGlobalVector_SNESVI - Creates global vector of the size of the reduced space 52 53 */ 54 PetscErrorCode DMCreateGlobalVector_SNESVI(DM dm,Vec *vec) 55 { 56 PetscErrorCode ierr; 57 PetscContainer isnes; 58 DM_SNESVI *dmsnesvi; 59 60 PetscFunctionBegin; 61 ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject*)&isnes);CHKERRQ(ierr); 62 if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Composed SNES is missing"); 63 ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr); 64 ierr = VecCreateMPI(PetscObjectComm((PetscObject)dm),dmsnesvi->n,PETSC_DETERMINE,vec);CHKERRQ(ierr); 65 PetscFunctionReturn(0); 66 } 67 68 #undef __FUNCT__ 69 #define __FUNCT__ "DMCreateInterpolation_SNESVI" 70 /* 71 DMCreateInterpolation_SNESVI - Modifieds the interpolation obtained from the DM by removing all rows and columns associated with active constraints. 72 73 */ 74 PetscErrorCode DMCreateInterpolation_SNESVI(DM dm1,DM dm2,Mat *mat,Vec *vec) 75 { 76 PetscErrorCode ierr; 77 PetscContainer isnes; 78 DM_SNESVI *dmsnesvi1,*dmsnesvi2; 79 Mat interp; 80 81 PetscFunctionBegin; 82 ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject*)&isnes);CHKERRQ(ierr); 83 if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_PLIB,"Composed VI data structure is missing"); 84 ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr); 85 ierr = PetscObjectQuery((PetscObject)dm2,"VI",(PetscObject*)&isnes);CHKERRQ(ierr); 86 if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm2),PETSC_ERR_PLIB,"Composed VI data structure is missing"); 87 ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi2);CHKERRQ(ierr); 88 89 ierr = (*dmsnesvi1->createinterpolation)(dm1,dm2,&interp,NULL);CHKERRQ(ierr); 90 ierr = MatGetSubMatrix(interp,dmsnesvi2->inactive,dmsnesvi1->inactive,MAT_INITIAL_MATRIX,mat);CHKERRQ(ierr); 91 ierr = MatDestroy(&interp);CHKERRQ(ierr); 92 *vec = 0; 93 PetscFunctionReturn(0); 94 } 95 96 extern PetscErrorCode DMSetVI(DM,IS); 97 98 #undef __FUNCT__ 99 #define __FUNCT__ "DMCoarsen_SNESVI" 100 /* 101 DMCoarsen_SNESVI - Computes the regular coarsened DM then computes additional information about its inactive set 102 103 */ 104 PetscErrorCode DMCoarsen_SNESVI(DM dm1,MPI_Comm comm,DM *dm2) 105 { 106 PetscErrorCode ierr; 107 PetscContainer isnes; 108 DM_SNESVI *dmsnesvi1; 109 Vec finemarked,coarsemarked; 110 IS inactive; 111 Mat inject; 112 const PetscInt *index; 113 PetscInt n,k,cnt = 0,rstart,*coarseindex; 114 PetscScalar *marked; 115 116 PetscFunctionBegin; 117 ierr = PetscObjectQuery((PetscObject)dm1,"VI",(PetscObject*)&isnes);CHKERRQ(ierr); 118 if (!isnes) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_PLIB,"Composed VI data structure is missing"); 119 ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi1);CHKERRQ(ierr); 120 121 /* get the original coarsen */ 122 ierr = (*dmsnesvi1->coarsen)(dm1,comm,dm2);CHKERRQ(ierr); 123 124 /* not sure why this extra reference is needed, but without the dm2 disappears too early */ 125 /* Updating the KSPCreateVecs() to avoid using DMGetGlobalVector() when matrix is available removes the need for this reference? */ 126 /* ierr = PetscObjectReference((PetscObject)*dm2);CHKERRQ(ierr);*/ 127 128 /* need to set back global vectors in order to use the original injection */ 129 ierr = DMClearGlobalVectors(dm1);CHKERRQ(ierr); 130 131 dm1->ops->createglobalvector = dmsnesvi1->createglobalvector; 132 133 ierr = DMCreateGlobalVector(dm1,&finemarked);CHKERRQ(ierr); 134 ierr = DMCreateGlobalVector(*dm2,&coarsemarked);CHKERRQ(ierr); 135 136 /* 137 fill finemarked with locations of inactive points 138 */ 139 ierr = ISGetIndices(dmsnesvi1->inactive,&index);CHKERRQ(ierr); 140 ierr = ISGetLocalSize(dmsnesvi1->inactive,&n);CHKERRQ(ierr); 141 ierr = VecSet(finemarked,0.0);CHKERRQ(ierr); 142 for (k=0; k<n; k++) { 143 ierr = VecSetValue(finemarked,index[k],1.0,INSERT_VALUES);CHKERRQ(ierr); 144 } 145 ierr = VecAssemblyBegin(finemarked);CHKERRQ(ierr); 146 ierr = VecAssemblyEnd(finemarked);CHKERRQ(ierr); 147 148 ierr = DMCreateInjection(*dm2,dm1,&inject);CHKERRQ(ierr); 149 ierr = MatRestrict(inject,finemarked,coarsemarked);CHKERRQ(ierr); 150 ierr = MatDestroy(&inject);CHKERRQ(ierr); 151 152 /* 153 create index set list of coarse inactive points from coarsemarked 154 */ 155 ierr = VecGetLocalSize(coarsemarked,&n);CHKERRQ(ierr); 156 ierr = VecGetOwnershipRange(coarsemarked,&rstart,NULL);CHKERRQ(ierr); 157 ierr = VecGetArray(coarsemarked,&marked);CHKERRQ(ierr); 158 for (k=0; k<n; k++) { 159 if (marked[k] != 0.0) cnt++; 160 } 161 ierr = PetscMalloc1(cnt,&coarseindex);CHKERRQ(ierr); 162 cnt = 0; 163 for (k=0; k<n; k++) { 164 if (marked[k] != 0.0) coarseindex[cnt++] = k + rstart; 165 } 166 ierr = VecRestoreArray(coarsemarked,&marked);CHKERRQ(ierr); 167 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)coarsemarked),cnt,coarseindex,PETSC_OWN_POINTER,&inactive);CHKERRQ(ierr); 168 169 ierr = DMClearGlobalVectors(dm1);CHKERRQ(ierr); 170 171 dm1->ops->createglobalvector = DMCreateGlobalVector_SNESVI; 172 173 ierr = DMSetVI(*dm2,inactive);CHKERRQ(ierr); 174 175 ierr = VecDestroy(&finemarked);CHKERRQ(ierr); 176 ierr = VecDestroy(&coarsemarked);CHKERRQ(ierr); 177 ierr = ISDestroy(&inactive);CHKERRQ(ierr); 178 PetscFunctionReturn(0); 179 } 180 181 #undef __FUNCT__ 182 #define __FUNCT__ "DMDestroy_SNESVI" 183 PetscErrorCode DMDestroy_SNESVI(DM_SNESVI *dmsnesvi) 184 { 185 PetscErrorCode ierr; 186 187 PetscFunctionBegin; 188 /* reset the base methods in the DM object that were changed when the DM_SNESVI was reset */ 189 dmsnesvi->dm->ops->createinterpolation = dmsnesvi->createinterpolation; 190 dmsnesvi->dm->ops->coarsen = dmsnesvi->coarsen; 191 dmsnesvi->dm->ops->createglobalvector = dmsnesvi->createglobalvector; 192 /* need to clear out this vectors because some of them may not have a reference to the DM 193 but they are counted as having references to the DM in DMDestroy() */ 194 ierr = DMClearGlobalVectors(dmsnesvi->dm);CHKERRQ(ierr); 195 196 ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr); 197 ierr = PetscFree(dmsnesvi);CHKERRQ(ierr); 198 PetscFunctionReturn(0); 199 } 200 201 #undef __FUNCT__ 202 #define __FUNCT__ "DMSetVI" 203 /* 204 DMSetVI - Marks a DM as associated with a VI problem. This causes the interpolation/restriction operators to 205 be restricted to only those variables NOT associated with active constraints. 206 207 */ 208 PetscErrorCode DMSetVI(DM dm,IS inactive) 209 { 210 PetscErrorCode ierr; 211 PetscContainer isnes; 212 DM_SNESVI *dmsnesvi; 213 214 PetscFunctionBegin; 215 if (!dm) PetscFunctionReturn(0); 216 217 ierr = PetscObjectReference((PetscObject)inactive);CHKERRQ(ierr); 218 219 ierr = PetscObjectQuery((PetscObject)dm,"VI",(PetscObject*)&isnes);CHKERRQ(ierr); 220 if (!isnes) { 221 ierr = PetscContainerCreate(PetscObjectComm((PetscObject)dm),&isnes);CHKERRQ(ierr); 222 ierr = PetscContainerSetUserDestroy(isnes,(PetscErrorCode (*)(void*))DMDestroy_SNESVI);CHKERRQ(ierr); 223 ierr = PetscNew(&dmsnesvi);CHKERRQ(ierr); 224 ierr = PetscContainerSetPointer(isnes,(void*)dmsnesvi);CHKERRQ(ierr); 225 ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)isnes);CHKERRQ(ierr); 226 ierr = PetscContainerDestroy(&isnes);CHKERRQ(ierr); 227 228 dmsnesvi->createinterpolation = dm->ops->createinterpolation; 229 dm->ops->createinterpolation = DMCreateInterpolation_SNESVI; 230 dmsnesvi->coarsen = dm->ops->coarsen; 231 dm->ops->coarsen = DMCoarsen_SNESVI; 232 dmsnesvi->createglobalvector = dm->ops->createglobalvector; 233 dm->ops->createglobalvector = DMCreateGlobalVector_SNESVI; 234 } else { 235 ierr = PetscContainerGetPointer(isnes,(void**)&dmsnesvi);CHKERRQ(ierr); 236 ierr = ISDestroy(&dmsnesvi->inactive);CHKERRQ(ierr); 237 } 238 ierr = DMClearGlobalVectors(dm);CHKERRQ(ierr); 239 ierr = ISGetLocalSize(inactive,&dmsnesvi->n);CHKERRQ(ierr); 240 241 dmsnesvi->inactive = inactive; 242 dmsnesvi->dm = dm; 243 PetscFunctionReturn(0); 244 } 245 246 #undef __FUNCT__ 247 #define __FUNCT__ "DMDestroyVI" 248 /* 249 DMDestroyVI - Frees the DM_SNESVI object contained in the DM 250 - also resets the function pointers in the DM for createinterpolation() etc to use the original DM 251 */ 252 PetscErrorCode DMDestroyVI(DM dm) 253 { 254 PetscErrorCode ierr; 255 256 PetscFunctionBegin; 257 if (!dm) PetscFunctionReturn(0); 258 ierr = PetscObjectCompose((PetscObject)dm,"VI",(PetscObject)NULL);CHKERRQ(ierr); 259 PetscFunctionReturn(0); 260 } 261 262 /* --------------------------------------------------------------------------------------------------------*/ 263 264 265 266 267 #undef __FUNCT__ 268 #define __FUNCT__ "SNESCreateIndexSets_VINEWTONRSLS" 269 PetscErrorCode SNESCreateIndexSets_VINEWTONRSLS(SNES snes,Vec X,Vec F,IS *ISact,IS *ISinact) 270 { 271 PetscErrorCode ierr; 272 273 PetscFunctionBegin; 274 ierr = SNESVIGetActiveSetIS(snes,X,F,ISact);CHKERRQ(ierr); 275 ierr = ISComplement(*ISact,X->map->rstart,X->map->rend,ISinact);CHKERRQ(ierr); 276 PetscFunctionReturn(0); 277 } 278 279 /* Create active and inactive set vectors. The local size of this vector is set and petsc computes the global size */ 280 #undef __FUNCT__ 281 #define __FUNCT__ "SNESCreateSubVectors_VINEWTONRSLS" 282 PetscErrorCode SNESCreateSubVectors_VINEWTONRSLS(SNES snes,PetscInt n,Vec *newv) 283 { 284 PetscErrorCode ierr; 285 Vec v; 286 287 PetscFunctionBegin; 288 ierr = VecCreate(PetscObjectComm((PetscObject)snes),&v);CHKERRQ(ierr); 289 ierr = VecSetSizes(v,n,PETSC_DECIDE);CHKERRQ(ierr); 290 ierr = VecSetType(v,VECSTANDARD);CHKERRQ(ierr); 291 *newv = v; 292 PetscFunctionReturn(0); 293 } 294 295 /* Resets the snes PC and KSP when the active set sizes change */ 296 #undef __FUNCT__ 297 #define __FUNCT__ "SNESVIResetPCandKSP" 298 PetscErrorCode SNESVIResetPCandKSP(SNES snes,Mat Amat,Mat Pmat) 299 { 300 PetscErrorCode ierr; 301 KSP snesksp; 302 303 PetscFunctionBegin; 304 ierr = SNESGetKSP(snes,&snesksp);CHKERRQ(ierr); 305 ierr = KSPReset(snesksp);CHKERRQ(ierr); 306 307 /* 308 KSP kspnew; 309 PC pcnew; 310 const MatSolverPackage stype; 311 312 313 ierr = KSPCreate(PetscObjectComm((PetscObject)snes),&kspnew);CHKERRQ(ierr); 314 kspnew->pc_side = snesksp->pc_side; 315 kspnew->rtol = snesksp->rtol; 316 kspnew->abstol = snesksp->abstol; 317 kspnew->max_it = snesksp->max_it; 318 ierr = KSPSetType(kspnew,((PetscObject)snesksp)->type_name);CHKERRQ(ierr); 319 ierr = KSPGetPC(kspnew,&pcnew);CHKERRQ(ierr); 320 ierr = PCSetType(kspnew->pc,((PetscObject)snesksp->pc)->type_name);CHKERRQ(ierr); 321 ierr = PCSetOperators(kspnew->pc,Amat,Pmat);CHKERRQ(ierr); 322 ierr = PCFactorGetMatSolverPackage(snesksp->pc,&stype);CHKERRQ(ierr); 323 ierr = PCFactorSetMatSolverPackage(kspnew->pc,stype);CHKERRQ(ierr); 324 ierr = KSPDestroy(&snesksp);CHKERRQ(ierr); 325 snes->ksp = kspnew; 326 ierr = PetscLogObjectParent((PetscObject)snes,(PetscObject)kspnew);CHKERRQ(ierr); 327 ierr = KSPSetFromOptions(kspnew);CHKERRQ(ierr);*/ 328 PetscFunctionReturn(0); 329 } 330 331 /* Variational Inequality solver using reduce space method. No semismooth algorithm is 332 implemented in this algorithm. It basically identifies the active constraints and does 333 a linear solve on the other variables (those not associated with the active constraints). */ 334 #undef __FUNCT__ 335 #define __FUNCT__ "SNESSolve_VINEWTONRSLS" 336 PetscErrorCode SNESSolve_VINEWTONRSLS(SNES snes) 337 { 338 SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data; 339 PetscErrorCode ierr; 340 PetscInt maxits,i,lits; 341 SNESLineSearchReason lssucceed; 342 PetscReal fnorm,gnorm,xnorm=0,ynorm; 343 Vec Y,X,F; 344 KSPConvergedReason kspreason; 345 KSP ksp; 346 PC pc; 347 348 PetscFunctionBegin; 349 /* Multigrid must use Galerkin for coarse grids with active set/reduced space methods; cannot rediscretize on coarser grids*/ 350 ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr); 351 ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); 352 ierr = PCMGSetGalerkin(pc,PETSC_TRUE);CHKERRQ(ierr); 353 354 snes->numFailures = 0; 355 snes->numLinearSolveFailures = 0; 356 snes->reason = SNES_CONVERGED_ITERATING; 357 358 maxits = snes->max_its; /* maximum number of iterations */ 359 X = snes->vec_sol; /* solution vector */ 360 F = snes->vec_func; /* residual vector */ 361 Y = snes->work[0]; /* work vectors */ 362 363 ierr = SNESLineSearchSetVIFunctions(snes->linesearch, SNESVIProjectOntoBounds, SNESVIComputeInactiveSetFnorm);CHKERRQ(ierr); 364 ierr = SNESLineSearchSetVecs(snes->linesearch, X, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 365 ierr = SNESLineSearchSetUp(snes->linesearch);CHKERRQ(ierr); 366 367 ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 368 snes->iter = 0; 369 snes->norm = 0.0; 370 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 371 372 ierr = SNESVIProjectOntoBounds(snes,X);CHKERRQ(ierr); 373 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 374 ierr = SNESVIComputeInactiveSetFnorm(snes,F,X,&fnorm);CHKERRQ(ierr); 375 ierr = VecNormBegin(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm <- ||x|| */ 376 ierr = VecNormEnd(X,NORM_2,&xnorm);CHKERRQ(ierr); 377 SNESCheckFunctionNorm(snes,fnorm); 378 ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 379 snes->norm = fnorm; 380 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 381 ierr = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr); 382 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 383 384 /* test convergence */ 385 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 386 if (snes->reason) PetscFunctionReturn(0); 387 388 389 for (i=0; i<maxits; i++) { 390 391 IS IS_act; /* _act -> active set _inact -> inactive set */ 392 IS IS_redact; /* redundant active set */ 393 VecScatter scat_act,scat_inact; 394 PetscInt nis_act,nis_inact; 395 Vec Y_act,Y_inact,F_inact; 396 Mat jac_inact_inact,prejac_inact_inact; 397 PetscBool isequal; 398 399 /* Call general purpose update function */ 400 if (snes->ops->update) { 401 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 402 } 403 ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr); 404 405 406 /* Create active and inactive index sets */ 407 408 /*original 409 ierr = SNESVICreateIndexSets_RS(snes,X,F,&IS_act,&vi->IS_inact);CHKERRQ(ierr); 410 */ 411 ierr = SNESVIGetActiveSetIS(snes,X,F,&IS_act);CHKERRQ(ierr); 412 413 if (vi->checkredundancy) { 414 (*vi->checkredundancy)(snes,IS_act,&IS_redact,vi->ctxP);CHKERRQ(ierr); 415 if (IS_redact) { 416 ierr = ISSort(IS_redact);CHKERRQ(ierr); 417 ierr = ISComplement(IS_redact,X->map->rstart,X->map->rend,&vi->IS_inact);CHKERRQ(ierr); 418 ierr = ISDestroy(&IS_redact);CHKERRQ(ierr); 419 } else { 420 ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&vi->IS_inact);CHKERRQ(ierr); 421 } 422 } else { 423 ierr = ISComplement(IS_act,X->map->rstart,X->map->rend,&vi->IS_inact);CHKERRQ(ierr); 424 } 425 426 427 /* Create inactive set submatrix */ 428 ierr = MatGetSubMatrix(snes->jacobian,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr); 429 430 if (0) { /* Dead code (temporary developer hack) */ 431 IS keptrows; 432 ierr = MatFindNonzeroRows(jac_inact_inact,&keptrows);CHKERRQ(ierr); 433 if (keptrows) { 434 PetscInt cnt,*nrows,k; 435 const PetscInt *krows,*inact; 436 PetscInt rstart=jac_inact_inact->rmap->rstart; 437 438 ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr); 439 ierr = ISDestroy(&IS_act);CHKERRQ(ierr); 440 441 ierr = ISGetLocalSize(keptrows,&cnt);CHKERRQ(ierr); 442 ierr = ISGetIndices(keptrows,&krows);CHKERRQ(ierr); 443 ierr = ISGetIndices(vi->IS_inact,&inact);CHKERRQ(ierr); 444 ierr = PetscMalloc1(cnt,&nrows);CHKERRQ(ierr); 445 for (k=0; k<cnt; k++) nrows[k] = inact[krows[k]-rstart]; 446 ierr = ISRestoreIndices(keptrows,&krows);CHKERRQ(ierr); 447 ierr = ISRestoreIndices(vi->IS_inact,&inact);CHKERRQ(ierr); 448 ierr = ISDestroy(&keptrows);CHKERRQ(ierr); 449 ierr = ISDestroy(&vi->IS_inact);CHKERRQ(ierr); 450 451 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)snes),cnt,nrows,PETSC_OWN_POINTER,&vi->IS_inact);CHKERRQ(ierr); 452 ierr = ISComplement(vi->IS_inact,F->map->rstart,F->map->rend,&IS_act);CHKERRQ(ierr); 453 ierr = MatGetSubMatrix(snes->jacobian,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&jac_inact_inact);CHKERRQ(ierr); 454 } 455 } 456 ierr = DMSetVI(snes->dm,vi->IS_inact);CHKERRQ(ierr); 457 /* remove later */ 458 459 /* 460 ierr = VecView(vi->xu,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xu))->comm));CHKERRQ(ierr); 461 ierr = VecView(vi->xl,PETSC_VIEWER_BINARY_(((PetscObject)(vi->xl))->comm));CHKERRQ(ierr); 462 ierr = VecView(X,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)X)));CHKERRQ(ierr); 463 ierr = VecView(F,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)F)));CHKERRQ(ierr); 464 ierr = ISView(vi->IS_inact,PETSC_VIEWER_BINARY_(PetscObjectComm((PetscObject)vi->IS_inact)));CHKERRQ(ierr); 465 */ 466 467 /* Get sizes of active and inactive sets */ 468 ierr = ISGetLocalSize(IS_act,&nis_act);CHKERRQ(ierr); 469 ierr = ISGetLocalSize(vi->IS_inact,&nis_inact);CHKERRQ(ierr); 470 471 /* Create active and inactive set vectors */ 472 ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_inact,&F_inact);CHKERRQ(ierr); 473 ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_act,&Y_act);CHKERRQ(ierr); 474 ierr = SNESCreateSubVectors_VINEWTONRSLS(snes,nis_inact,&Y_inact);CHKERRQ(ierr); 475 476 /* Create scatter contexts */ 477 ierr = VecScatterCreate(Y,IS_act,Y_act,NULL,&scat_act);CHKERRQ(ierr); 478 ierr = VecScatterCreate(Y,vi->IS_inact,Y_inact,NULL,&scat_inact);CHKERRQ(ierr); 479 480 /* Do a vec scatter to active and inactive set vectors */ 481 ierr = VecScatterBegin(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 482 ierr = VecScatterEnd(scat_inact,F,F_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 483 484 ierr = VecScatterBegin(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 485 ierr = VecScatterEnd(scat_act,Y,Y_act,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 486 487 ierr = VecScatterBegin(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 488 ierr = VecScatterEnd(scat_inact,Y,Y_inact,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 489 490 /* Active set direction = 0 */ 491 ierr = VecSet(Y_act,0);CHKERRQ(ierr); 492 if (snes->jacobian != snes->jacobian_pre) { 493 ierr = MatGetSubMatrix(snes->jacobian_pre,vi->IS_inact,vi->IS_inact,MAT_INITIAL_MATRIX,&prejac_inact_inact);CHKERRQ(ierr); 494 } else prejac_inact_inact = jac_inact_inact; 495 496 ierr = ISEqual(vi->IS_inact_prev,vi->IS_inact,&isequal);CHKERRQ(ierr); 497 if (!isequal) { 498 ierr = SNESVIResetPCandKSP(snes,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr); 499 } 500 501 /* ierr = ISView(vi->IS_inact,0);CHKERRQ(ierr); */ 502 /* ierr = ISView(IS_act,0);CHKERRQ(ierr);*/ 503 /* ierr = MatView(snes->jacobian_pre,0); */ 504 505 506 507 ierr = KSPSetOperators(snes->ksp,jac_inact_inact,prejac_inact_inact);CHKERRQ(ierr); 508 ierr = KSPSetUp(snes->ksp);CHKERRQ(ierr); 509 { 510 PC pc; 511 PetscBool flg; 512 ierr = KSPGetPC(snes->ksp,&pc);CHKERRQ(ierr); 513 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&flg);CHKERRQ(ierr); 514 if (flg) { 515 KSP *subksps; 516 ierr = PCFieldSplitGetSubKSP(pc,NULL,&subksps);CHKERRQ(ierr); 517 ierr = KSPGetPC(subksps[0],&pc);CHKERRQ(ierr); 518 ierr = PetscFree(subksps);CHKERRQ(ierr); 519 ierr = PetscObjectTypeCompare((PetscObject)pc,PCBJACOBI,&flg);CHKERRQ(ierr); 520 if (flg) { 521 PetscInt n,N = 101*101,j,cnts[3] = {0,0,0}; 522 const PetscInt *ii; 523 524 ierr = ISGetSize(vi->IS_inact,&n);CHKERRQ(ierr); 525 ierr = ISGetIndices(vi->IS_inact,&ii);CHKERRQ(ierr); 526 for (j=0; j<n; j++) { 527 if (ii[j] < N) cnts[0]++; 528 else if (ii[j] < 2*N) cnts[1]++; 529 else if (ii[j] < 3*N) cnts[2]++; 530 } 531 ierr = ISRestoreIndices(vi->IS_inact,&ii);CHKERRQ(ierr); 532 533 ierr = PCBJacobiSetTotalBlocks(pc,3,cnts);CHKERRQ(ierr); 534 } 535 } 536 } 537 538 ierr = KSPSolve(snes->ksp,F_inact,Y_inact);CHKERRQ(ierr); 539 ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 540 if (kspreason < 0) { 541 if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 542 ierr = PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);CHKERRQ(ierr); 543 snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 544 break; 545 } 546 } 547 548 ierr = VecScatterBegin(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 549 ierr = VecScatterEnd(scat_act,Y_act,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 550 ierr = VecScatterBegin(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 551 ierr = VecScatterEnd(scat_inact,Y_inact,Y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 552 553 ierr = VecDestroy(&F_inact);CHKERRQ(ierr); 554 ierr = VecDestroy(&Y_act);CHKERRQ(ierr); 555 ierr = VecDestroy(&Y_inact);CHKERRQ(ierr); 556 ierr = VecScatterDestroy(&scat_act);CHKERRQ(ierr); 557 ierr = VecScatterDestroy(&scat_inact);CHKERRQ(ierr); 558 ierr = ISDestroy(&IS_act);CHKERRQ(ierr); 559 if (!isequal) { 560 ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr); 561 ierr = ISDuplicate(vi->IS_inact,&vi->IS_inact_prev);CHKERRQ(ierr); 562 } 563 ierr = ISDestroy(&vi->IS_inact);CHKERRQ(ierr); 564 ierr = MatDestroy(&jac_inact_inact);CHKERRQ(ierr); 565 if (snes->jacobian != snes->jacobian_pre) { 566 ierr = MatDestroy(&prejac_inact_inact);CHKERRQ(ierr); 567 } 568 ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 569 snes->linear_its += lits; 570 ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr); 571 /* 572 if (snes->ops->precheck) { 573 PetscBool changed_y = PETSC_FALSE; 574 ierr = (*snes->ops->precheck)(snes,X,Y,snes->precheck,&changed_y);CHKERRQ(ierr); 575 } 576 577 if (PetscLogPrintInfo) { 578 ierr = SNESVICheckResidual_Private(snes,snes->jacobian,F,Y,G,W);CHKERRQ(ierr); 579 } 580 */ 581 /* Compute a (scaled) negative update in the line search routine: 582 Y <- X - lambda*Y 583 and evaluate G = function(Y) (depends on the line search). 584 */ 585 ierr = VecCopy(Y,snes->vec_sol_update);CHKERRQ(ierr); 586 ynorm = 1; gnorm = fnorm; 587 ierr = SNESLineSearchApply(snes->linesearch, X, F, &gnorm, Y);CHKERRQ(ierr); 588 ierr = SNESLineSearchGetReason(snes->linesearch, &lssucceed);CHKERRQ(ierr); 589 ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &gnorm, &ynorm);CHKERRQ(ierr); 590 ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)fnorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr); 591 if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 592 if (snes->domainerror) { 593 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 594 ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr); 595 PetscFunctionReturn(0); 596 } 597 if (lssucceed) { 598 if (++snes->numFailures >= snes->maxFailures) { 599 PetscBool ismin; 600 snes->reason = SNES_DIVERGED_LINE_SEARCH; 601 ierr = SNESVICheckLocalMin_Private(snes,snes->jacobian,F,X,gnorm,&ismin);CHKERRQ(ierr); 602 if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 603 break; 604 } 605 } 606 ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr); 607 /* Update function and solution vectors */ 608 fnorm = gnorm; 609 /* Monitor convergence */ 610 ierr = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr); 611 snes->iter = i+1; 612 snes->norm = fnorm; 613 ierr = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr); 614 ierr = SNESLogConvergenceHistory(snes,snes->norm,lits);CHKERRQ(ierr); 615 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 616 /* Test for convergence, xnorm = || X || */ 617 if (snes->ops->converged != SNESConvergedSkip) { ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); } 618 ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 619 if (snes->reason) break; 620 } 621 /* make sure that the VI information attached to the DM is removed if the for loop above was broken early due to some exceptional conditional */ 622 ierr = DMDestroyVI(snes->dm);CHKERRQ(ierr); 623 if (i == maxits) { 624 ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr); 625 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 626 } 627 PetscFunctionReturn(0); 628 } 629 630 #undef __FUNCT__ 631 #define __FUNCT__ "SNESVISetRedundancyCheck" 632 PetscErrorCode SNESVISetRedundancyCheck(SNES snes,PetscErrorCode (*func)(SNES,IS,IS*,void*),void *ctx) 633 { 634 SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*)snes->data; 635 636 PetscFunctionBegin; 637 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 638 vi->checkredundancy = func; 639 vi->ctxP = ctx; 640 PetscFunctionReturn(0); 641 } 642 643 #if defined(PETSC_HAVE_MATLAB_ENGINE) 644 #include <engine.h> 645 #include <mex.h> 646 typedef struct {char *funcname; mxArray *ctx;} SNESMatlabContext; 647 648 #undef __FUNCT__ 649 #define __FUNCT__ "SNESVIRedundancyCheck_Matlab" 650 PetscErrorCode SNESVIRedundancyCheck_Matlab(SNES snes,IS is_act,IS *is_redact,void *ctx) 651 { 652 PetscErrorCode ierr; 653 SNESMatlabContext *sctx = (SNESMatlabContext*)ctx; 654 int nlhs = 1, nrhs = 5; 655 mxArray *plhs[1], *prhs[5]; 656 long long int l1 = 0, l2 = 0, ls = 0; 657 PetscInt *indices=NULL; 658 659 PetscFunctionBegin; 660 PetscValidHeaderSpecific(snes,SNES_CLASSID,1); 661 PetscValidHeaderSpecific(is_act,IS_CLASSID,2); 662 PetscValidPointer(is_redact,3); 663 PetscCheckSameComm(snes,1,is_act,2); 664 665 /* Create IS for reduced active set of size 0, its size and indices will 666 bet set by the Matlab function */ 667 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)snes),0,indices,PETSC_OWN_POINTER,is_redact);CHKERRQ(ierr); 668 /* call Matlab function in ctx */ 669 ierr = PetscMemcpy(&ls,&snes,sizeof(snes));CHKERRQ(ierr); 670 ierr = PetscMemcpy(&l1,&is_act,sizeof(is_act));CHKERRQ(ierr); 671 ierr = PetscMemcpy(&l2,is_redact,sizeof(is_act));CHKERRQ(ierr); 672 prhs[0] = mxCreateDoubleScalar((double)ls); 673 prhs[1] = mxCreateDoubleScalar((double)l1); 674 prhs[2] = mxCreateDoubleScalar((double)l2); 675 prhs[3] = mxCreateString(sctx->funcname); 676 prhs[4] = sctx->ctx; 677 ierr = mexCallMATLAB(nlhs,plhs,nrhs,prhs,"PetscSNESVIRedundancyCheckInternal");CHKERRQ(ierr); 678 ierr = mxGetScalar(plhs[0]);CHKERRQ(ierr); 679 mxDestroyArray(prhs[0]); 680 mxDestroyArray(prhs[1]); 681 mxDestroyArray(prhs[2]); 682 mxDestroyArray(prhs[3]); 683 mxDestroyArray(plhs[0]); 684 PetscFunctionReturn(0); 685 } 686 687 #undef __FUNCT__ 688 #define __FUNCT__ "SNESVISetRedundancyCheckMatlab" 689 PetscErrorCode SNESVISetRedundancyCheckMatlab(SNES snes,const char *func,mxArray *ctx) 690 { 691 PetscErrorCode ierr; 692 SNESMatlabContext *sctx; 693 694 PetscFunctionBegin; 695 /* currently sctx is memory bleed */ 696 ierr = PetscNew(&sctx);CHKERRQ(ierr); 697 ierr = PetscStrallocpy(func,&sctx->funcname);CHKERRQ(ierr); 698 sctx->ctx = mxDuplicateArray(ctx); 699 ierr = SNESVISetRedundancyCheck(snes,SNESVIRedundancyCheck_Matlab,sctx);CHKERRQ(ierr); 700 PetscFunctionReturn(0); 701 } 702 703 #endif 704 705 /* -------------------------------------------------------------------------- */ 706 /* 707 SNESSetUp_VINEWTONRSLS - Sets up the internal data structures for the later use 708 of the SNESVI nonlinear solver. 709 710 Input Parameter: 711 . snes - the SNES context 712 713 Application Interface Routine: SNESSetUp() 714 715 Notes: 716 For basic use of the SNES solvers, the user need not explicitly call 717 SNESSetUp(), since these actions will automatically occur during 718 the call to SNESSolve(). 719 */ 720 #undef __FUNCT__ 721 #define __FUNCT__ "SNESSetUp_VINEWTONRSLS" 722 PetscErrorCode SNESSetUp_VINEWTONRSLS(SNES snes) 723 { 724 PetscErrorCode ierr; 725 SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*) snes->data; 726 PetscInt *indices; 727 PetscInt i,n,rstart,rend; 728 SNESLineSearch linesearch; 729 730 PetscFunctionBegin; 731 ierr = SNESSetUp_VI(snes);CHKERRQ(ierr); 732 733 /* Set up previous active index set for the first snes solve 734 vi->IS_inact_prev = 0,1,2,....N */ 735 736 ierr = VecGetOwnershipRange(snes->vec_sol,&rstart,&rend);CHKERRQ(ierr); 737 ierr = VecGetLocalSize(snes->vec_sol,&n);CHKERRQ(ierr); 738 ierr = PetscMalloc1(n,&indices);CHKERRQ(ierr); 739 for (i=0; i < n; i++) indices[i] = rstart + i; 740 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)snes),n,indices,PETSC_OWN_POINTER,&vi->IS_inact_prev);CHKERRQ(ierr); 741 742 /* set the line search functions */ 743 if (!snes->linesearch) { 744 ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr); 745 ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);CHKERRQ(ierr); 746 } 747 PetscFunctionReturn(0); 748 } 749 /* -------------------------------------------------------------------------- */ 750 #undef __FUNCT__ 751 #define __FUNCT__ "SNESReset_VINEWTONRSLS" 752 PetscErrorCode SNESReset_VINEWTONRSLS(SNES snes) 753 { 754 SNES_VINEWTONRSLS *vi = (SNES_VINEWTONRSLS*) snes->data; 755 PetscErrorCode ierr; 756 757 PetscFunctionBegin; 758 ierr = SNESReset_VI(snes);CHKERRQ(ierr); 759 ierr = ISDestroy(&vi->IS_inact_prev);CHKERRQ(ierr); 760 PetscFunctionReturn(0); 761 } 762 763 /* -------------------------------------------------------------------------- */ 764 /*MC 765 SNESVINEWTONRSLS - Reduced space active set solvers for variational inequalities based on Newton's method 766 767 Options Database: 768 + -snes_type <vinewtonssls,vinewtonrsls> a semi-smooth solver, a reduced space active set method 769 - -snes_vi_monitor - prints the number of active constraints at each iteration. 770 771 Level: beginner 772 773 References: 774 - T. S. Munson, and S. Benson. Flexible Complementarity Solvers for Large-Scale 775 Applications, Optimization Methods and Software, 21 (2006). 776 777 .seealso: SNESVISetVariableBounds(), SNESVISetComputeVariableBounds(), SNESCreate(), SNES, SNESSetType(), SNESVINEWTONSSLS, SNESNEWTONTR, SNESLineSearchSet(),SNESLineSearchSetPostCheck(), SNESLineSearchSetPreCheck() 778 779 M*/ 780 #undef __FUNCT__ 781 #define __FUNCT__ "SNESCreate_VINEWTONRSLS" 782 PETSC_EXTERN PetscErrorCode SNESCreate_VINEWTONRSLS(SNES snes) 783 { 784 PetscErrorCode ierr; 785 SNES_VINEWTONRSLS *vi; 786 787 PetscFunctionBegin; 788 snes->ops->reset = SNESReset_VINEWTONRSLS; 789 snes->ops->setup = SNESSetUp_VINEWTONRSLS; 790 snes->ops->solve = SNESSolve_VINEWTONRSLS; 791 snes->ops->destroy = SNESDestroy_VI; 792 snes->ops->setfromoptions = SNESSetFromOptions_VI; 793 snes->ops->view = NULL; 794 snes->ops->converged = SNESConvergedDefault_VI; 795 796 snes->usesksp = PETSC_TRUE; 797 snes->usespc = PETSC_FALSE; 798 799 ierr = PetscNewLog(snes,&vi);CHKERRQ(ierr); 800 snes->data = (void*)vi; 801 vi->checkredundancy = NULL; 802 803 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESVISetVariableBounds_C",SNESVISetVariableBounds_VI);CHKERRQ(ierr); 804 ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESVISetComputeVariableBounds_C",SNESVISetComputeVariableBounds_VI);CHKERRQ(ierr); 805 PetscFunctionReturn(0); 806 } 807 808