Actual source code: sinvert.c

  1: /*
  2:       Implements the shift-and-invert technique for eigenvalue problems.
  3: */
 4:  #include src/st/stimpl.h

  8: PetscErrorCode STApply_Sinvert(ST st,Vec x,Vec y)
  9: {

 13:   if (st->B) {
 14:     /* generalized eigenproblem: y = (A - sB)^-1 B x */
 15:     MatMult(st->B,x,st->w);
 16:     STAssociatedKSPSolve(st,st->w,y);
 17:   }
 18:   else {
 19:     /* standard eigenproblem: y = (A - sI)^-1 x */
 20:     STAssociatedKSPSolve(st,x,y);
 21:   }
 22:   return(0);
 23: }

 27: PetscErrorCode STApplyTranspose_Sinvert(ST st,Vec x,Vec y)
 28: {

 32:   if (st->B) {
 33:     /* generalized eigenproblem: y = B^T (A - sB)^-T x */
 34:     STAssociatedKSPSolveTranspose(st,x,st->w);
 35:     MatMultTranspose(st->B,st->w,y);
 36:   }
 37:   else {
 38:     /* standard eigenproblem: y = (A - sI)^-T x */
 39:     STAssociatedKSPSolveTranspose(st,x,y);
 40:   }
 41:   return(0);
 42: }

 46: PetscErrorCode STApplyNoB_Sinvert(ST st,Vec x,Vec y)
 47: {

 51:   STAssociatedKSPSolve(st,x,y);
 52:   return(0);
 53: }

 57: PetscErrorCode STApplyB_Sinvert(ST st,Vec x,Vec y)
 58: {

 62:   if( st->B ) {
 63:     MatMult( st->B, x, y );
 64:   }
 65:   else {
 66:     VecCopy( x, y );
 67:   }
 68:   return(0);
 69: }

 73: PetscErrorCode STBackTransform_Sinvert(ST st,PetscScalar *eigr,PetscScalar *eigi)
 74: {
 75: #ifndef PETSC_USE_COMPLEX
 76:   PetscScalar t;
 80:   if (*eigi == 0) *eigr = 1.0 / *eigr + st->sigma;
 81:   else {
 82:     t = *eigr * *eigr + *eigi * *eigi;
 83:     *eigr = *eigr / t + st->sigma;
 84:     *eigi = - *eigi / t;
 85:   }
 86: #else
 89:   *eigr = 1.0 / *eigr + st->sigma;
 90: #endif
 91:   return(0);
 92: }

 96: PetscErrorCode STPostSolve_Sinvert(ST st)
 97: {

101:   if (st->shift_matrix == STMATMODE_INPLACE) {
102:     if( st->B ) {
103:       MatAXPY(st->A,st->sigma,st->B,st->str);
104:     } else {
105:       MatShift(st->A,st->sigma);
106:     }
107:     st->setupcalled = 0;
108:   }
109:   return(0);
110: }

114: PetscErrorCode STSetUp_Sinvert(ST st)
115: {

119: 
120:   if (st->mat) { MatDestroy(st->mat); }

122:   switch (st->shift_matrix) {
123:   case STMATMODE_INPLACE:
124:     st->mat = PETSC_NULL;
125:     if (st->sigma != 0.0) {
126:       if (st->B) {
127:         MatAXPY(st->A,-st->sigma,st->B,st->str);
128:       } else {
129:         MatShift(st->A,-st->sigma);
130:       }
131:     }
132:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
133:      * improve performance when solving a number of related eigenproblems */
134:     KSPSetOperators(st->ksp,st->A,st->A,SAME_NONZERO_PATTERN);
135:     break;
136:   case STMATMODE_SHELL:
137:     STMatShellCreate(st,&st->mat);
138:     KSPSetOperators(st->ksp,st->mat,st->mat,DIFFERENT_NONZERO_PATTERN);
139:     break;
140:   default:
141:     MatDuplicate(st->A,MAT_COPY_VALUES,&st->mat);
142:     if (st->sigma != 0.0) {
143:       if (st->B) {
144:         MatAXPY(st->mat,-st->sigma,st->B,st->str);
145:       } else {
146:         MatShift(st->mat,-st->sigma);
147:       }
148:     }
149:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
150:      * improve performance when solving a number of related eigenproblems */
151:     KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
152:   }
153:   KSPSetUp(st->ksp);
154:   return(0);
155: }

159: PetscErrorCode STSetShift_Sinvert(ST st,PetscScalar newshift)
160: {


165:   /* Nothing to be done if STSetUp has not been called yet */
166:   if (!st->setupcalled) return(0);

168:   switch (st->shift_matrix) {
169:   case STMATMODE_INPLACE:
170:     /* Undo previous operations */
171:     if (st->sigma != 0.0) {
172:       if (st->B) {
173:         MatAXPY(st->A,st->sigma,st->B,st->str);
174:       } else {
175:         MatShift(st->A,st->sigma);
176:       }
177:     }
178:     /* Apply new shift */
179:     if (newshift != 0.0) {
180:       if (st->B) {
181:         MatAXPY(st->A,-newshift,st->B,st->str);
182:       } else {
183:         MatShift(st->A,-newshift);
184:       }
185:     }
186:     KSPSetOperators(st->ksp,st->A,st->A,SAME_NONZERO_PATTERN);
187:     break;
188:   case STMATMODE_SHELL:
189:     KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
190:     break;
191:   default:
192:     MatCopy(st->A, st->mat,SUBSET_NONZERO_PATTERN);
193:     if (newshift != 0.0) {
194:       if (st->B) {
195:         MatAXPY(st->mat,-newshift,st->B,st->str);
196:       } else {
197:         MatShift(st->mat,-newshift);
198:       }
199:     }
200:     /* In the following line, the SAME_NONZERO_PATTERN flag has been used to
201:      * improve performance when solving a number of related eigenproblems */
202:     KSPSetOperators(st->ksp,st->mat,st->mat,SAME_NONZERO_PATTERN);
203:   }
204:   st->sigma = newshift;
205:   KSPSetUp(st->ksp);
206:   return(0);
207: }

212: PetscErrorCode STCreate_Sinvert(ST st)
213: {
215:   st->data                = 0;

217:   st->ops->apply          = STApply_Sinvert;
218:   st->ops->applyB         = STApplyB_Sinvert;
219:   st->ops->applynoB       = STApplyNoB_Sinvert;
220:   st->ops->applytrans     = STApplyTranspose_Sinvert;
221:   st->ops->postsolve      = STPostSolve_Sinvert;
222:   st->ops->backtr         = STBackTransform_Sinvert;
223:   st->ops->setup          = STSetUp_Sinvert;
224:   st->ops->setshift       = STSetShift_Sinvert;
225:   st->ops->view           = STView_Default;
226: 
227:   st->checknullspace      = STCheckNullSpace_Default;

229:   return(0);
230: }