38#include <boost/core/ignore_unused.hpp>
73 m_equ[0]->PrintSummary(out);
76 if (
m_comm->GetRank() == 0)
78 out <<
"\tArnoldi solver type : Modified Arnoldi" << endl;
83 for (
int i = 0; i <
m_nequ; ++i)
85 m_equ[i]->DoInitialise();
99 int nq =
m_equ[0]->UpdateFields()[0]->GetNcoeffs();
104 std::string evlFile =
m_session->GetSessionName() +
".evl";
106 if (
m_comm->GetRank() == 0)
108 evlout.open(evlFile.c_str());
123 for (i = 0; i <
m_kdim + 1; ++i)
132 Kseqcopy[i] = Kseq[i];
138 if (
m_session->DefinesFunction(
"InitialConditions"))
140 if (
m_comm->GetRank() == 0)
142 out <<
"\tInital vector : specified in input file " << endl;
144 m_equ[0]->SetInitialConditions(0.0,
false);
150 if (
m_comm->GetRank() == 0)
152 out <<
"\tInital vector : random " << endl;
166 if (
m_comm->GetRank() == 0)
168 out <<
"Iteration: " << 0 << endl;
176 alpha[0] =
Blas::Ddot(ntot, &Kseqcopy[0][0], 1, &Kseqcopy[0][0], 1);
179 Vmath::Smul(ntot, 1.0 / alpha[0], Kseq[0], 1, Kseq[0], 1);
183 for (i = 1; !converged && i <=
m_kdim; ++i)
193 alpha[i] =
Blas::Ddot(ntot, &Kseqcopy[i][0], 1, &Kseqcopy[i][0], 1);
198 Vmath::Smul(ntot, 1.0 / alpha[i], Kseq[i], 1, Kseq[i], 1);
201 for (
int k = 0; k < i + 1; ++k)
216 EV_small(Tseq, Kseqcopy, ntot, alpha, i, zvec, wr, wi, resnorm);
219 converged =
EV_test(i, i, zvec, wr, wi, resnorm, std::min(i,
m_nvec),
223 converged = max(converged, 0);
230 if (
m_comm->GetRank() == 0)
232 out <<
"Iteration: " << i <<
" (residual : " << resid0 <<
")"
244 for (
int j = 1; j <=
m_kdim; ++j)
246 alpha[j - 1] = alpha[j];
267 for (
int k = 0; k <
m_kdim + 1; ++k)
289 if (
m_comm->GetRank() == 0)
291 out <<
"Iteration: " << i <<
" (residual : " << resid0 <<
")"
303 for (j = 0; j <
m_equ[0]->GetNvariables(); ++j)
307 if (
m_comm->GetRank() == 0)
309 out <<
"L 2 error (variable " <<
m_equ[0]->GetVariable(j)
310 <<
") : " << vL2Error << endl;
311 out <<
"L inf error (variable " <<
m_equ[0]->GetVariable(j)
312 <<
") : " << vLinfError << endl;
322 "Need to implement Ritz re-evaluation of"
323 "eigenvalue. Only one half of complex "
324 "value will be correct");
331 if (
m_comm->GetRank() == 0)
345 m_equ[0]->TransCoeffToPhys();
347 m_equ[0]->SetTime(0.);
353 fields =
m_equ[0]->UpdateFields();
357 m_equ[1]->TransCoeffToPhys();
359 m_equ[1]->SetTime(0.);
378 int kdimp = kdim + 1;
379 int lwork = 10 * kdim;
386 for (
int i = 0; i < kdimp; ++i)
391 ASSERTL0(gsc != 0.0,
"Vectors are linearly independent.");
393 R[i * kdimp + i] = gsc;
394 Vmath::Smul(ntot, 1.0 / gsc, Kseq[i], 1, Kseq[i], 1);
397 Vmath::Smul(ntot, 1.0 / gsc, Kseqcopy[i], 1, Kseqcopy[i], 1);
400 for (
int j = i + 1; j < kdimp; ++j)
402 gsc =
Blas::Ddot(ntot, &Kseq[i][0], 1, &Kseq[j][0], 1);
404 Vmath::Svtvp(ntot, -gsc, Kseq[i], 1, Kseq[j], 1, Kseq[j], 1);
407 Vmath::Svtvp(ntot, -gsc, Kseqcopy[i], 1, Kseqcopy[j], 1,
410 R[j * kdimp + i] = gsc;
415 for (
int i = 0; i < kdim; ++i)
417 for (
int j = 0; j < kdim; ++j)
420 alpha[j + 1] * R[(j + 1) * kdimp + i] -
421 Vmath::Dot(j, &H[0] + i, kdim, &R[0] + j * kdimp, 1);
422 H[j * kdim + i] /= R[j * kdimp + j];
426 H[(kdim - 1) * kdim + kdim] =
428 std::fabs(R[kdim * kdimp + kdim] / R[(kdim - 1) * kdimp + kdim - 1]);
430 Lapack::dgeev_(
'N',
'V', kdim, &H[0], kdim, &wr[0], &wi[0], 0, 1, &zvec[0],
431 kdim, &rwork[0], lwork, ier);
435 resnorm = H[(kdim - 1) * kdim + kdim];
452 for (
int i = 0; i < kdim; ++i)
455 Vmath::Dot(kdim, &zvec[0] + i * kdim, 1, &zvec[0] + i * kdim, 1));
456 resid[i] = resnorm * std::fabs(zvec[kdim - 1 + i * kdim]) / tmp;
459 resid[i - 1] = resid[i] = hypot(resid[i - 1], resid[i]);
463 EV_sort(zvec, wr, wi, resid, kdim);
465 while (nvec <= kdim && resid[nvec - 1] <
m_evtol)
472 if (
m_comm->GetRank() == 0)
474 evlout <<
"-- Iteration = " << itrn <<
", H(k+1, k) = " << resnorm
477 evlout.setf(ios::scientific, ios::floatfield);
480 evlout <<
" Magnitude Angle Growth "
481 <<
"Frequency Residual" << endl;
485 evlout <<
" Real Imaginary inverse real "
486 <<
"inverse imag Residual" << endl;
489 for (
int i = 0; i < kdim; i++)
491 WriteEvs(evlout, i, wr[i], wi[i], resid[i]);
495 resid0 = resid[nvec - 1];
509 for (
int j = 1; j < dim; ++j)
516 while (i >= 0 &&
test[i] > te_tmp)
521 Vmath::Vcopy(dim, &evec[0] + i * dim, 1, &evec[0] + (i + 1) * dim,
527 test[i + 1] = te_tmp;
528 Vmath::Vcopy(dim, &z_tmp[0], 1, &evec[0] + (i + 1) * dim, 1);
539 const int ntot,
const int kdim,
548 ASSERTL0(
false,
"Convergence was not achieved within the "
549 "prescribed number of iterations.");
554 ASSERTL0(
false,
"Minimum residual reached.");
556 else if (icon == nvec)
559 EV_big(Tseq, Kseq, ntot, kdim, icon, zvec, wr, wi);
561 m_equ[0]->UpdateFields();
563 for (
int j = 0; j < icon; ++j)
565 std::string file =
m_session->GetSessionName() +
"_eig_" +
566 boost::lexical_cast<std::string>(j) +
".fld";
568 if (
m_comm->GetRank() == 0)
575 std::string fileunmask =
576 m_session->GetSessionName() +
"_eig_masked_" +
577 boost::lexical_cast<std::string>(j) +
".fld";
585 ASSERTL0(
false,
"Unrecognised value.");
594 const int ntot,
const int kdim,
599 boost::ignore_unused(wr);
604 for (
int i = 0; i < nvec; ++i)
618 for (
int j = 0; j < nvec; ++j)
625 for (
int i = 0; i < kdim; ++i)
627 wgt = zvec[i + j * kdim];
628 Vmath::Svtvp(ntot, wgt, bvecs[i], 1, btmp[j], 1, btmp[j], 1);
631 Vmath::Svtvp(ntot, wgt, evecs[i], 1, etmp[j], 1, etmp[j], 1);
637 for (
int i = 0; i < nvec; ++i)
641 if (
m_session->GetComm()->GetRank() == 0)
643 cout <<
"eigenvalue " << i <<
": real mode" << endl;
645 norm =
Blas::Ddot(ntot, &btmp[i][0], 1, &btmp[i][0], 1);
650 Vmath::Smul(ntot, 1.0 / norm, btmp[i], 1, bvecs[i], 1);
651 Vmath::Smul(ntot, 1.0 / norm, etmp[i], 1, evecs[i], 1);
655 Vmath::Smul(ntot, 1.0 / norm, btmp[i], 1, evecs[i], 1);
660 if (
m_session->GetComm()->GetRank() == 0)
662 cout <<
"eigenvalues " << i <<
", " << i + 1
663 <<
": complex modes" << endl;
665 norm =
Blas::Ddot(ntot, &btmp[i][0], 1, &btmp[i][0], 1);
666 norm +=
Blas::Ddot(ntot, &btmp[i + 1][0], 1, &btmp[i + 1][0], 1);
672 Vmath::Smul(ntot, 1.0 / norm, btmp[i], 1, bvecs[i], 1);
673 Vmath::Smul(ntot, 1.0 / norm, btmp[i + 1], 1, bvecs[i + 1], 1);
674 Vmath::Smul(ntot, 1.0 / norm, etmp[i], 1, evecs[i], 1);
675 Vmath::Smul(ntot, 1.0 / norm, etmp[i + 1], 1, evecs[i + 1], 1);
679 Vmath::Smul(ntot, 1.0 / norm, btmp[i], 1, evecs[i], 1);
680 Vmath::Smul(ntot, 1.0 / norm, btmp[i + 1], 1, evecs[i + 1], 1);
#define ASSERTL0(condition, msg)
#define WARNINGL0(condition, msg)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
static std::string RegisterEnumValue(std::string pEnum, std::string pString, int pEnumValue)
Registers an enumeration value.
Base class for the development of solvers.
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.
Array< OneD, NekDouble > m_maskCoeffs
void CopyFieldToArnoldiArray(Array< OneD, NekDouble > &array)
Copy fields to Arnoldi storage.
int m_nvec
Dimension of Krylov subspace.
bool m_timeSteppingAlgorithm
Period of time stepping algorithm.
int m_nits
Number of vectors to test.
Array< OneD, NekDouble > m_imag_evl
void CopyArnoldiArrayToField(Array< OneD, NekDouble > &array)
Copy Arnoldi storage to fields.
NekDouble m_evtol
Maxmum number of iterations.
int m_nfields
interval to dump information if required.
SOLVER_UTILS_EXPORT void ArnoldiSummary(std::ostream &out)
Array< OneD, NekDouble > m_real_evl
Operator in solve call is negated.
void WriteEvs(std::ostream &evlout, const int k, const NekDouble real, const NekDouble imag, NekDouble resid=NekConstants::kNekUnsetDouble, bool DumpInverse=true)
LibUtilities::SessionReaderSharedPtr m_session
Session reader object.
LibUtilities::CommSharedPtr m_comm
Communication object.
enum EvolutionOperatorType m_EvolutionOperator
Evolution Operator.
Array< OneD, EquationSystemSharedPtr > m_equ
Equation system to solve.
int m_nequ
number of equations
void EV_update(Array< OneD, NekDouble > &src, Array< OneD, NekDouble > &tgt)
Generates a new vector in the sequence by applying the linear operator.
void EV_post(Array< OneD, Array< OneD, NekDouble > > &Tseq, Array< OneD, Array< OneD, NekDouble > > &Kseq, const int ntot, const int kdim, const int nvec, Array< OneD, NekDouble > &zvec, Array< OneD, NekDouble > &wr, Array< OneD, NekDouble > &wi, const int icon)
int EV_test(const int itrn, const int kdim, Array< OneD, NekDouble > &zvec, Array< OneD, NekDouble > &wr, Array< OneD, NekDouble > &wi, const NekDouble resnorm, int nvec, std::ofstream &evlout, NekDouble &resid0)
Tests for convergence of eigenvalues of H.
void EV_small(Array< OneD, Array< OneD, NekDouble > > &Kseq, Array< OneD, Array< OneD, NekDouble > > &Kseqcopy, const int ntot, const Array< OneD, NekDouble > &alpha, const int kdim, Array< OneD, NekDouble > &zvec, Array< OneD, NekDouble > &wr, Array< OneD, NekDouble > &wi, NekDouble &resnorm)
Generates the upper Hessenberg matrix H and computes its eigenvalues.
void EV_sort(Array< OneD, NekDouble > &evec, Array< OneD, NekDouble > &wr, Array< OneD, NekDouble > &wi, Array< OneD, NekDouble > &test, const int dim)
Sorts a sequence of eigenvectors/eigenvalues by magnitude.
static std::string driverLookupId
static DriverSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const SpatialDomains::MeshGraphSharedPtr &pGraph)
Creates an instance of this class.
DriverModifiedArnoldi(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 className
Name of the class.
virtual void v_Execute(std::ostream &out=std::cout) override
Virtual function for solve implementation.
void EV_big(Array< OneD, Array< OneD, NekDouble > > &bvecs, Array< OneD, Array< OneD, NekDouble > > &evecs, const int ntot, const int kdim, const int nvec, Array< OneD, NekDouble > &zvec, Array< OneD, NekDouble > &wr, Array< OneD, NekDouble > &wi)
static double Ddot(const int &n, const double *x, const int &incx, const double *y, const int &incy)
BLAS level 1: output = .
std::shared_ptr< SessionReader > SessionReaderSharedPtr
DriverFactory & GetDriverFactory()
std::shared_ptr< MeshGraph > MeshGraphSharedPtr
The above copyright notice and this permission notice shall be included.
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
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
T Dot(int n, const T *w, const T *x)
dot (vector times vector): z = w*x
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
void Zero(int n, T *x, const int incx)
Zero vector.
void FillWhiteNoise(int n, const T eps, T *x, const int incx, int outseed)
Fills a vector with white noise.
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
scalarT< T > sqrt(scalarT< T > in)