Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 // 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: Arnoldi solver using Arpack
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
37 
38 namespace Nektar
39 {
40  namespace SolverUtils
41  {
43  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","LargestReal" ,0),
44  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","SmallestReal" ,1),
45  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","LargestImag" ,2),
46  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","SmallestImag" ,3),
47  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","LargestMag" ,4),
48  LibUtilities::SessionReader::RegisterEnumValue("ArpackProblemType","SmallestMag" ,5),
49  };
52 
54 
56  { "LR", "SR", "LI", "SI", "LM", "SM" };
57 
58 
59  /**
60  *
61  */
63  : DriverArnoldi(pSession)
64  {
65  }
66 
67 
68  /**
69  *
70  */
72  {
73  }
74 
75  /**
76  *
77  */
78  void DriverArpack::v_InitObject(ostream &out)
79  {
81 
82  //Initialisation of Arnoldi parameters
83  m_maxn = 1000000; // Maximum size of the problem
84  m_maxnev = 200; // maximum number of eigenvalues requested
85  m_maxncv = 500; // Largest number of basis vector used in Implicitly Restarted Arnoldi
86 
87  // Error alerts
88  ASSERTL0(m_nvec <= m_maxnev,"NEV is greater than MAXNEV");
89  ASSERTL0(m_kdim <= m_maxncv,"NEV is greater than MAXNEV");
90  ASSERTL0(2 <= m_kdim-m_nvec,"NCV-NEV is less than 2");
91 
92  m_equ[0]->PrintSummary(out);
93 
94  // Print session parameters
95  out << "\tArnoldi solver type : Arpack" << endl;
96 
97  out << "\tArpack problem type : ";
98  out << ArpackProblemTypeTrans[m_session->GetSolverInfoAsEnum<int>("ArpackProblemType")] << endl;
100 
101  m_equ[m_nequ - 1]->DoInitialise();
102 
103  //FwdTrans Initial conditions to be in Coefficient Space
104  m_equ[m_nequ-1] ->TransPhysToCoeff();
105 
106  }
107 
108 
109  void DriverArpack::v_Execute(ostream &out)
110 
111  {
112  Array<OneD, NekDouble> tmpworkd;
113  bool random;
114 
115  int nq = m_equ[0]->UpdateFields()[0]->GetNcoeffs(); // Number of points in the mesh
116  int n = m_nfields*nq; // Number of points in eigenvalue calculation
117  int lworkl = 3*m_kdim*(m_kdim+2); // Size of work array
118  int ido ; //REVERSE COMMUNICATION parameter. At the first call must be initialised at 0
119  int info; // do not set initial vector (info=0 random initial vector, info=1 read initial vector from session file)
120 
121  int iparam[11];
122  int ipntr[14];
123 
124  Array<OneD, int> ritzSelect;
125  Array<OneD, NekDouble> dr;
126  Array<OneD, NekDouble> di;
127  Array<OneD, NekDouble> workev;
128  Array<OneD, NekDouble> z;
129  NekDouble sigmar, sigmai;
130 
131  Array<OneD, NekDouble> resid(n);
132  Array<OneD, NekDouble> v(n*m_kdim);
133  Array<OneD, NekDouble> workl(lworkl);
134  Array<OneD, NekDouble> workd(3*n, 0.0);
135 
136  ASSERTL0(n <= m_maxn, "N is greater than MAXN");
137 
138  if(m_session->DefinesFunction("InitialConditions"))
139  {
140 
141  out << "\tInital vector : input file " << endl;
142  info = 1;
144 
145  }
146  else
147  {
148  out << "\tInital vector : random " << endl;
149  info = 0;
150  }
151 
152 
153  iparam[0] = 1; // strategy for shift-invert
154  iparam[1] = 0; // (deprecated)
155  iparam[2] = m_nits; // maximum number of iterations allowed/taken
156  iparam[3] = 1; // blocksize to be used for recurrence
157  iparam[4] = 0; // number of converged ritz eigenvalues
158  iparam[5] = 0; // (deprecated)
159  if((fabs(m_realShift) > NekConstants::kNekZeroTol)|| // use shift if m_realShift > 1e-12
161  {
162  iparam[6] = 3;
163  }
164  else
165  {
166  iparam[6] = 1; // computation mode 1=> matrix-vector prod
167  }
168  iparam[7] = 0; // (for shift-invert)
169  iparam[8] = 0; // number of MV operations
170  iparam[9] = 0; // number of BV operations
171  iparam[10]= 0; // number of reorthogonalisation steps
172 
173  int cycle = 0;
174  const char* problem = ArpackProblemTypeTrans[m_session->GetSolverInfoAsEnum<int>("ArpackProblemType")].c_str();
175 
176  std::string name = m_session->GetFilename().substr(0,m_session->GetFilename().find_last_of('.'))+".evl";
177  ofstream pFile(name.c_str());
178 
179  ido = 0; //At the first call must be initialisedat 0
180 
181  while(ido != 99)//ido==-1 || ido==1 || ido==0)
182  {
183  //Routine for eigenvalue evaluation for non-symmetric operators
184  Arpack::Dnaupd( ido, "I", // B='I' for std eval problem
185  n, problem, m_nvec,
186  m_evtol, &resid[0], m_kdim,
187  &v[0], n, iparam, ipntr, &workd[0],
188  &workl[0], lworkl, info);
189 
190  //Plotting of real and imaginary part of the eigenvalues from workl
191  out << "\rIteration " << cycle << ", output: " << info << ", ido=" << ido << " " << std::flush;
192 
193  if(!((cycle-1)%m_kdim)&&(cycle> m_kdim))
194  {
195  pFile << "Krylov spectrum at iteration: " << cycle << endl;
196 
198  {
199  pFile << "EV Magnitude Angle Growth Frequency Residual" << endl;
200  }
201  else
202  {
203  pFile << "EV Real Imaginary inverse real inverse imag Residual" << endl;
204  }
205 
206  out << endl;
207  for(int k=0; k<=m_kdim-1; ++k)
208  {
209  // write m_nvec eigs to screen
210  if(m_kdim-1-k < m_nvec)
211  {
212  WriteEvs(out,k, workl[ipntr[5]-1+k],workl[ipntr[6]-1+k]);
213  }
214  // write m_kdim eigs to screen
215  WriteEvs(pFile,k, workl[ipntr[5]-1+k],workl[ipntr[6]-1+k]);
216  }
217  }
218 
219  cycle++;
220 
221  if (ido == 99) break;
222 
223  ASSERTL0(ido == 1, "Unexpected reverse communication request.");
224 
225  //workd[inptr[0]-1] copied into operator fields
226  CopyArnoldiArrayToField(tmpworkd = workd + (ipntr[0]-1));
227 
228  m_equ[0]->TransCoeffToPhys();
229 
230  m_equ[0]->DoSolve();
231 
232  if(!(cycle%m_infosteps))
233  {
234  out << endl;
235  m_equ[0]->Output();
236  }
237 
239  {
240  //start Adjoint with latest fields of direct
241  CopyFwdToAdj();
242 
243  m_equ[1]->TransCoeffToPhys();
244  m_equ[1]->DoSolve();
245  }
246 
247  // operated fields are copied into workd[inptr[1]-1]
248  CopyFieldToArnoldiArray(tmpworkd = workd + (ipntr[1]-1));
249 
250  }
251 
252  out<< endl << "Converged in " << iparam[8] << " iterations" << endl;
253 
254  ASSERTL0(info >= 0," Error with Dnaupd");
255 
256  ritzSelect = Array<OneD, int> (m_kdim,0);
257  dr = Array<OneD, NekDouble> (m_nvec+1,0.0);
258  di = Array<OneD, NekDouble> (m_nvec+1,0.0);
259  workev = Array<OneD, NekDouble> (3*m_kdim);
260  z = Array<OneD, NekDouble> (n*(m_nvec+1));
261 
262  sigmar = m_realShift;
263  sigmai = m_imagShift;
264 
265  //Setting 'A', Ritz vectors are computed. 'S' for Shur vectors
266  Arpack::Dneupd(1, "A", ritzSelect.get(), dr.get(), di.get(), z.get(), n, sigmar, sigmai, workev.get(), "I", n, problem, m_nvec, m_evtol, resid.get(), m_kdim, v.get(), n, iparam, ipntr, workd.get(), workl.get(),lworkl,info);
267 
268  ASSERTL0(info == 0, " Error with Dneupd");
269  int nconv=iparam[4];
270  Array<OneD, MultiRegions::ExpListSharedPtr> fields = m_equ[0]->UpdateFields();
271 
272  out << "Converged Eigenvalues: " << nconv << endl;
273  pFile << "Converged Eigenvalues:"<< nconv << endl;
274 
276  {
277  pFile << "EV Magnitude Angle Growth Frequency" << endl;
278  }
279  else
280  {
281  pFile << "EV Real Imaginary inverse real inverse imag" << endl;
282  }
283 
284 
285  for(int i= 0; i< nconv; ++i)
286  {
287  WriteEvs(out,i,dr[i],di[i]);
288  WriteEvs(pFile,i,dr[i],di[i]);
289 
290  std::string file = m_session->GetFilename().substr(0,m_session->GetFilename().find_last_of('.')) + "_eig_" + boost::lexical_cast<std::string>(i);
291 
292  WriteFld(file,z + i*nq);
293  }
294 
295  m_real_evl = dr;
296  m_imag_evl = di;
297 
298  pFile.close();
299 
300  for(int j = 0; j < m_equ[0]->GetNvariables(); ++j)
301  {
302  NekDouble vL2Error = m_equ[0]->L2Error(j,false);
303  NekDouble vLinfError = m_equ[0]->LinfError(j);
304  if (m_comm->GetRank() == 0)
305  {
306  out << "L 2 error (variable " << m_equ[0]->GetVariable(j) << ") : " << vL2Error << endl;
307  out << "L inf error (variable " << m_equ[0]->GetVariable(j) << ") : " << vLinfError << endl;
308  }
309  }
310  }
311  }
312 }