Nektar++
DriverArpack.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: DriverArpack.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// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description: Arnoldi solver using Arpack
32//
33///////////////////////////////////////////////////////////////////////////////
34
36
37using namespace std;
38
39namespace Nektar
40{
41namespace SolverUtils
42{
43
46 "LargestReal", 0),
48 "SmallestReal", 1),
50 "LargestImag", 2),
52 "SmallestImag", 3),
54 "LargestMag", 4),
56 "SmallestMag", 5),
57};
60 "LargestMag");
63
64std::string DriverArpack::className =
66
67std::string DriverArpack::ArpackProblemTypeTrans[6] = {"LR", "SR", "LI",
68 "SI", "LM", "SM"};
69
70/**
71 *
72 */
75 : DriverArnoldi(pSession, pGraph)
76{
77}
78
79/**
80 *
81 */
83{
85
86 // Initialisation of Arnoldi parameters
87 m_maxn = 1000000; // Maximum size of the problem
88 m_maxnev = 200; // maximum number of eigenvalues requested
89 m_maxncv = 500; // Largest number of basis vector used in Implicitly
90 // Restarted Arnoldi
91
92 // Error alerts
93 ASSERTL0(m_nvec <= m_maxnev, "NEV is greater than MAXNEV");
94 ASSERTL0(m_kdim <= m_maxncv, "NEV is greater than MAXNEV");
95 ASSERTL0(2 <= m_kdim - m_nvec, "NCV-NEV is less than 2");
96
97 ASSERTL0(m_comm->GetSize() == 1,
98 "..ARPACK is not currently set-up for parallel execution...\n");
99
100 m_equ[0]->PrintSummary(out);
101
102 // Print session parameters
103 out << "\tArnoldi solver type : Arpack" << endl;
104 out << "\tArpack problem type : ";
105 out << ArpackProblemTypeTrans[m_session->GetSolverInfoAsEnum<int>(
106 "ArpackProblemType")]
107 << endl;
109
110 // Initialization
111 for (int i = 0; i < m_nequ; ++i)
112 {
113 m_equ[i]->DoInitialise();
114 }
115
116 // FwdTrans Initial conditions to be in Coefficient Space
117 m_equ[m_nequ - 1]->TransPhysToCoeff();
118}
119
120/**
121 *
122 */
123void DriverArpack::v_Execute(ostream &out)
124
125{
126 Array<OneD, NekDouble> tmpworkd;
127
128 int nq = m_equ[0]
129 ->UpdateFields()[0]
130 ->GetNcoeffs(); // Number of points in the mesh
131 int n = m_nfields * nq; // Number of points in eigenvalue calculation
132 int lworkl = 3 * m_kdim * (m_kdim + 2); // Size of work array
133 int ido; // REVERSE COMMUNICATION parameter. At the first call must be
134 // initialised at 0
135 int info; // do not set initial vector (info=0 random initial vector, info=1
136 // read initial vector from session file)
137
138 int iparam[11];
139 int ipntr[14];
140
141 Array<OneD, int> ritzSelect;
146 NekDouble sigmar, sigmai;
147
148 Array<OneD, NekDouble> resid(n);
150 Array<OneD, NekDouble> workl(lworkl, 0.0);
151 Array<OneD, NekDouble> workd(3 * n, 0.0);
152
153 ASSERTL0(n <= m_maxn, "N is greater than MAXN");
154
155 if (m_session->DefinesFunction("InitialConditions"))
156 {
157 out << "\tInital vector : input file " << endl;
158 info = 1;
160 }
161 else
162 {
163 out << "\tInital vector : random " << endl;
164 info = 0;
165 }
166
167 char B;
168
169 iparam[0] = 1; // strategy for shift-invert
170 iparam[1] = 0; // (deprecated)
171 iparam[2] = m_nits; // maximum number of iterations allowed/taken
172 iparam[3] = 1; // blocksize to be used for recurrence
173 iparam[4] = 0; // number of converged ritz eigenvalues
174 iparam[5] = 0; // (deprecated)
175
176 // Use generalized B matrix for coupled solver.
178 {
179 iparam[6] = 1; // computation mode 1=> matrix-vector prod
180 B = 'I';
181 }
182 else
183 {
184 iparam[6] = 3; // computation mode 1=> matrix-vector prod
185 B = 'G';
186 }
187#if 0
188 if((fabs(m_realShift) > NekConstants::kNekZeroTol)|| // use shift if m_realShift > 1e-12
190 {
191 iparam[6] = 3; // This was 3 need to know what to set it to
192 B = 'G';
193 }
194 else
195 {
196 iparam[6] = 1; // computation mode 1=> matrix-vector prod
197 B = 'I';
198 }
199#endif
200 iparam[7] = 0; // (for shift-invert)
201 iparam[8] = 0; // number of MV operations
202 iparam[9] = 0; // number of BV operations
203 iparam[10] = 0; // number of reorthogonalisation steps
204
205 int cycle = 0;
206 const char *problem =
207 ArpackProblemTypeTrans[m_session->GetSolverInfoAsEnum<int>(
208 "ArpackProblemType")]
209 .c_str();
210
211 std::string name = m_session->GetSessionName() + ".evl";
212 ofstream pFile(name.c_str());
213
214 ido = 0; // At the first call must be initialisedat 0
215
216 while (ido != 99) // ido==-1 || ido==1 || ido==0)
217 {
218 // Routine for eigenvalue evaluation for non-symmetric operators
219 Arpack::Dnaupd(ido, &B, // B='I' for std eval problem
220 n, problem, m_nvec, m_evtol, &resid[0], m_kdim, &v[0], n,
221 iparam, ipntr, &workd[0], &workl[0], lworkl, info);
222
223 // Plotting of real and imaginary part of the
224 // eigenvalues from workl
225 out << "\rIteration " << cycle << ", output: " << info
226 << ", ido=" << ido << " " << std::flush;
227
228 if (!((cycle - 1) % m_kdim) && (cycle > m_kdim) && (ido != 2))
229 {
230 pFile << "Krylov spectrum at iteration: " << cycle << endl;
231
233 {
234 pFile << "EV Magnitude Angle Growth Frequency "
235 "Residual"
236 << endl;
237 }
238 else
239 {
240 pFile << "EV Real Imaginary inverse real inverse "
241 "imag Residual"
242 << endl;
243 }
244
245 out << endl;
246 for (int k = 0; k < m_kdim; ++k)
247 {
248 // write m_kdim eigs to screen
249 WriteEvs(pFile, k, workl[ipntr[5] - 1 + k],
250 workl[ipntr[6] - 1 + k]);
251 }
252 }
253
254 if (ido == 99)
255 break;
256
257 switch (ido)
258 {
259 case -1:
260 case 1: // Note that ido=1 we are using input x
261 // (workd[inptr[0]-1]) rather than Mx as
262 // recommended in manual since it is not
263 // possible to impose forcing directly.
264 CopyArnoldiArrayToField(tmpworkd = workd + (ipntr[0] - 1));
265
266 m_equ[0]->TransCoeffToPhys();
267
268 m_equ[0]->DoSolve();
270 {
271 // start Adjoint with latest fields of direct
272 CopyFwdToAdj();
273
274 m_equ[1]->TransCoeffToPhys();
275 m_equ[1]->DoSolve();
276 }
277
278 if (!(cycle % m_infosteps))
279 {
280 out << endl;
281 m_equ[0]->Output();
282 }
283
284 // operated fields are copied into workd[inptr[1]-1]
285 CopyFieldToArnoldiArray(tmpworkd = workd + (ipntr[1] - 1));
286
287 cycle++;
288 break;
289 case 2: // provide y = M x (bwd trans and iproduct);
290 {
291 // workd[inptr[0]-1] copied into operator fields
292 CopyArnoldiArrayToField(tmpworkd = workd + (ipntr[0] - 1));
293
294 m_equ[0]->TransCoeffToPhys();
295
297 m_equ[0]->UpdateFields();
298 for (int i = 0; i < fields.size(); ++i)
299 {
300 fields[i]->IProductWRTBase(fields[i]->GetPhys(),
301 fields[i]->UpdateCoeffs());
302 }
303
304 // operated fields are copied into workd[inptr[1]-1]
305 CopyFieldToArnoldiArray(tmpworkd = workd + (ipntr[1] - 1));
306 break;
307 }
308 default:
309 ASSERTL0(false, "Unexpected reverse communication request.");
310 }
311 }
312
313 out << endl << "Converged in " << iparam[8] << " iterations" << endl;
314
315 ASSERTL0(info >= 0, " Error with Dnaupd");
316
317 ritzSelect = Array<OneD, int>(m_kdim, 0);
318 dr = Array<OneD, NekDouble>(m_nvec + 1, 0.0);
319 di = Array<OneD, NekDouble>(m_nvec + 1, 0.0);
320 workev = Array<OneD, NekDouble>(3 * m_kdim);
321 z = Array<OneD, NekDouble>(n * (m_nvec + 1));
322
323 if (m_negatedOp)
324 {
325 sigmar = -m_realShift;
326 }
327 else
328 {
329 sigmar = m_realShift;
330 }
331
332 // Do not pass imaginary shift to Arpack since we have not
333 // used a Fortran complex number format and so processing
334 // is mucked up. Need to do some processing afterwards.
335 sigmai = 0;
336
337 // Setting 'A', Ritz vectors are computed. 'S' for Shur vectors
338 Arpack::Dneupd(1, "A", ritzSelect.get(), dr.get(), di.get(), z.get(), n,
339 sigmar, sigmai, workev.get(), &B, n, problem, m_nvec,
340 m_evtol, resid.get(), m_kdim, v.get(), n, iparam, ipntr,
341 workd.get(), workl.get(), lworkl, info);
342
343 ASSERTL0(info == 0, " Error with Dneupd");
344
345 int nconv = iparam[4];
346
347 // Subtract off complex shift if it exists
348 if (m_negatedOp)
349 {
350 Vmath::Sadd(nconv, m_imagShift, di, 1, di, 1);
351 }
352 else
353 {
354 Vmath::Sadd(nconv, -m_imagShift, di, 1, di, 1);
355 }
356
357 WARNINGL0(m_imagShift == 0, "Complex Shift applied. "
358 "Need to implement Ritz re-evaluation of"
359 "eigenvalue. Only one half of complex "
360 "value will be correct");
361
363 m_equ[0]->UpdateFields();
364
365 out << "Converged Eigenvalues: " << nconv << endl;
366 pFile << "Converged Eigenvalues: " << nconv << endl;
367
369 {
370 out << " Magnitude Angle Growth Frequency" << endl;
371 pFile << " Magnitude Angle Growth Frequency"
372 << endl;
373 for (int i = 0; i < nconv; ++i)
374 {
375 WriteEvs(out, i, dr[i], di[i]);
376 WriteEvs(pFile, i, dr[i], di[i]);
377
378 std::string file = m_session->GetSessionName() + "_eig_" +
379 boost::lexical_cast<std::string>(i) + ".fld";
380 WriteFld(file, z + i * n);
381 }
382 }
383 else
384 {
385 out << " Real Imaginary " << endl;
386 pFile << " Real Imaginary " << endl;
387 for (int i = 0; i < nconv; ++i)
388 {
389 WriteEvs(out, i, dr[i], di[i], NekConstants::kNekUnsetDouble,
390 false);
391 WriteEvs(pFile, i, dr[i], di[i], NekConstants::kNekUnsetDouble,
392 false);
393
394 std::string file = m_session->GetSessionName() + "_eig_" +
395 boost::lexical_cast<std::string>(i) + ".fld";
396 WriteFld(file, z + i * n);
397 }
398 }
399
400 m_real_evl = dr;
401 m_imag_evl = di;
402
403 pFile.close();
404
405 for (int j = 0; j < m_equ[0]->GetNvariables(); ++j)
406 {
407 NekDouble vL2Error = m_equ[0]->L2Error(j, false);
408 NekDouble vLinfError = m_equ[0]->LinfError(j);
409 if (m_comm->GetRank() == 0)
410 {
411 out << "L 2 error (variable " << m_equ[0]->GetVariable(j)
412 << ") : " << vL2Error << endl;
413 out << "L inf error (variable " << m_equ[0]->GetVariable(j)
414 << ") : " << vLinfError << endl;
415 }
416 }
417}
418
419} // namespace SolverUtils
420} // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define WARNINGL0(condition, msg)
Definition: ErrorUtil.hpp:222
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
static std::string RegisterEnumValue(std::string pEnum, std::string pString, int pEnumValue)
Registers an enumeration value.
static std::string RegisterDefaultSolverInfo(const std::string &pName, const std::string &pValue)
Registers the default string value of a solver info property.
Base class for the development of solvers.
Definition: DriverArnoldi.h:47
void CopyFwdToAdj()
Copy the forward field to the adjoint system in transient growth calculations.
virtual void v_InitObject(std::ostream &out=std::cout) override
Virtual function for initialisation implementation.
void WriteFld(std::string file, std::vector< Array< OneD, NekDouble > > coeffs)
Write coefficients to file.
int m_infosteps
underlying operator is time stepping
Definition: DriverArnoldi.h:69
void CopyFieldToArnoldiArray(Array< OneD, NekDouble > &array)
Copy fields to Arnoldi storage.
int m_nvec
Dimension of Krylov subspace.
Definition: DriverArnoldi.h:63
bool m_timeSteppingAlgorithm
Period of time stepping algorithm.
Definition: DriverArnoldi.h:67
int m_nits
Number of vectors to test.
Definition: DriverArnoldi.h:64
Array< OneD, NekDouble > m_imag_evl
Definition: DriverArnoldi.h:77
void CopyArnoldiArrayToField(Array< OneD, NekDouble > &array)
Copy Arnoldi storage to fields.
NekDouble m_evtol
Maxmum number of iterations.
Definition: DriverArnoldi.h:65
int m_nfields
interval to dump information if required.
Definition: DriverArnoldi.h:71
SOLVER_UTILS_EXPORT void ArnoldiSummary(std::ostream &out)
Array< OneD, NekDouble > m_real_evl
Operator in solve call is negated.
Definition: DriverArnoldi.h:76
void WriteEvs(std::ostream &evlout, const int k, const NekDouble real, const NekDouble imag, NekDouble resid=NekConstants::kNekUnsetDouble, bool DumpInverse=true)
static std::string arpackProblemTypeDefault
Definition: DriverArpack.h:90
static DriverSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Creates an instance of this class.
Definition: DriverArpack.h:54
DriverArpack(const LibUtilities::SessionReaderSharedPtr pSession, const SpatialDomains::MeshGraphSharedPtr pGraph)
Constructor.
virtual void v_InitObject(std::ostream &out=std::cout) override
Virtual function for initialisation implementation.
static std::string driverLookupId
Definition: DriverArpack.h:86
static std::string arpackProblemTypeLookupIds[]
Definition: DriverArpack.h:89
virtual void v_Execute(std::ostream &out=std::cout) override
Virtual function for solve implementation.
static std::string className
Name of the class.
Definition: DriverArpack.h:65
static std::string ArpackProblemTypeTrans[]
Definition: DriverArpack.h:91
LibUtilities::SessionReaderSharedPtr m_session
Session reader object.
Definition: Driver.h:85
LibUtilities::CommSharedPtr m_comm
Communication object.
Definition: Driver.h:82
enum EvolutionOperatorType m_EvolutionOperator
Evolution Operator.
Definition: Driver.h:100
Array< OneD, EquationSystemSharedPtr > m_equ
Equation system to solve.
Definition: Driver.h:94
int m_nequ
number of equations
Definition: Driver.h:97
static void Dnaupd(int &ido, const char *bmat, const int &n, const char *which, const int &nev, const double &tol, double *resid, const int &ncv, double *v, const int &ldv, int *iparam, int *ipntr, double *workd, double *workl, const int &lworkl, int &info)
Top level reverse communication interface to solve real double-precision non-symmetric problems.
Definition: Arpack.hpp:116
static void Dneupd(const int &rvec, const char *howmny, const int *select, double *dr, double *di, double *z, const int &ldz, const double &sigmar, const double &sigmai, double *workev, const char *bmat, const int &n, const char *which, const int &nev, const double &tol, double *resid, const int &ncv, double *v, const int &ldv, int *iparam, int *ipntr, double *workd, double *workl, const int &lworkl, int &info)
Post-processing routine to computed eigenvector of computed eigenvalues in Dnaupd.
Definition: Arpack.hpp:131
std::shared_ptr< SessionReader > SessionReaderSharedPtr
static const NekDouble kNekUnsetDouble
static const NekDouble kNekZeroTol
DriverFactory & GetDriverFactory()
Definition: Driver.cpp:67
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:176
std::vector< double > z(NPUPPER)
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add scalar y = alpha + x.
Definition: Vmath.cpp:379