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 
37 using namespace std;
38 
39 namespace Nektar
40 {
41 namespace SolverUtils
42 {
43 
44 std::string DriverArpack::arpackProblemTypeLookupIds[6] = {
45  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","LargestReal" ,0),
46  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","SmallestReal" ,1),
47  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","LargestImag" ,2),
48  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","SmallestImag" ,3),
49  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","LargestMag" ,4),
50  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","SmallestMag" ,5),
51 };
52 std::string DriverArpack::arpackProblemTypeDefault = LibUtilities::SessionReader::RegisterDefaultSolverInfo("ArpackProblemType","LargestMag");
53 std::string DriverArpack::driverLookupId = LibUtilities::SessionReader::RegisterEnumValue("Driver","Arpack",0);
54 
55 std::string DriverArpack::className = GetDriverFactory().RegisterCreatorFunction("Arpack", DriverArpack::create);
56 
57 std::string DriverArpack::ArpackProblemTypeTrans[6] =
58 { "LR", "SR", "LI", "SI", "LM", "SM" };
59 
60 
61 /**
62  *
63  */
64 DriverArpack::DriverArpack(const LibUtilities::SessionReaderSharedPtr pSession,
66  : DriverArnoldi(pSession, pGraph)
67 {
68 }
69 
70 
71 /**
72  *
73  */
75 {
76 }
77 
78 /**
79  *
80  */
81 void DriverArpack::v_InitObject(ostream &out)
82 {
84 
85  //Initialisation of Arnoldi parameters
86  m_maxn = 1000000; // Maximum size of the problem
87  m_maxnev = 200; // maximum number of eigenvalues requested
88  m_maxncv = 500; // Largest number of basis vector used in Implicitly Restarted Arnoldi
89 
90  // Error alerts
91  ASSERTL0(m_nvec <= m_maxnev,"NEV is greater than MAXNEV");
92  ASSERTL0(m_kdim <= m_maxncv,"NEV is greater than MAXNEV");
93  ASSERTL0(2 <= m_kdim-m_nvec,"NCV-NEV is less than 2");
94 
95  ASSERTL0(m_comm->GetSize()==1,"..ARPACK is not currently set-up for parallel execution...\n");
96  m_equ[0]->PrintSummary(out);
97 
98  ASSERTL0(m_comm->GetSize() == 1,
99  "ARPACK Arnoldi solver does not support execution in parallel.");
100 
101  // Print session parameters
102  out << "\tArnoldi solver type : Arpack" << endl;
103 
104  out << "\tArpack problem type : ";
105  out << ArpackProblemTypeTrans[m_session->GetSolverInfoAsEnum<int>("ArpackProblemType")] << endl;
107 
108  for( int i = 0; i < m_nequ; ++i)
109  {
110  m_equ[i]->DoInitialise();
111  }
112 
113  // FwdTrans Initial conditions to be in Coefficient Space
114  m_equ[m_nequ-1] ->TransPhysToCoeff();
115 
116 }
117 
118 
119 void DriverArpack::v_Execute(ostream &out)
120 
121 {
122  Array<OneD, NekDouble> tmpworkd;
123 
124  int nq = m_equ[0]->UpdateFields()[0]->GetNcoeffs(); // Number of points in the mesh
125  int n = m_nfields*nq; // Number of points in eigenvalue calculation
126  int lworkl = 3*m_kdim*(m_kdim+2); // Size of work array
127  int ido ; //REVERSE COMMUNICATION parameter. At the first call must be initialised at 0
128  int info; // do not set initial vector (info=0 random initial vector, info=1 read initial vector from session file)
129 
130  int iparam[11];
131  int ipntr[14];
132 
133  Array<OneD, int> ritzSelect;
136  Array<OneD, NekDouble> workev;
138  NekDouble sigmar, sigmai;
139 
140  Array<OneD, NekDouble> resid(n);
142  Array<OneD, NekDouble> workl(lworkl, 0.0);
143  Array<OneD, NekDouble> workd(3*n, 0.0);
144 
145  ASSERTL0(n <= m_maxn, "N is greater than MAXN");
146 
147  if(m_session->DefinesFunction("InitialConditions"))
148  {
149  out << "\tInital vector : input file " << endl;
150  info = 1;
152  }
153  else
154  {
155  out << "\tInital vector : random " << endl;
156  info = 0;
157  }
158 
159  char B;
160 
161  iparam[0] = 1; // strategy for shift-invert
162  iparam[1] = 0; // (deprecated)
163  iparam[2] = m_nits; // maximum number of iterations allowed/taken
164  iparam[3] = 1; // blocksize to be used for recurrence
165  iparam[4] = 0; // number of converged ritz eigenvalues
166  iparam[5] = 0; // (deprecated)
167 
168  // Use generalized B matrix for coupled solver.
170  {
171  iparam[6] = 1; // computation mode 1=> matrix-vector prod
172  B = 'I';
173  }
174  else {
175  iparam[6] = 3; // computation mode 1=> matrix-vector prod
176  B = 'G';
177  }
178 #if 0
179  if((fabs(m_realShift) > NekConstants::kNekZeroTol)|| // use shift if m_realShift > 1e-12
181  {
182  iparam[6] = 3; // This was 3 need to know what to set it to
183  B = 'G';
184  }
185  else
186  {
187  iparam[6] = 1; // computation mode 1=> matrix-vector prod
188  B = 'I';
189  }
190 #endif
191  iparam[7] = 0; // (for shift-invert)
192  iparam[8] = 0; // number of MV operations
193  iparam[9] = 0; // number of BV operations
194  iparam[10]= 0; // number of reorthogonalisation steps
195 
196  int cycle = 0;
197  const char* problem = ArpackProblemTypeTrans[m_session->GetSolverInfoAsEnum<int>("ArpackProblemType")].c_str();
198 
199  std::string name = m_session->GetSessionName() + ".evl";
200  ofstream pFile(name.c_str());
201 
202  ido = 0; //At the first call must be initialisedat 0
203 
204  while(ido != 99)//ido==-1 || ido==1 || ido==0)
205  {
206  //Routine for eigenvalue evaluation for non-symmetric operators
207  Arpack::Dnaupd( ido, &B, // B='I' for std eval problem
208  n, problem, m_nvec,
209  m_evtol, &resid[0], m_kdim,
210  &v[0], n, iparam, ipntr, &workd[0],
211  &workl[0], lworkl, info);
212 
213  //Plotting of real and imaginary part of the
214  //eigenvalues from workl
215  out << "\rIteration " << cycle << ", output: " << info << ", ido=" << ido << " " << std::flush;
216 
217  if(!((cycle-1)%m_kdim)&&(cycle> m_kdim)&&(ido!=2))
218  {
219  pFile << "Krylov spectrum at iteration: " << cycle << endl;
220 
222  {
223  pFile << "EV Magnitude Angle Growth Frequency Residual" << endl;
224  }
225  else
226  {
227  pFile << "EV Real Imaginary inverse real inverse imag Residual" << endl;
228  }
229 
230  out << endl;
231  for(int k = 0; k < m_kdim; ++k)
232  {
233  // write m_kdim eigs to screen
234  WriteEvs(pFile,k, workl[ipntr[5]-1+k],workl[ipntr[6]-1+k]);
235  }
236  }
237 
238  if (ido == 99) break;
239 
240  switch(ido)
241  {
242  case -1:
243  case 1: // Note that ido=1 we are using input x
244  // (workd[inptr[0]-1]) rather than Mx as
245  // recommended in manual since it is not
246  // possible to impose forcing directly.
247  CopyArnoldiArrayToField(tmpworkd = workd + (ipntr[0]-1));
248 
249  m_equ[0]->TransCoeffToPhys();
250 
251  m_equ[0]->DoSolve();
253  {
254  //start Adjoint with latest fields of direct
255  CopyFwdToAdj();
256 
257  m_equ[1]->TransCoeffToPhys();
258  m_equ[1]->DoSolve();
259  }
260 
261  if(!(cycle%m_infosteps))
262  {
263  out << endl;
264  m_equ[0]->Output();
265  }
266 
267  // operated fields are copied into workd[inptr[1]-1]
268  CopyFieldToArnoldiArray(tmpworkd = workd + (ipntr[1]-1));
269 
270  cycle++;
271  break;
272  case 2: // provide y = M x (bwd trans and iproduct);
273  {
274  //workd[inptr[0]-1] copied into operator fields
275  CopyArnoldiArrayToField(tmpworkd = workd + (ipntr[0]-1));
276 
277  m_equ[0]->TransCoeffToPhys();
278 
279  Array<OneD, MultiRegions::ExpListSharedPtr> fields = m_equ[0]->UpdateFields();
280  for (int i = 0; i < fields.size(); ++i)
281  {
282  fields[i]->IProductWRTBase(fields[i]->GetPhys(),
283  fields[i]->UpdateCoeffs());
284  }
285 
286  // operated fields are copied into workd[inptr[1]-1]
287  CopyFieldToArnoldiArray(tmpworkd = workd + (ipntr[1]-1));
288  break;
289  }
290  default:
291  ASSERTL0(false, "Unexpected reverse communication request.");
292  }
293 
294  }
295 
296  out<< endl << "Converged in " << iparam[8] << " iterations" << endl;
297 
298  ASSERTL0(info >= 0," Error with Dnaupd");
299 
300  ritzSelect = Array<OneD, int> (m_kdim,0);
301  dr = Array<OneD, NekDouble> (m_nvec+1,0.0);
302  di = Array<OneD, NekDouble> (m_nvec+1,0.0);
303  workev = Array<OneD, NekDouble> (3*m_kdim);
304  z = Array<OneD, NekDouble> (n*(m_nvec+1));
305 
306  if(m_negatedOp)
307  {
308  sigmar = -m_realShift;
309  }
310  else
311  {
312  sigmar = m_realShift;
313  }
314 
315  // Do not pass imaginary shift to Arpack since we have not
316  // used a Fortran complex number format and so processing
317  // is mucked up. Need to do some processing afterwards.
318  sigmai = 0;
319 
320  //Setting 'A', Ritz vectors are computed. 'S' for Shur vectors
321  Arpack::Dneupd(1, "A", ritzSelect.get(), dr.get(), di.get(),
322  z.get(), n, sigmar, sigmai, workev.get(), &B,
323  n, problem, m_nvec, m_evtol, resid.get(), m_kdim,
324  v.get(), n, iparam, ipntr, workd.get(),
325  workl.get(),lworkl,info);
326 
327  ASSERTL0(info == 0, " Error with Dneupd");
328 
329  int nconv=iparam[4];
330 
331  // Subtract off complex shift if it exists
332  if(m_negatedOp)
333  {
334  Vmath::Sadd(nconv,m_imagShift,di,1,di,1);
335  }
336  else
337  {
338  Vmath::Sadd(nconv,-m_imagShift,di,1,di,1);
339  }
340 
341  WARNINGL0(m_imagShift == 0,"Complex Shift applied. "
342  "Need to implement Ritz re-evaluation of"
343  "eigenvalue. Only one half of complex "
344  "value will be correct");
345 
346 
347  Array<OneD, MultiRegions::ExpListSharedPtr> fields = m_equ[0]->UpdateFields();
348 
349  out << "Converged Eigenvalues: " << nconv << endl;
350  pFile << "Converged Eigenvalues: " << nconv << endl;
351 
353  {
354  out << " Magnitude Angle Growth Frequency" << endl;
355  pFile << " Magnitude Angle Growth Frequency" << endl;
356  for(int i= 0; i< nconv; ++i)
357  {
358  WriteEvs(out,i,dr[i],di[i]);
359  WriteEvs(pFile,i,dr[i],di[i]);
360 
361  std::string file = m_session->GetSessionName() + "_eig_"
362  + boost::lexical_cast<std::string>(i)
363  + ".fld";
364  WriteFld(file,z + i*n);
365  }
366  }
367  else
368  {
369  out << " Real Imaginary " << endl;
370  pFile << " Real Imaginary " << endl;
371  for(int i= 0; i< nconv; ++i)
372  {
373  WriteEvs(out,i,dr[i],di[i],
375  WriteEvs(pFile,i,dr[i],di[i],
377 
378  std::string file = m_session->GetSessionName() + "_eig_"
379  + boost::lexical_cast<std::string>(i)
380  + ".fld";
381  WriteFld(file,z + i*n);
382  }
383  }
384 
385  m_real_evl = dr;
386  m_imag_evl = di;
387 
388  pFile.close();
389 
390  for(int j = 0; j < m_equ[0]->GetNvariables(); ++j)
391  {
392  NekDouble vL2Error = m_equ[0]->L2Error(j,false);
393  NekDouble vLinfError = m_equ[0]->LinfError(j);
394  if (m_comm->GetRank() == 0)
395  {
396  out << "L 2 error (variable " << m_equ[0]->GetVariable(j) << ") : " << vL2Error << endl;
397  out << "L inf error (variable " << m_equ[0]->GetVariable(j) << ") : " << vLinfError << endl;
398  }
399  }
400 }
401 
402 }
403 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
#define WARNINGL0(condition, msg)
Definition: ErrorUtil.hpp:223
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:200
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.
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:65
void CopyFieldToArnoldiArray(Array< OneD, NekDouble > &array)
Copy fields to Arnoldi storage.
virtual void v_InitObject(std::ostream &out=std::cout)
int m_nvec
Dimension of Krylov subspace.
Definition: DriverArnoldi.h:59
bool m_timeSteppingAlgorithm
Period of time stepping algorithm.
Definition: DriverArnoldi.h:63
int m_nits
Number of vectors to test.
Definition: DriverArnoldi.h:60
Array< OneD, NekDouble > m_imag_evl
Definition: DriverArnoldi.h:73
void CopyArnoldiArrayToField(Array< OneD, NekDouble > &array)
Copy Arnoldi storage to fields.
NekDouble m_evtol
Maxmum number of iterations.
Definition: DriverArnoldi.h:61
int m_nfields
interval to dump information if required.
Definition: DriverArnoldi.h:67
SOLVER_UTILS_EXPORT void ArnoldiSummary(std::ostream &out)
Array< OneD, NekDouble > m_real_evl
Operator in solve call is negated.
Definition: DriverArnoldi.h:72
void WriteEvs(std::ostream &evlout, const int k, const NekDouble real, const NekDouble imag, NekDouble resid=NekConstants::kNekUnsetDouble, bool DumpInverse=true)
virtual void v_InitObject(std::ostream &out=std::cout)
Virtual function for initialisation implementation.
virtual ~DriverArpack()
Destructor.
virtual void v_Execute(std::ostream &out=std::cout)
Virtual function for solve implementation.
static std::string ArpackProblemTypeTrans[]
Definition: DriverArpack.h:92
LibUtilities::SessionReaderSharedPtr m_session
Session reader object.
Definition: Driver.h:89
LibUtilities::CommSharedPtr m_comm
Communication object.
Definition: Driver.h:86
enum EvolutionOperatorType m_EvolutionOperator
Evolution Operator.
Definition: Driver.h:104
Array< OneD, EquationSystemSharedPtr > m_equ
Equation system to solve.
Definition: Driver.h:98
int m_nequ
number of equations
Definition: Driver.h:101
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:134
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:148
std::shared_ptr< SessionReader > SessionReaderSharedPtr
static const NekDouble kNekUnsetDouble
static const NekDouble kNekZeroTol
DriverFactory & GetDriverFactory()
Definition: Driver.cpp:65
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:174
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
double NekDouble
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add vector y = alpha - x.
Definition: Vmath.cpp:341