Actual source code: lcd.c
1: #define PETSCKSP_DLL
2: /*
3: This file implements the LCD (left conjugate direction) method in PETSc.
4: References:
5: - J.Y. Yuan, G.H.Golub, R.J. Plemmons, and W.A.G. Cecilio. Semiconjugate
6: direction methods for real positive definite system. BIT Numerical
7: Mathematics, 44(1):189-207,2004.
8: - Y. Dai and J.Y. Yuan. Study on semi-conjugate direction methods for
9: non-symmetric systems. International Journal for Numerical Methods in
10: Engineering, 60:1383-1399,2004.
11: - L. Catabriga, A.L.G.A. Coutinho, and L.P.Franca. Evaluating the LCD
12: algorithm for solving linear systems of equations arising from implicit
13: SUPG formulation of compressible flows. International Journal for
14: Numerical Methods in Engineering, 60:1513-1534,2004
15: - L. Catabriga, A. M. P. Valli, B. Z. Melotti, L. M. Pessoa,
16: A. L. G. A. Coutinho, Performance of LCD iterative method in the finite
17: element and finite difference solution of convection-diffusion
18: equations, Communications in Numerical Methods in Engineering, (Early
19: View).
21: Contributed by: Lucia Catabriga <luciac@ices.utexas.edu>
22: */
24: #include src/ksp/ksp/impls/lcd/lcdctx.h
28: PetscErrorCode KSPSetUp_LCD(KSP ksp)
29: {
30: KSP_LCD *lcd = (KSP_LCD*)ksp->data;
32: PetscInt restart = lcd->restart;
35: /*
36: This implementation of LCD only handles left preconditioning
37: so generate an error otherwise.
38: */
39: if (ksp->pc_side == PC_RIGHT) {
40: SETERRQ(2,"No right preconditioning for KSPLCD");
41: } else if (ksp->pc_side == PC_SYMMETRIC) {
42: SETERRQ(2,"No symmetric preconditioning for KSPLCD");
43: }
45: /* get work vectors needed by LCD */
46: KSPDefaultGetWork(ksp,2);
47:
48: VecDuplicateVecs(ksp->vec_rhs,restart+1,&lcd->P);
49: VecDuplicateVecs(ksp->vec_rhs, restart + 1, &lcd->Q);
50: PetscLogObjectMemory(ksp,2*(restart+2)*sizeof(Vec));
51: return(0);
52: }
54: /* KSPSolve_LCD - This routine actually applies the left conjugate
55: direction method
57: Input Parameter:
58: . ksp - the Krylov space object that was set to use LCD, by, for
59: example, KSPCreate(MPI_Comm,KSP *ksp); KSPSetType(ksp,KSPLCD);
61: Output Parameter:
62: . its - number of iterations used
64: */
67: PetscErrorCode KSPSolve_LCD(KSP ksp)
68: {
70: PetscInt it,j,max_k;
71: PetscScalar alfa, beta, num, den, mone, pone;
72: PetscReal rnorm;
73: Vec X,B,R,Z;
74: KSP_LCD *lcd;
75: Mat Amat,Pmat;
76: MatStructure pflag;
77: PetscTruth diagonalscale;
80:
81: PCDiagonalScale(ksp->pc,&diagonalscale);
82: if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",ksp->type_name);
84: lcd = (KSP_LCD*)ksp->data;
85: X = ksp->vec_sol;
86: B = ksp->vec_rhs;
87: R = ksp->work[0];
88: Z = ksp->work[1];
89: max_k = lcd->restart;
90: mone = -1;
91: pone = 1;
93: PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);
95: ksp->its = 0;
96: if (!ksp->guess_zero) {
97: KSP_MatMult(ksp,Amat,X,Z); /* z <- b - Ax */
98: VecAYPX(Z,mone,B);
99: } else {
100: VecCopy(B,Z); /* z <- b (x is 0) */
101: }
102:
103: KSP_PCApply(ksp,Z,R); /* r <- M^-1z */
104: VecNorm(R,NORM_2,&rnorm);
105: KSPLogResidualHistory(ksp,rnorm);
106: KSPMonitor(ksp,0,rnorm); /* call any registered monitor routines */
107: ksp->rnorm = rnorm;
108:
109: /* test for convergence */
110: (*ksp->converged)(ksp,0,rnorm,&ksp->reason,ksp->cnvP);
111: if (ksp->reason) return(0);
113: it = 0;
114: VecCopy(R,lcd->P[0]);
115:
116: while (!ksp->reason && ksp->its < ksp->max_it) {
117: it = 0;
118: KSP_MatMult(ksp,Amat,lcd->P[it],Z);
119: KSP_PCApply(ksp,Z,lcd->Q[it]);
120:
121: while(!ksp->reason && it < max_k && ksp->its < ksp->max_it) {
122: ksp->its++;
123: VecDot(lcd->P[it],R,&num);
124: VecDot(lcd->P[it],lcd->Q[it], &den);
125: alfa = num/den;
126: VecAXPY(X,alfa,lcd->P[it]);
127: VecAXPY(R,-alfa,lcd->Q[it]);
128: VecNorm(R,NORM_2,&rnorm);
130: ksp->rnorm = rnorm;
131: KSPLogResidualHistory(ksp,rnorm);
132: KSPMonitor(ksp,ksp->its,rnorm);
133: (*ksp->converged)(ksp,ksp->its,rnorm,&ksp->reason,ksp->cnvP);
134:
135: if (ksp->reason) break;
136:
137: VecCopy(R,lcd->P[it+1]);
138: KSP_MatMult(ksp,Amat,lcd->P[it+1],Z);
139: KSP_PCApply(ksp,Z,lcd->Q[it+1]);
140:
141: for( j = 0; j <= it; j++) {
142: VecDot(lcd->P[j],lcd->Q[it+1],&num);
143: VecDot(lcd->P[j],lcd->Q[j],&den);
144: beta = - num/den;
145: VecAXPY(lcd->P[it+1],beta,lcd->P[j]);
146: VecAXPY(lcd->Q[it+1],beta,lcd->Q[j]);
147: }
148: it++;
149: }
150: VecCopy(lcd->P[it],lcd->P[0]);
151: }
152: if (ksp->its >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
153: VecCopy(X,ksp->vec_sol);
154:
155: return(0);
156: }
157: /*
158: KSPDestroy_LCD - Frees all memory space used by the Krylov method
160: */
163: PetscErrorCode KSPDestroy_LCD(KSP ksp)
164: {
165: KSP_LCD *lcd = (KSP_LCD*)ksp->data;
169: KSPDefaultFreeWork(ksp);
170: if (lcd->P) { VecDestroyVecs(lcd->P, lcd->restart+1); }
171: if (lcd->Q) { VecDestroyVecs(lcd->Q, lcd->restart+1); }
172: PetscFree(ksp->data);
173: return(0);
174: }
176: /*
177: KSPView_LCD - Prints information about the current Krylov method being used
179: Currently this only prints information to a file (or stdout) about the
180: symmetry of the problem. If your Krylov method has special options or
181: flags that information should be printed here.
183: */
186: PetscErrorCode KSPView_LCD(KSP ksp,PetscViewer viewer)
187: {
189: KSP_LCD *lcd = (KSP_LCD *)ksp->data;
191: PetscTruth iascii;
194: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
195: if (iascii) {
196: PetscViewerASCIIPrintf(viewer," LCD: restart=%d\n",lcd->restart);
197: PetscViewerASCIIPrintf(viewer," LCD: happy breakdown tolerance %g\n",lcd->haptol);
198: } else {
199: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for KSP LCD",((PetscObject)viewer)->type_name);
200: }
201: return(0);
202: }
204: /*
205: KSPSetFromOptions_LCD - Checks the options database for options related to the
206: LCD method.
207: */
210: PetscErrorCode KSPSetFromOptions_LCD(KSP ksp)
211: {
213: PetscTruth flg;
214: KSP_LCD *lcd = (KSP_LCD *)ksp->data;
215:
217: PetscOptionsHead("KSP LCD options");
218: PetscOptionsInt("-ksp_lcd_restart","Number of vectors conjugate","KSPLCDSetRestart",lcd->restart,&lcd->restart,&flg);
219: if(flg && lcd->restart < 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Restart must be positive");
220: PetscOptionsReal("-ksp_lcd_haptol","Tolerance for exact convergence (happy ending)","KSPLCDSetHapTol",lcd->haptol,&lcd->haptol,&flg);
221: if (flg && lcd->haptol < 0.0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Tolerance must be non-negative");
222: return(0);
223: }
228: PetscErrorCode KSPCreate_LCD(KSP ksp)
229: {
231: KSP_LCD *lcd;
234: PetscNew(KSP_LCD,&lcd);
235: PetscMemzero(lcd,sizeof(KSP_LCD));
236: PetscLogObjectMemory(ksp,sizeof(KSP_LCD));
237: ksp->data = (void*)lcd;
238: ksp->pc_side = PC_LEFT;
239: lcd->restart = 30;
240: lcd->haptol = 1.0e-30;
242: /*
243: Sets the functions that are associated with this data structure
244: (in C++ this is the same as defining virtual functions)
245: */
246: ksp->ops->setup = KSPSetUp_LCD;
247: ksp->ops->solve = KSPSolve_LCD;
248: ksp->ops->destroy = KSPDestroy_LCD;
249: ksp->ops->view = KSPView_LCD;
250: ksp->ops->setfromoptions = KSPSetFromOptions_LCD;
251: ksp->ops->buildsolution = KSPDefaultBuildSolution;
252: ksp->ops->buildresidual = KSPDefaultBuildResidual;
254: return(0);
255: }