G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsMinResQLP.hpp
Go to the documentation of this file.
1
14namespace gismo
15{
16
17//A stable way of finding radius, cosinus and sinus (r,c,s) from a and b
18//That is: r = sqrt(a*a + b*b), c = a/r, s= b/r
19//Rewritten from PETSc minres
20template<class T>
21void MinResQLPSymOrtho(T const a, T const b, T &c, T &s, T &r)
22{
23 if (b == 0.0)
24 {
25 if (a == 0.0)
26 c = 1.0;
27 else
28 c = math::getSign(a);
29 s = 0.0;
30 r = math::abs(a);
31 }
32 else if (a == 0.0)
33 {
34 c = 0.0;
35 s = math::getSign(b);
36 r = math::abs(b);
37 }
38 else if (math::abs(b) > math::abs(a))
39 {
40 T t = a / b;
41
42 s = math::getSign(b) / math::sqrt(1.0 + t * t);
43 c = s * t;
44 r = b / s;
45 }
46 else
47 {
48 T t = b / a;
49 c = math::getSign(a) / math::sqrt(1.0 + t * t);
50 s = c * t;
51 r = a / c;
52 }
53}
54
55
56template<class T>
58{
59 m_rhs = rhs;
60 Base::initIteration(rhs,x);
61 index_t n = m_mat->cols();
62 index_t m = 1; // = rhs.cols();
63
64 resvec.setZero(m_max_iters+1,1);
65 Aresvec.setZero(m_max_iters+1,1);
66
67 //r2 = rhs;
68 m_mat->apply(x,r2); //erex
69 xnorm = x.norm();
70 Axnorm = r2.norm();
71 r2 = rhs-r2;
72 //y = x + beta y.
73 //VecAYPX(Vec y, PetscScalar beta, Vec x)
74 r3.setZero(n,m);
75 m_precond->apply(r2, r3);
76 beta1 = r2.col(0).dot(r3.col(0));
77 GISMO_ASSERT(beta1 > 0, "Preconditioner is indefinite");
78 beta1 = math::sqrt(beta1);
79 beta = 0;
80 tau = 0; taul = 0; gmin = 0;
81 phi = beta1; betan = beta1;
82 cs = -1; cr1 = -1; cr2 = -1;
83 sn = 0; sr1 = 0; sr2 = 0;
84 deltan = 0; epsilonn = 0;
85 gamma = 0; gammal = 0; gammal2 = 0;
86 eta = 0; etal = 0; etal2 = 0;
87 vepln = 0; veplnl = 0; veplnl2 = 0; ul3= 0;
88 ul2 = 0; ul = 0; u = 0; rnorm = betan;
89 xl2norm = 0;
90 Anorm = 0; Acond = 1;
91 relres = 1;
92 QLPiter = 0;
93
94 x.setZero(n,m); w.setZero(n,m); wl.setZero(n,m);
95 resvec(0,0) = beta1;
96
97 //NB User input
98 maxxnorm = 1e7;
99
100
101 m_error = r2.norm() / m_rhs_norm;
102 if (m_error < m_tol)
103 return true;
104
105 return false;
106}
107
108template<class T>
110{
111 betal = beta;
112 beta= betan;
113 v = (1.0/beta)*r3;
114 m_mat->apply(v,r3);
115 //Assume that m_num_iter starts at 1 (at this point in the code)
116 //TODO check assumption
117 if (m_num_iter > 1)
118 r3 = r3 - (beta/betal)*r1;
119
120 alpha = T (r3.col(0).dot(v.col(0)));
121 r3 = r3 - (alpha/beta)*r2;
122 r1.swap(r2);
123 r2.swap(r3);
124
125 m_precond->apply(r2,r3);
126 betan = r2.col(0).dot(r3.col(0));
127 GISMO_ASSERT(betan > 0, "Preconditioner is indefinite");
128 betan = math::sqrt(betan);
129
130 //pnorm = rho
131 pnorm = math::sqrt(alpha*alpha + betal*betal + betan*betan);
132
133 dbar = deltan;
134 delta = cs*dbar + sn*alpha;
135 epsilon = epsilonn;
136 gbar = sn*dbar - cs*alpha;
137 epsilonn= sn*betan;
138 deltan = -cs*betan;
139
140 gammal3 = gammal2;
141 gammal2 = gammal;
142 gammal = gamma;
143 MinResQLPSymOrtho(gbar, betan, cs, sn, gamma);
144 //real_t gammaTmp = gamma; used for (normal) minres update
145 taul2 = taul;
146 taul = tau;
147 tau = cs*phi;
148 Axnorm = math::sqrt(Axnorm*Axnorm + tau*tau);
149 phi = sn*phi;
150
151
152 if (m_num_iter > 2)
153 {
154 veplnl2 = veplnl;
155 etal2 = etal;
156 etal = eta;
157 real_t delta_tmp = sr2*vepln - cr2*delta;
158 veplnl = cr2*vepln + sr2*delta;
159 delta = delta_tmp;
160 eta = sr2*gamma;
161 gamma = -cr2*gamma;
162 }
163 if (m_num_iter > 1)
164 {
165 MinResQLPSymOrtho(gammal, delta, cr1, sr1, gammal);
166 vepln = sr1*gamma;
167 gamma = -cr1*gamma;
168 }
169
170
171 real_t ul4 = ul3;
172 ul3 = ul2;
173 if (m_num_iter > 2)
174 {
175 ul2 = (taul2 - etal2*ul4 - veplnl2*ul3) / gammal2;
176 }
177 if (m_num_iter > 1)
178 {
179 ul = ( taul - etal *ul3 - veplnl *ul2) / gammal;
180 }
181 real_t xnorm_tmp = math::sqrt(xl2norm*xl2norm + ul2*ul2 + ul*ul);
182 if ( math::abs(gamma) > std::numeric_limits<real_t>::min() && xnorm_tmp < maxxnorm)
183 {
184 u = (tau - eta*ul2 - vepln*ul) / gamma;
185 if ( math::sqrt(xnorm_tmp*xnorm_tmp + u*u) > maxxnorm)
186 {
187 u = 0; //NB flag = 6 LINE 374
188 }
189 }
190 else
191 {
192 u = 0; //NB flag = 9 LINE 379
193 }
194 xl2norm = math::sqrt(xl2norm*xl2norm + ul2*ul2);
195
196 xnorm = math::sqrt(xl2norm*xl2norm + ul*ul + u*u);
197
198 //MINRES-QLP updates
199 //TODO: add IF/ELSE if we want to integrate
200 // normal MINRES with MINRES-QLP
201 QLPiter += 1;
202 if (QLPiter == 1)
203 {
204 xl2.setZero(m_mat->cols(),1);
205 if (m_num_iter > 1)
206 {
207 if (m_num_iter > 3)
208 {
209 wl2 = gammal3*wl2 + veplnl2*wl + etal*w;
210 }
211 if (m_num_iter > 2)
212 {
213 wl = gammal_QLP*wl + vepln_QLP*w;
214 }
215 w = gamma_QLP*w;
216 xl2 = x - wl*ul_QLP - w*u_QLP;
217 }
218 }
219 if (m_num_iter == 1)
220 {
221 wl2.swap(wl);
222 wl = v*sr1;
223 w = -v*cr1;
224 }
225 else if (m_num_iter ==2)
226 {
227 wl2.swap(wl);
228 wl = w*cr1 + v*sr1;
229 w = w*sr1 - v*cr1;
230 }
231 else
232 {
233 wl2.swap(wl);
234 wl.swap(w);
235 w = wl2*sr2 - v*cr2;
236 wl2 = wl2*cr2 + v*sr2;
237 v = wl *cr1 + w*sr1;
238 w = wl *sr1 - w*cr1;
239 wl.swap(v);
240 }
241 xl2 = xl2 + wl2*ul2;
242 x = xl2 + wl *ul + w*u;
243
244 real_t gammal_tmp = gammal;
245 MinResQLPSymOrtho(gammal, epsilonn, cr2, sr2, gammal);
246
247 gammal_QLP = gammal_tmp;
248 vepln_QLP = vepln;
249 gamma_QLP = gamma;
250 ul_QLP = ul;
251 u_QLP = u;
252
253 abs_gamma = math::abs(gamma);
254
255 real_t tmp_max = std::max(gammal, abs_gamma);
256 Anorm = std::max(Anorm, pnorm);
257 Anorm = std::max(Anorm, tmp_max);
258 if (m_num_iter == 1)
259 {
260 gmin = gamma;
261 gminl = gmin;
262 }
263 else if (m_num_iter > 1)
264 {
265 gminl2 = gminl;
266 gminl = gmin;
267
268 gmin = std::min(gminl2, gammal);
269 gmin = std::min(gmin, abs_gamma);
270 }
271
272
273 Acond = Anorm/gmin;
274 rnorml = rnorm;
275 if (phi != 0.0) //LINE 441
276 rnorm = phi; //NB if flag != 9;
277 relres = rnorm / (Anorm*xnorm + beta1);
278 rootl = math::sqrt(gbar*gbar + deltan*deltan);
279 Arnorml = rnorml*rootl;
280 relAresl = rootl / Anorm;
281
282
283 // Test for convergence
284 if (m_inexact_residual)
285 {
286 m_error = relres;
287 }
288 else
289 {
290 m_mat->apply(x,negResidual);
291 gsMatrix<T> r1_tmp = m_rhs - negResidual;
292 m_error = r1_tmp.norm()/m_rhs_norm;
293 }
294 if (m_error < m_tol)
295 return true;
296
297
298 resvec(m_num_iter, 0) = rnorm;
299 Aresvec(m_num_iter-1, 0) = Arnorml;
300
301 return false;
302
303}
304
305template<class T>
307{
308 m_mat->apply(x,negResidual);
309 r1 = m_rhs - negResidual;
310 rnorm = r1.norm();
311 m_mat->apply(r1, negResidual);
312 Arnorm = negResidual.norm();
313 xnorm = x.norm();
314 relres = rnorm/(Anorm*xnorm + beta1);
315 m_error = relres;
316 relAres = 0;
317 if(rnorm > std::numeric_limits<real_t>::min())
318 {
319 relAres = Arnorm / (Anorm*rnorm);
320 }
321 Aresvec(m_num_iter, 0) = Arnorm;
322 Aresvec.conservativeResize(m_num_iter+1,1);
323 resvec.conservativeResize(m_num_iter+1,1);
324 r1.clear(); r2.clear(); r3.clear();
325
326 negResidual.clear(); v.clear();
327 xl2.clear();
328 wl.clear(); w.clear();
329 wl2.clear();
330}
331
332
333}
void finalizeIteration(VectorType &x)
Some post-processing might be required.
Definition gsMinResQLP.hpp:306
bool step(VectorType &x)
Perform one step, requires initIteration.
Definition gsMinResQLP.hpp:109
bool initIteration(const VectorType &rhs, VectorType &x)
Init the iteration.
Definition gsMinResQLP.hpp:57
#define index_t
Definition gsConfig.h:32
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
int getSign(T val)
Returns the sign of val.
Definition gsMath.h:325
The G+Smo namespace, containing all definitions for the library.