Nektar++
Loading...
Searching...
No Matches
NekLinSysIterGMRES.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: NekLinSysIterGMRES.cpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10// Department of Aeronautics, Imperial College London (UK), and Scientific
11// Computing and Imaging Institute, University of Utah (USA).
12//
13// License for the specific language governing rights and limitations under
14// Permission is hereby granted, free of charge, to any person obtaining a
15// copy of this software and associated documentation files (the "Software"),
16// to deal in the Software without restriction, including without limitation
17// the rights to use, copy, modify, merge, publish, distribute, sublicense,
18// and/or sell copies of the Software, and to permit persons to whom the
19// Software is furnished to do so, subject to the following conditions:
20//
21// The above copyright notice and this permission notice shall be included
22// in all copies or substantial portions of the Software.
23//
24// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30// DEALINGS IN THE SOFTWARE.
31//
32// Description: NekLinSysIterGMRES definition
33//
34///////////////////////////////////////////////////////////////////////////////
35
38
39using namespace std;
40
42{
43/**
44 * @class NekLinSysIterGMRES
45 *
46 * Solves a linear system using iterative methods.
47 */
50 "GMRES", NekLinSysIterGMRES::create, "NekLinSysIterGMRES solver.");
51
54 const LibUtilities::CommSharedPtr &vRowComm, const int nDimen,
55 const NekSysKey &pKey)
56 : NekLinSysIter(pSession, vRowComm, nDimen, pKey)
57{
60
62
66
68
69 // LGMRES parameter
70 // Reference:
71 // Baker, Allison H., Elizabeth R. Jessup, and Thomas Manteuffel. "A
72 // technique for accelerating the convergence of restarted GMRES." SIAM
73 // Journal on Matrix Analysis and Applications 26, no. 4 (2005):
74 // 962-984.
75 m_GMRESDeltaDirection = pSession->DefinesParameter("GMRESDeltaDirection")
76 ? pSession->GetParameter("GMRESDeltaDirection")
77 : 0;
78
79 m_flexible = pSession->DefinesParameter("FlexibleGMRES")
80 ? pSession->GetParameter("FlexibleGMRES")
81 : false;
82
83 // Allocate array storage of coefficients
84 // Hessenburg matrix
86 for (size_t nd = 0; nd < m_LinSysMaxStorage; nd++)
87 {
89 }
90 // Hesseburg matrix after rotation
92 for (size_t nd = 0; nd < m_LinSysMaxStorage; nd++)
93 {
95 }
96 // Total search directions
99}
100
105
106/**
107 *
108 */
110 const int nGlobal, const Array<OneD, const NekDouble> &pInput,
111 Array<OneD, NekDouble> &pOutput, const int nDir)
112{
113 int niterations = DoGMRES(nGlobal, pInput, pOutput, nDir);
114
115 return niterations;
116}
117
118void NekLinSysIterGMRES::v_DoIterate(const int nGlobal,
119 const Array<OneD, NekDouble> &rhs,
120 Array<OneD, NekDouble> &x, const int nDir,
121 NekDouble &err, int &iter)
122{
123 iter = DoGMRES(nGlobal, rhs, x, nDir);
124 err = m_finalError;
125}
126
127/**  
128 * Solve a global linear system using the Gmres 
129 * We solve only for the non-Dirichlet modes. The operator is evaluated  
130 * using an auxiliary function v_DoMatrixMultiply defined by the  
131 * specific solver. Distributed math routines are used to support  
132 * parallel execution of the solver.  
133 *  
134 * @param pInput Input residual of all DOFs.  
135 * @param pOutput Solution vector of all DOFs.  
136 */
137
138int NekLinSysIterGMRES::DoGMRES(const int nGlobal,
139 const Array<OneD, const NekDouble> &pInput,
140 Array<OneD, NekDouble> &pOutput, const int nDir)
141{
144 {
145 Set_Rhs_Magnitude(pInput);
146 }
147
148 // Get vector sizes
149 int nNonDir = nGlobal - nDir;
150 NekDouble eps = 0.0;
151
153
154 // zero homogeneous out array ready for solution updates
155 // Should not be earlier in case input vector is same as
156 // output and above copy has been peformed
157 Vmath::Zero(nNonDir, tmp = pOutput + nDir, 1);
158
160 m_converged = false;
161
162 bool truncted = false;
163
165 {
166 truncted = true;
167 }
168
169 for (int nrestart = 0; nrestart < m_maxrestart; ++nrestart)
170 {
171 eps =
172 DoGmresRestart(nrestart, truncted, nGlobal, pInput, pOutput, nDir);
173
174 if (m_converged)
175 {
176 break;
177 }
178 }
179
180 // Verbose print error, iteration count, tolerance, ..
181 if (m_verbose)
182 {
183 // Compute "real eps" based on solution x as r = Ax - b
184 Array<OneD, NekDouble> r0(nGlobal, 0.0);
186 Vmath::Vsub(nNonDir, &pInput[0] + nDir, 1, &r0[0] + nDir, 1,
187 &r0[0] + nDir, 1);
188 NekDouble vExchange = Vmath::Dot2(nNonDir, &r0[0] + nDir, &r0[0] + nDir,
189 &m_map[0] + nDir);
190 m_rowComm->AllReduce(vExchange, LibUtilities::ReduceSum);
191 NekDouble eps1 = vExchange;
192
193 if (m_root)
194 {
195 cout << "GMRES iterations made = " << m_totalIterations
196 << " using tolerance of " << m_NekLinSysTolerance
197 << " (error = " << m_finalError
198 << ", rhs_mag = " << sqrt(m_rhs_magnitude)
199 << " with (GMRES eps = " << eps << " REAL eps= " << eps1
200 << ")";
201
202 // Append appropriate message when finalising GMRES
203 if (m_converged)
204 {
205 cout << " CONVERGED" << endl;
206 }
207 else
208 {
209 cout << " WARNING: Exceeded maxIt" << endl;
210 }
211 }
212 }
213
214 if (m_FlagWarnings)
215 {
216 WARNINGL1(m_converged, "GMRES did not converge.");
217 }
218 return m_totalIterations;
219}
220
222 const unsigned int nrestart, const bool truncted, const int nGlobal,
224 const int nDir)
225{
226 // Hookstep data exposure
227 m_HookData.valid = false;
228
229 int nNonDir = nGlobal - nDir;
230
231 // Allocate array storage of coefficients
232 // Residual
234 // Givens rotation c
236 // Givens rotation s
238 // Total coefficients, just for check
240 // Search direction order
244 // Temporary variables
245 int idtem;
246 int starttem;
247 int endtem;
248
249 NekDouble eps;
250 NekDouble beta, alpha;
251 NekDouble vExchange = 0;
252 // Temporary Array
253 Array<OneD, NekDouble> w(nGlobal, 0.0);
254 Array<OneD, NekDouble> wk(nGlobal, 0.0);
255 Array<OneD, NekDouble> r0(nGlobal, 0.0);
262
263 if (nrestart)
264 {
265 // This is A*x
267
268 // The first search direction
269 beta = -1.0;
270
271 // This is r0 = b-A*x
272 Vmath::Svtvp(nNonDir, beta, &r0[0] + nDir, 1, &pInput[0] + nDir, 1,
273 &r0[0] + nDir, 1);
274 }
275 else
276 {
277 // This is r0 = b, x = x0 assumed to be zero
278 Vmath::Vcopy(nNonDir, &pInput[0] + nDir, 1, &r0[0] + nDir, 1);
279 }
280
282 {
283 m_operator.DoNekSysPrecon(r0 + nDir, tmp = r0 + nDir);
284 }
285
286 // Norm of (r0)
287 // The m_map tells how to connect
288 vExchange =
289 Vmath::Dot2(nNonDir, &r0[0] + nDir, &r0[0] + nDir, &m_map[0] + nDir);
290 m_rowComm->AllReduce(vExchange, LibUtilities::ReduceSum);
291 eps = vExchange;
292
293 // Detect zero input array
294 // Causes Arnoldi to breakdown, hence stop here
296 {
297 m_converged = true;
299 {
300 m_prec_factor = 1.0;
301 }
302 return eps;
303 }
304
305 if (!nrestart)
306 {
309 {
310 // Evaluate initial residual error for exit check
311 vExchange = Vmath::Dot2(nNonDir, &pInput[0] + nDir,
312 &pInput[0] + nDir, &m_map[0] + nDir);
313 m_rowComm->AllReduce(vExchange, LibUtilities::ReduceSum);
314 m_prec_factor = vExchange / eps;
315 }
316 else
317 {
318 m_prec_factor = 1.0;
319 }
320 }
321
322 Vmath::Smul(nNonDir, sqrt(m_prec_factor), r0 + nDir, 1, tmp = r0 + nDir, 1);
323 eps = eps * m_prec_factor;
324 eta[0] = sqrt(eps);
325 NekDouble beta0 = eta[0]; // Hookstep export data before change
326
327 // Give an order for the entries in Hessenburg matrix
328 for (int nd = 0; nd < m_LinSysMaxStorage; ++nd)
329 {
330 id[nd] = nd;
331 id_end[nd] = nd + 1;
332 starttem = id_end[nd] - m_KrylovMaxHessMatBand;
333 if (truncted && (starttem) > 0)
334 {
335 id_start[nd] = starttem;
336 }
337 else
338 {
339 id_start[nd] = 0;
340 }
341 }
342
343 // Normlized by r0 norm V(:,1)=r0/norm(r0)
344 alpha = 1.0 / eta[0];
345
346 // Scalar multiplication
347 if (m_V_total[0].size() == 0)
348 {
349 m_V_total[0] = Array<OneD, NekDouble>(nGlobal, 0.0);
350 m_Z_total[0] = Array<OneD, NekDouble>(nGlobal, 0.0);
351 // Set storage of LGMRES
352 for (unsigned int dir = 0; dir < m_GMRESDeltaDirection; dir++)
353 {
354 m_delta.push_back(Array<OneD, NekDouble>(nGlobal, 0.0));
355 }
356 }
357 Vmath::Smul(nNonDir, alpha, &r0[0] + nDir, 1, &m_V_total[0][0] + nDir, 1);
358
359 // Restarted Gmres(m) process
360 int nswp = 0;
361 for (int nd = 0; nd < m_LinSysMaxStorage; ++nd)
362 {
363 if (m_V_total[nd + 1].size() == 0)
364 {
365 m_V_total[nd + 1] = Array<OneD, NekDouble>(nGlobal, 0.0);
366 if (m_flexible)
367 {
368 m_Z_total[nd + 1] = Array<OneD, NekDouble>(nGlobal, 0.0);
369 }
370 }
371 Vmath::Zero(nGlobal, m_V_total[nd + 1], 1);
373
374 // For LGMRES use m_delta for the last m_GMRESDeltaDirection
375 // iterations.
376 bool cond = nd >= (m_LinSysMaxStorage - m_GMRESDeltaDirection) &&
377 nrestart >= m_GMRESDeltaDirection;
378 unsigned int index = nd - (m_LinSysMaxStorage - m_GMRESDeltaDirection);
379 auto &V1 = (cond) ? m_delta[index] : m_V_total[nd];
380 auto &Z1 =
381 (m_NekLinSysRightPrecon) ? m_Z_total[(m_flexible) ? nd : 0] : V1;
382 V2 = m_V_total[nd + 1];
383 h1 = m_hes[nd];
384
386 {
387 m_operator.DoNekSysPrecon(V1 + nDir, tmp = Z1 + nDir);
388 }
389
390 // w here is no need to add nDir due to temporary Array
391 idtem = id[nd];
392 starttem = id_start[idtem];
393 endtem = id_end[idtem];
394
395 DoArnoldi(starttem, endtem, nGlobal, nDir, w, Z1, V2, h1);
396
397 if (starttem > 0)
398 {
399 starttem = starttem - 1;
400 }
401
402 h2 = m_Upper[nd];
403 Vmath::Vcopy(m_LinSysMaxStorage + 1, &h1[0], 1, &h2[0], 1);
404 DoGivensRotation(starttem, endtem, cs, sn, h2, eta);
405
406 eps = eta[nd + 1] * eta[nd + 1];
407
408 // This Gmres merge truncted Gmres to accelerate.
409 // If truncted, cannot jump out because
410 // the last term of eta is not residual
411 if ((!truncted) || (nd < m_KrylovMaxHessMatBand))
412 {
415 nd > 0)
416 {
417 m_converged = true;
418 }
419 }
420
421 nswp++;
423
424 if (m_converged)
425 {
426 break;
427 }
428 }
429
430 DoBackward(nswp, m_Upper, eta, y_total);
431
432 // Hookstep data exposure
434 {
435 m_HookData.valid = true;
436 m_HookData.nswp = nswp;
437 m_HookData.nGlobal = nGlobal;
438 m_HookData.nDir = nDir;
439 m_HookData.beta = beta0;
440
442 for (int i = 0; i < nswp + 1; ++i)
443 {
444 m_HookData.V[i] = Array<OneD, NekDouble>(nGlobal, 0.0);
445 Vmath::Vcopy(nGlobal, m_V_total[i], 1, m_HookData.V[i], 1);
446 }
447
449 for (int i = 0; i < nswp; ++i)
450 {
451 m_HookData.H[i] = Array<OneD, NekDouble>(nswp + 1, 0.0);
452 Vmath::Vcopy(nswp + 1, m_hes[i], 1, m_HookData.H[i], 1);
453 }
454
456 Vmath::Vcopy(nswp, y_total, 1, m_HookData.yNewton, 1);
457 }
458 // Hookstep stuf ends here
459
460 // Calculate output V_total * y_total or Z_total * y_total (flexible).
461 auto &Z_total = (m_flexible) ? m_Z_total : m_V_total;
462 Array<OneD, NekDouble> solution(nNonDir, 0.0);
463 for (int i = 0; i < nswp; ++i)
464 {
465 // For LGMRES use m_delta for the last m_GMRESDeltaDirection
466 // iterations.
467 bool cond = i >= (m_LinSysMaxStorage - m_GMRESDeltaDirection) &&
468 nrestart >= m_GMRESDeltaDirection;
469 if (cond)
470 {
471 unsigned int index =
473 Vmath::Svtvp(nNonDir, y_total[i], &m_delta[index][0] + nDir, 1,
474 solution.data(), 1, solution.data(), 1);
475 }
476 else
477 {
478 Vmath::Svtvp(nNonDir, y_total[i], &Z_total[i][0] + nDir, 1,
479 solution.data(), 1, solution.data(), 1);
480 }
481 }
482
483 // Store last m_GMRESDeltaDirection delta for LGMRES.
485 {
486 auto last = std::move(m_delta.back());
487 Vmath::Vcopy(nNonDir, solution.data(), 1, &last[0] + nDir, 1);
488 m_delta.pop_back();
489 m_delta.push_front(std::move(last));
490 }
491
493 {
494 m_operator.DoNekSysPrecon(solution, solution);
495 }
496
497 // Update output.
498 Vmath::Vadd(nNonDir, solution.data(), 1, &pOutput[0] + nDir, 1,
499 &pOutput[0] + nDir, 1);
500
501 return eps;
502}
503
504// Arnoldi Subroutine
505void NekLinSysIterGMRES::DoArnoldi(const int starttem, const int endtem,
506 const int nGlobal, const int nDir,
511{
512 NekDouble alpha, beta, vExchange = 0.0;
514 int nNonDir = nGlobal - nDir;
516 timer.Start();
518 timer.Stop();
519 timer.AccumulateRegion("NekSysOperators::DoNekSysLhsEval", 10);
520
522 {
523 m_operator.DoNekSysPrecon(w + nDir, tmp = w + nDir);
524 }
525
526 Vmath::Smul(nNonDir, sqrt(m_prec_factor), w + nDir, 1, tmp = w + nDir, 1);
527
528 // Modified Gram-Schmidt
529 for (int i = starttem; i < endtem; ++i)
530 {
531 vExchange = Vmath::Dot2(nNonDir, &w[0] + nDir, &m_V_total[i][0] + nDir,
532 &m_map[0] + nDir);
533 m_rowComm->AllReduce(vExchange, LibUtilities::ReduceSum);
534
535 h[i] = vExchange;
536
537 beta = -1.0 * vExchange;
538 Vmath::Svtvp(nNonDir, beta, &m_V_total[i][0] + nDir, 1, &w[0] + nDir, 1,
539 &w[0] + nDir, 1);
540 }
541 // end of Modified Gram-Schmidt
542
543 // calculate the L2 norm and normalize
544 vExchange =
545 Vmath::Dot2(nNonDir, &w[0] + nDir, &w[0] + nDir, &m_map[0] + nDir);
546 m_rowComm->AllReduce(vExchange, LibUtilities::ReduceSum);
547
548 h[endtem] = sqrt(vExchange);
549
550 alpha = 1.0 / h[endtem];
551 Vmath::Smul(nNonDir, alpha, &w[0] + nDir, 1, &V2[0] + nDir, 1);
552}
553
554// QR factorization through Givens rotation
555void NekLinSysIterGMRES::DoGivensRotation(const int starttem, const int endtem,
560{
561 NekDouble dbl;
562 NekDouble dd;
563 NekDouble hh;
564 int idtem = endtem - 1;
565 // The starttem and endtem are beginning and ending order of Givens rotation
566 // They usually equal to the beginning position and ending position of
567 // Hessenburg matrix But sometimes starttem will change, like if it is
568 // initial 0 and becomes nonzero because previous Givens rotation See Yu
569 // Pan's User Guide
570 for (int i = starttem; i < idtem; ++i)
571 {
572 dbl = c[i] * h[i] - s[i] * h[i + 1];
573 h[i + 1] = s[i] * h[i] + c[i] * h[i + 1];
574 h[i] = dbl;
575 }
576 dd = h[idtem];
577 hh = h[endtem];
578 if (hh == 0.0)
579 {
580 c[idtem] = 1.0;
581 s[idtem] = 0.0;
582 }
583 else if (abs(hh) > abs(dd))
584 {
585 dbl = -dd / hh;
586 s[idtem] = 1.0 / sqrt(1.0 + dbl * dbl);
587 c[idtem] = dbl * s[idtem];
588 }
589 else
590 {
591 dbl = -hh / dd;
592 c[idtem] = 1.0 / sqrt(1.0 + dbl * dbl);
593 s[idtem] = dbl * c[idtem];
594 }
595
596 h[idtem] = c[idtem] * h[idtem] - s[idtem] * h[endtem];
597 h[endtem] = 0.0;
598
599 dbl = c[idtem] * eta[idtem] - s[idtem] * eta[endtem];
600 eta[endtem] = s[idtem] * eta[idtem] + c[idtem] * eta[endtem];
601 eta[idtem] = dbl;
602}
603
604// Backward calculation
605// To notice, Hesssenburg matrix's column
606// and row changes due to use Array<OneD,Array<OneD,NekDouble>>
607void NekLinSysIterGMRES::DoBackward(const int number,
611{
612 // Number is the entry number
613 // but C++'s order need to be one smaller
614 int maxid = number - 1;
615 NekDouble sum;
616 y[maxid] = b[maxid] / A[maxid][maxid];
617 for (int i = maxid - 1; i > -1; --i)
618 {
619 sum = b[i];
620 for (int j = i + 1; j < number; ++j)
621 {
622 // i and j changes due to use Array<OneD,Array<OneD,NekDouble>>
623 sum -= y[j] * A[j][i];
624 }
625 y[i] = sum / A[i][i];
626 }
627}
628} // namespace Nektar::LibUtilities
#define WARNINGL1(condition, msg)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
int v_SolveSystem(const int nGlobal, const Array< OneD, const NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const int nDir) override
void DoGivensRotation(const int starttem, const int endtem, Array< OneD, NekDouble > &c, Array< OneD, NekDouble > &s, Array< OneD, NekDouble > &h, Array< OneD, NekDouble > &eta)
NekLinSysIterGMRES(const LibUtilities::SessionReaderSharedPtr &pSession, const LibUtilities::CommSharedPtr &vRowComm, const int nDimen, const NekSysKey &pKey=NekSysKey())
Array< OneD, Array< OneD, NekDouble > > m_Z_total
int DoGMRES(const int pNumRows, const Array< OneD, const NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const int pNumDir)
Actual iterative solve-GMRES.
NekDouble DoGmresRestart(const unsigned int nrestart, const bool truncted, const int nGlobal, const Array< OneD, const NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const int nDir)
Actual iterative gmres solver for one restart.
void DoBackward(const int number, Array< OneD, Array< OneD, NekDouble > > &A, const Array< OneD, const NekDouble > &b, Array< OneD, NekDouble > &y)
Array< OneD, Array< OneD, NekDouble > > m_V_total
Array< OneD, Array< OneD, NekDouble > > m_Upper
Array< OneD, Array< OneD, NekDouble > > m_hes
void DoArnoldi(const int starttem, const int endtem, const int nGlobal, const int nDir, Array< OneD, NekDouble > &w, Array< OneD, NekDouble > &V1, Array< OneD, NekDouble > &V2, Array< OneD, NekDouble > &h)
static NekLinSysIterSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const LibUtilities::CommSharedPtr &vRowComm, const int nDimen, const NekSysKey &pKey)
void v_DoIterate(const int nGlobal, const Array< OneD, NekDouble > &rhs, Array< OneD, NekDouble > &x, const int nDir, NekDouble &err, int &iter) override
std::deque< Array< OneD, NekDouble > > m_delta
void Set_Rhs_Magnitude(const Array< OneD, NekDouble > &pIn)
Array< OneD, int > m_map
Global to universal unique map.
LibUtilities::CommSharedPtr m_rowComm
Definition NekSys.h:299
NekSysOperators m_operator
Definition NekSys.h:306
void DoNekSysPrecon(InArrayType &inarray, OutArrayType &outarray, const bool &flag=false) const
Definition NekSys.h:155
void DoNekSysLhsEval(InArrayType &inarray, OutArrayType &outarray, const bool &flag=false) const
Definition NekSys.h:148
void AccumulateRegion(std::string, int iolevel=0)
Accumulate elapsed time for a region.
Definition Timer.cpp:70
std::shared_ptr< SessionReader > SessionReaderSharedPtr
NekLinSysIterFactory & GetNekLinSysIterFactory()
@ beta
Gauss Radau pinned at x=-1,.
Definition PointsType.h:59
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition Comm.h:55
static const NekDouble kNekUnsetDouble
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Svtvp (scalar times vector plus vector): z = alpha*x + y.
Definition Vmath.hpp:396
T Dot2(int n, const T *w, const T *x, const int *y)
dot product
Definition Vmath.hpp:790
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition Vmath.hpp:180
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition Vmath.hpp:100
void Zero(int n, T *x, const int incx)
Zero vector.
Definition Vmath.hpp:273
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition Vmath.hpp:220
STL namespace.
scalarT< T > abs(scalarT< T > in)
Definition scalar.hpp:295
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290
NekDouble beta
Initial residual norm beta used in || beta e_1 - H y ||_2.
Array< OneD, Array< OneD, NekDouble > > V
Arnoldi basis vectors V_0,...,V_m; contains nswp + 1 vectors of length nGlobal.
Array< OneD, Array< OneD, NekDouble > > H
Arnoldi Hessenberg matrix stored by columns: H[col][row]. H size is (nswp + 1) x nswp.
Array< OneD, NekDouble > yNewton
Unconstrained reduced GMRES solution y of size nswp.
int nGlobal
Dimension of the system; length of each Krylov vector.
int nDir
Offset to the non-Dirichlet part of the vector; active size is nGlobal - nDir.
int nswp
Current Krylov subspace dimension, number of done Arnoldi sweeps.