Nektar++
DriverArnoldi.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: DriverArnoldi.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: Base Driver class for the stability solver
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 #include <iomanip>
35 
37 
38 using namespace std;
39 
40 namespace Nektar
41 {
42 namespace SolverUtils
43 {
44 
45 /**
46  * Constructor
47  */
48 DriverArnoldi::DriverArnoldi(
51  : Driver(pSession, pGraph)
52 {
53  m_session->LoadParameter("IO_InfoSteps", m_infosteps, 1);
54 }
55 
56 /**
57  * Destructor
58  */
60 {
61 }
62 
63 /**
64  * Arnoldi driver initialisation
65  */
66 void DriverArnoldi::v_InitObject(ostream &out)
67 {
69  m_session->MatchSolverInfo("SolverType", "VelocityCorrectionScheme",
71 
73  {
74  m_period = m_session->GetParameter("TimeStep") *
75  m_session->GetParameter("NumSteps");
76  m_nfields = m_equ[0]->UpdateFields().size() - 1;
77  }
78  else
79  {
80  m_period = 1.0;
81  m_nfields = m_equ[0]->UpdateFields().size();
82  }
83 
84  if (m_session->DefinesSolverInfo("ModeType") &&
85  (boost::iequals(m_session->GetSolverInfo("ModeType"), "SingleMode") ||
86  boost::iequals(m_session->GetSolverInfo("ModeType"), "HalfMode")))
87  {
88  for (int i = 0; i < m_nfields; ++i)
89  {
90  m_equ[0]->UpdateFields()[i]->SetWaveSpace(true);
91  }
92  }
93  m_negatedOp = m_equ[0]->v_NegatedOp();
94 
95  m_session->LoadParameter("kdim", m_kdim, 16);
96  m_session->LoadParameter("nvec", m_nvec, 2);
97  m_session->LoadParameter("nits", m_nits, 500);
98  m_session->LoadParameter("evtol", m_evtol, 1e-06);
99 
100  ASSERTL0(m_kdim >= m_nvec, "nvec cannot be larger than kdim.");
101 
102  m_session->LoadParameter("realShift", m_realShift, 0.0);
103  m_equ[0]->SetLambda(m_realShift);
104 
105  m_session->LoadParameter("imagShift", m_imagShift, 0.0);
106 
107  // The imaginary shift is applied at system assembly
108  // Only if using HOMOGENEOUS expansion and ModeType set to SingleMode
109  if (m_imagShift != 0.0)
110  {
111  if (!m_session->DefinesSolverInfo("HOMOGENEOUS") &&
112  !m_session->DefinesSolverInfo("ModeType"))
113  {
115  "Imaginary shift only supported with HOMOGENEOUS "
116  "expansion and ModeType set to SingleMode");
117  }
118  else if (!boost::iequals(m_session->GetSolverInfo("ModeType"),
119  "SingleMode"))
120  {
122  "Imaginary shift only supported with HOMOGENEOUS "
123  "expansion and ModeType set to SingleMode");
124  }
125  }
126  MaskInit();
127 }
128 
129 void DriverArnoldi::ArnoldiSummary(std::ostream &out)
130 {
131  if (m_comm->GetRank() == 0)
132  {
133  if (m_session->DefinesSolverInfo("ModeType") &&
134  boost::iequals(m_session->GetSolverInfo("ModeType"), "SingleMode"))
135  {
136  out << "\tSingle Fourier mode : true " << endl;
137  ASSERTL0(m_session->DefinesSolverInfo("Homogeneous"),
138  "Expected a homogeneous expansion to be defined "
139  "with single mode");
140  }
141  else
142  {
143  out << "\tSingle Fourier mode : false " << endl;
144  }
145  if (m_session->DefinesSolverInfo("BetaZero"))
146  {
147  out << "\tBeta set to Zero : true (overrides LHom)" << endl;
148  }
149  else
150  {
151  out << "\tBeta set to Zero : false " << endl;
152  }
153 
155  {
156  out << "\tEvolution operator : "
157  << m_session->GetSolverInfo("EvolutionOperator") << endl;
158  }
159  else
160  {
161  out << "\tShift (Real,Imag) : " << m_realShift << ","
162  << m_imagShift << endl;
163  }
164  out << "\tKrylov-space dimension : " << m_kdim << endl;
165  out << "\tNumber of vectors : " << m_nvec << endl;
166  out << "\tMax iterations : " << m_nits << endl;
167  out << "\tEigenvalue tolerance : " << m_evtol << endl;
168  out << "======================================================" << endl;
169  }
170 }
171 
172 /**
173  * Copy Arnoldi array to field variables which depend from
174  * either the m_fields or m_forces
175  */
177 {
178 
180  m_equ[0]->UpdateFields();
181  int nq = fields[0]->GetNcoeffs();
182 
183  for (int k = 0; k < m_nfields; ++k)
184  {
185  Vmath::Vcopy(nq, &array[k * nq], 1, &fields[k]->UpdateCoeffs()[0], 1);
186  fields[k]->SetPhysState(false);
187  }
188 }
189 
190 /**
191  * Copy field variables which depend from either the m_fields
192  * or m_forces array the Arnoldi array
193  */
195 {
196 
198 
200  {
201  // This matters for the Adaptive SFD method because
202  // m_equ[1] is the nonlinear problem with non
203  // homogeneous BCs.
204  fields = m_equ[0]->UpdateFields();
205  }
206  else
207  {
208  fields = m_equ[m_nequ - 1]->UpdateFields();
209  }
210 
211  for (int k = 0; k < m_nfields; ++k)
212  {
213  int nq = fields[0]->GetNcoeffs();
214  Vmath::Vcopy(nq, &fields[k]->GetCoeffs()[0], 1, &array[k * nq], 1);
215  fields[k]->SetPhysState(false);
216  }
217 }
218 
219 /**
220  * Initialisation for the transient growth
221  */
223 {
225 
227  "Transient Growth non available for Coupled Solver");
228 
229  fields = m_equ[0]->UpdateFields();
230  int nq = fields[0]->GetNcoeffs();
231 
232  for (int k = 0; k < m_nfields; ++k)
233  {
234  Vmath::Vcopy(nq, &fields[k]->GetCoeffs()[0], 1,
235  &m_equ[1]->UpdateFields()[k]->UpdateCoeffs()[0], 1);
236  }
237 }
238 
239 void DriverArnoldi::WriteFld(std::string file,
240  std::vector<Array<OneD, NekDouble>> coeffs)
241 {
242 
243  std::vector<std::string> variables(m_nfields);
244 
245  ASSERTL1(coeffs.size() >= m_nfields, "coeffs is not of the correct length");
246  for (int i = 0; i < m_nfields; ++i)
247  {
248  variables[i] = m_equ[0]->GetVariable(i);
249  }
250 
251  m_equ[0]->WriteFld(file, m_equ[0]->UpdateFields()[0], coeffs, variables);
252 }
253 
254 void DriverArnoldi::WriteFld(std::string file, Array<OneD, NekDouble> coeffs)
255 {
256 
257  std::vector<std::string> variables(m_nfields);
258  std::vector<Array<OneD, NekDouble>> fieldcoeffs(m_nfields);
259 
260  int ncoeffs = m_equ[0]->UpdateFields()[0]->GetNcoeffs();
261  ASSERTL1(coeffs.size() >= ncoeffs * m_nfields,
262  "coeffs is not of sufficient size");
263 
264  for (int i = 0; i < m_nfields; ++i)
265  {
266  variables[i] = m_equ[0]->GetVariable(i);
267  fieldcoeffs[i] = coeffs + i * ncoeffs;
268  }
269 
270  m_equ[0]->WriteFld(file, m_equ[0]->UpdateFields()[0], fieldcoeffs,
271  variables);
272 }
273 
274 void DriverArnoldi::WriteEvs(ostream &evlout, const int i,
275  const NekDouble re_ev, const NekDouble im_ev,
276  NekDouble resid, bool DumpInverse)
277 {
279  {
280  NekDouble abs_ev = hypot(re_ev, im_ev);
281  NekDouble ang_ev = atan2(im_ev, re_ev);
282 
283  evlout << "EV: " << setw(2) << i << setw(12) << abs_ev << setw(12)
284  << ang_ev << setw(12) << log(abs_ev) / m_period << setw(12)
285  << ang_ev / m_period;
286 
287  if (resid != NekConstants::kNekUnsetDouble)
288  {
289  evlout << setw(12) << resid;
290  }
291  evlout << endl;
292  }
293  else
294  {
295  NekDouble invmag = 1.0 / (re_ev * re_ev + im_ev * im_ev);
296  NekDouble sign;
297  if (m_negatedOp)
298  {
299  sign = -1.0;
300  }
301  else
302  {
303  sign = 1.0;
304  }
305 
306  evlout << "EV: " << setw(2) << i << setw(14) << sign * re_ev << setw(14)
307  << sign * im_ev;
308 
309  if (DumpInverse)
310  {
311  evlout << setw(14) << sign * re_ev * invmag + m_realShift
312  << setw(14) << sign * im_ev * invmag + m_imagShift;
313  }
314 
315  if (resid != NekConstants::kNekUnsetDouble)
316  {
317  evlout << setw(12) << resid;
318  }
319  evlout << endl;
320  }
321 }
322 
324  std::vector<std::vector<LibUtilities::EquationSharedPtr>> &unmaskfun)
325 {
326  string Unmask0("Unmask0");
327  string C0("C0");
328  for (size_t i = 0; 1; ++i)
329  {
330  Unmask0[Unmask0.size() - 1] = '0' + i;
331  if (!m_session->DefinesFunction(Unmask0))
332  {
333  break;
334  }
335  for (size_t j = 0; 1; ++j)
336  {
337  C0[C0.size() - 1] = '0' + j;
338  if (!m_session->DefinesFunction(Unmask0, C0))
339  {
340  break;
341  }
342  if (j == 0)
343  {
344  unmaskfun.push_back(
345  std::vector<LibUtilities::EquationSharedPtr>());
346  }
347  unmaskfun[unmaskfun.size() - 1].push_back(
348  m_session->GetFunction(Unmask0, C0));
349  }
350  }
351 }
352 
354 {
355  std::vector<std::vector<LibUtilities::EquationSharedPtr>> unmaskfun;
356  GetUnmaskFunction(unmaskfun);
357  if (unmaskfun.size() == 0)
358  {
359  m_useMask = false;
360  return;
361  }
362  m_useMask = true;
363  MultiRegions::ExpListSharedPtr field = m_equ[0]->UpdateFields()[0];
364  int ncoef = field->GetNcoeffs();
365  int nphys = field->GetNpoints();
368  for (size_t i = 0; i < field->GetExpSize(); ++i)
369  {
370  LocalRegions::ExpansionSharedPtr exp = field->GetExp(i);
371  SpatialDomains::GeometrySharedPtr geom = exp->GetGeom();
372  int nv = geom->GetNumVerts();
373  NekDouble gc[3] = {0., 0., 0.};
374  NekDouble gct[3] = {0., 0., 0.};
375  for (size_t j = 0; j < nv; ++j)
376  {
377  SpatialDomains::PointGeomSharedPtr vertex = geom->GetVertex(j);
378  vertex->GetCoords(gct[0], gct[1], gct[2]);
379  gc[0] += gct[0] / NekDouble(nv);
380  gc[1] += gct[1] / NekDouble(nv);
381  gc[2] += gct[2] / NekDouble(nv);
382  }
383  int unmask = 1;
384  for (size_t m = 0; m < unmaskfun.size(); ++m)
385  {
386  unmask = 0;
387  for (size_t n = 0; n < unmaskfun[m].size(); ++n)
388  {
389  if (unmaskfun[m][n]->Evaluate(gc[0], gc[1], gc[2]) <= 0.)
390  {
391  unmask = 0;
392  break;
393  }
394  else
395  {
396  unmask = 1;
397  }
398  }
399  if (unmask == 1)
400  break;
401  }
402  if (unmask == 0)
403  {
404  for (int j = 0; j < m_nfields; ++j)
405  {
406  Vmath::Fill(
407  exp->GetNcoeffs(), 0.,
408  &m_maskCoeffs[field->GetCoeff_Offset(i) + j * ncoef], 1);
409  Vmath::Fill(exp->GetTotPoints(), 0.,
410  &m_maskPhys[field->GetPhys_Offset(i) + j * nphys],
411  1);
412  }
413  }
414  }
415 }
416 
417 } // namespace SolverUtils
418 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:49
virtual ~DriverArnoldi()
Destructor.
void CopyFwdToAdj()
Copy the forward field to the adjoint system in transient growth calculations.
virtual void v_InitObject(std::ostream &out=std::cout) override
NekDouble m_period
Tolerance of iteratiosn.
Definition: DriverArnoldi.h:64
int m_infosteps
underlying operator is time stepping
Definition: DriverArnoldi.h:67
void WriteFld(std::string file, std::vector< Array< OneD, NekDouble >> coeffs)
Write coefficients to file.
Array< OneD, NekDouble > m_maskCoeffs
Definition: DriverArnoldi.h:78
void CopyFieldToArnoldiArray(Array< OneD, NekDouble > &array)
Copy fields to Arnoldi storage.
int m_nvec
Dimension of Krylov subspace.
Definition: DriverArnoldi.h:61
bool m_timeSteppingAlgorithm
Period of time stepping algorithm.
Definition: DriverArnoldi.h:65
int m_nits
Number of vectors to test.
Definition: DriverArnoldi.h:62
void CopyArnoldiArrayToField(Array< OneD, NekDouble > &array)
Copy Arnoldi storage to fields.
void GetUnmaskFunction(std::vector< std::vector< LibUtilities::EquationSharedPtr >> &unmaskfun)
Array< OneD, NekDouble > m_maskPhys
Definition: DriverArnoldi.h:79
NekDouble m_evtol
Maxmum number of iterations.
Definition: DriverArnoldi.h:63
int m_nfields
interval to dump information if required.
Definition: DriverArnoldi.h:69
SOLVER_UTILS_EXPORT void ArnoldiSummary(std::ostream &out)
void WriteEvs(std::ostream &evlout, const int k, const NekDouble real, const NekDouble imag, NekDouble resid=NekConstants::kNekUnsetDouble, bool DumpInverse=true)
Base class for the development of solvers.
Definition: Driver.h:67
LibUtilities::SessionReaderSharedPtr m_session
Session reader object.
Definition: Driver.h:88
virtual SOLVER_UTILS_EXPORT void v_InitObject(std::ostream &out=std::cout)
Definition: Driver.cpp:87
LibUtilities::CommSharedPtr m_comm
Communication object.
Definition: Driver.h:85
enum EvolutionOperatorType m_EvolutionOperator
Evolution Operator.
Definition: Driver.h:103
Array< OneD, EquationSystemSharedPtr > m_equ
Equation system to solve.
Definition: Driver.h:97
int m_nequ
number of equations
Definition: Driver.h:100
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
static const NekDouble kNekUnsetDouble
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
Definition: MeshGraph.h:172
std::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:59
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1255
scalarT< T > log(scalarT< T > in)
Definition: scalar.hpp:303