51#include <boost/format.hpp>
61 session->MatchSolverInfo(
"Homogeneous",
"1D", isH1d,
false);
62 session->MatchSolverInfo(
"Homogeneous",
"2D", isH2d,
false);
63 bool singleMode, halfMode;
64 session->MatchSolverInfo(
"ModeType",
"SingleMode", singleMode,
false);
65 session->MatchSolverInfo(
"ModeType",
"HalfMode", halfMode,
false);
66 if (singleMode || halfMode)
70 int expdim = isH2d ? 1 : pField->GetGraph()->GetMeshDimension();
71 m_spacedim = expdim + (isH1d ? 1 : 0) + (isH2d ? 2 : 0);
72 m_isRoot = pField->GetComm()->TreatAsRankZero();
77 TiXmlElement *pSolver = session->GetElement(
"Nektar/RIGIDSOLVER");
104 else if (nFreeTrans == 1 && freeX)
112 else if ((nFreeTrans == 2 || nFreeTrans == 0) &&
m_hasRotation)
118 ASSERTL0(
false,
"Unsupported rigid motion: this solver supports only "
119 "(i) translation-only motion, "
120 "(ii) x-only translation with optional rotation, or "
121 "(iii) full planar rigid-body motion.");
128 for (
size_t i = 0; i <
m_K.size(); ++i)
132 for (
size_t i = 0; i <
m_C.size(); ++i)
137 "C, K should be zero [in body frame solver].");
147 moveDoFs[it.first] =
true;
165 if (moveDoFs[0] || moveDoFs[1])
182 catch (
const std::runtime_error &)
191 const std::string &FuncName,
const std::string &var,
192 std::map<int, LibUtilities::EquationSharedPtr> &result,
const int i)
194 if (session->DefinesFunction(FuncName, var))
197 session->GetFunction(FuncName, var);
198 if (allowzero ||
"0" != equ->GetExpression())
207 const TiXmlElement *pSolver)
209 const TiXmlElement *funcNameElmt;
211 funcNameElmt = pSolver->FirstChildElement(
"FRAMEVELOCITY");
214 std::string FuncName = funcNameElmt->GetText();
215 ASSERTL0(session->DefinesFunction(FuncName),
216 "Function '" + FuncName +
"' is not defined in the session.");
220 std::string var = session->GetVariable(i);
225 std::vector<std::string> linearDispVar = {
"X",
"Y",
"Z"};
226 std::vector<std::string> linearAcceVar = {
"A_x",
"A_y",
"A_z"};
235 std::vector<std::string> angularVar = {
"Omega_x",
"Omega_y",
"Omega_z"};
237 for (
int i = 0; i < 3; ++i)
239 std::string var = angularVar[i];
246 std::vector<std::string> angularDispVar = {
"Theta_x",
"Theta_y",
248 std::vector<std::string> angularAccepVar = {
"DOmega_x",
"DOmega_y",
250 for (
int i = 0; i < 3; ++i)
260 funcNameElmt = pSolver->FirstChildElement(
"EXTERNALFORCE");
263 std::string FuncName = funcNameElmt->GetText();
264 if (session->DefinesFunction(FuncName))
266 std::vector<std::string> forceVar = {
"Fx",
"Fy",
"Fz"};
269 std::string var = forceVar[i];
273 std::vector<std::string> momentVar = {
"Mx",
"My",
"Mz"};
274 for (
int i = 0; i < 3; ++i)
276 std::string var = momentVar[i];
284 const TiXmlElement *mssgTag = pSolver->FirstChildElement(
"OutputFile");
285 std::string filename;
288 filename = mssgTag->GetText();
292 filename = session->GetSessionName();
294 if (!(filename.length() >= 4 &&
295 filename.substr(filename.length() - 4) ==
".mrf"))
305 <<
"Variables = t, x, ux, ax, y, uy, ay, theta, omega, domega"
310 m_outputStream <<
"Variables = t, x, ux, ax, y, uy, ay, z, uz, az, "
311 "theta, omega, domega"
318 mssgTag = pSolver->FirstChildElement(
"OutputFrequency");
321 std::vector<std::string> values;
322 std::string mssgStr = mssgTag->GetText();
326 "OutputFrequency should be greater than zero.");
334 const TiXmlElement *mssgTag;
338 for (
size_t i = 0; i < 3; ++i)
344 for (
int i = 0; i < NumDof; ++i)
348 mssgTag = pSolver->FirstChildElement(
"MOTIONPRESCRIBED");
351 std::vector<std::string> values;
352 mssgStr = mssgTag->GetText();
355 "MOTIONPRESCRIBED vector should be of size " +
356 std::to_string(NumDof));
357 for (
int i = 0; i < NumDof; ++i)
370 mssgTag = pSolver->FirstChildElement(
"MASS");
374 std::vector<std::string> values;
375 mssgStr = mssgTag->GetText();
377 ASSERTL0(values.size() == 1,
"Mass matrix should be a scalar.");
384 mssgTag = pSolver->FirstChildElement(
"ROTATIONINERTIA");
387 std::vector<std::string> values;
388 mssgStr = mssgTag->GetText();
390 ASSERTL0(values.size() == 1,
"Inertia should be a scalar.");
396 mssgTag = pSolver->FirstChildElement(
"DAMPING");
399 std::vector<std::string> values;
400 mssgStr = mssgTag->GetText();
402 ASSERTL0(values.size() == NumDof * NumDof,
403 "Damping matrix should be of size " + std::to_string(NumDof) +
404 "X" + std::to_string(NumDof));
406 for (
int i = 0; i < NumDof; ++i)
408 for (
int j = 0; j < NumDof; ++j)
417 mssgTag = pSolver->FirstChildElement(
"RIGIDITY");
420 std::vector<std::string> values;
421 mssgStr = mssgTag->GetText();
423 ASSERTL0(values.size() == NumDof * NumDof,
424 "Rigidity matrix should be of size " + std::to_string(NumDof) +
425 "X" + std::to_string(NumDof));
427 for (
int i = 0; i < NumDof; ++i)
429 for (
int j = 0; j < NumDof; ++j)
437 mssgTag = pSolver->FirstChildElement(
"PIVOTPOINT");
441 std::vector<std::string> values;
442 mssgStr = mssgTag->GetText();
445 "PIVOTPOINT vector should be of size " +
454 mssgTag = pSolver->FirstChildElement(
"PIVOTDISTANCE");
458 std::vector<std::string> values;
459 mssgStr = mssgTag->GetText();
461 ASSERTL0(values.size() == 1,
"PivotDistance should be a scalar.");
465 m_timestep = session->GetParameter(
"TimeStep");
468 if (session->DefinesParameter(
"NewmarkBeta"))
470 m_beta = session->GetParameter(
"NewmarkBeta");
472 if (session->DefinesParameter(
"NewmarkGamma"))
474 m_gamma = session->GetParameter(
"NewmarkGamma");
479 std::map<int, NekDouble> &Dirs)
486 Dirs[it.first] = it.second->Evaluate(0., 0., 0., time);
488 else if (it.first == 5)
490 Dirs[
m_spacedim] = it.second->Evaluate(0., 0., 0., time);
492 else if (it.first < 9)
494 Dirs[NumDof + it.first - 6] = it.second->Evaluate(0., 0., 0., time);
496 else if (it.first == 11)
498 Dirs[NumDof +
m_spacedim] = it.second->Evaluate(0., 0., 0., time);
500 else if (it.first < 15)
502 Dirs[(NumDof << 1) + it.first - 12] =
503 it.second->Evaluate(0., 0., 0., time);
505 else if (it.first == 17)
508 it.second->Evaluate(0., 0., 0., time);
513 if (Dirs.find(i) == Dirs.end())
516 Dirs[i + NumDof] = 0.;
517 Dirs[i + (NumDof << 1)] = 0.;
524 for (
int i = 0; i < 6; ++i)
544 for (
int i = 0; i < 6; ++i)
551 std::map<int, NekDouble> Dirs;
558 m_extForceXYZ[it.first] = it.second->Evaluate(0., 0., 0., time);
567 for (
size_t i = 0; i <
m_vel.size(); ++i)
577 tmpVel[2][0] -= tmpVel[1][
m_spacedim] * tmpVel[1][1];
578 tmpVel[2][1] += tmpVel[1][
m_spacedim] * tmpVel[1][0];
593 for (
size_t i = 0; i < tmpVel[0].size(); ++i)
596 << boost::format(
"%25.19e") % tmpVel[1][i] <<
" "
597 << boost::format(
"%25.19e") % tmpVel[2][i] <<
" ";
613 for (
int i = 0; i < 18; ++i)
625 MRFData[0] =
m_vel[0][0];
626 MRFData[1] =
m_vel[0][1];
636 MRFData[i + 6] =
m_vel[1][i];
637 MRFData[i + 12] =
m_vel[2][i];
649 std::map<int, NekDouble> &Dirs)
665 ASSERTL0(
false,
"Unsupported rigid solver type.");
691 std::map<int, NekDouble> &Dirs)
695 if (Dirs.find(1) != Dirs.end())
707 force[i] = forcebody[i] + force[i];
718 std::map<int, NekDouble> &Dirs)
728 bodyVel[2][0] += bodyVel[1][
m_spacedim] * bodyVel[1][1];
729 bodyVel[2][1] -= bodyVel[1][
m_spacedim] * bodyVel[1][0];
740 force[i] = forcebody[i] + force[i];
751 for (
size_t i = 0; i < bodyVel.size(); ++i)
754 Vmath::Vcopy(bodyVel[i].size(), bodyVel[i], 1, tmpbodyVel[i], 1);
756 for (
int iter = 0; iter < 2; ++iter)
760 for (
size_t i = 0; i < bodyVel.size(); ++i)
771 force[i] = forcebody[i] + force[i];
777 for (
size_t i = 0; i < bodyVel.size(); ++i)
779 Vmath::Vcopy(bodyVel[i].size(), tmpbodyVel[i], 1, bodyVel[i], 1);
807 rhs[i] +=
m_M[i][j] * bm[j] -
m_K[i][j] * bk[j];
812 rhs[i] -=
m_M[i][j] * u[2][j1] +
m_C[i][j] * u[1][j1] +
813 m_K[i][j] * u[0][j1];
824 dMatrix[1] += mass * u[1][
m_rows - 1];
840 u[0][j1] =
m_coeffs[2] * u[1][j1] + bk[j];
841 u[2][j1] =
m_coeffs[0] * u[1][j1] - bm[j];
852 if (AddedMass.size() >= NumDof * NumDof)
865 std::map<std::string, std::string> fieldMetaDataMap;
866 std::vector<std::string> strFrameData = {
867 "X",
"Y",
"Z",
"Theta_x",
"Theta_y",
"Theta_z",
868 "U",
"V",
"W",
"Omega_x",
"Omega_y",
"Omega_z",
869 "A_x",
"A_y",
"A_z",
"DOmega_x",
"DOmega_y",
"DOmega_z"};
870 std::map<std::string, NekDouble> fileData;
871 if (session->DefinesFunction(
"InitialConditions"))
873 for (
int i = 0; i < session->GetVariables().size(); ++i)
875 if (session->GetFunctionType(
"InitialConditions",
876 session->GetVariable(i)) ==
879 std::string filename = session->GetFunctionFilename(
880 "InitialConditions", session->GetVariable(i));
881 fs::path pfilename(filename);
883 if (fs::is_directory(pfilename))
885 fs::path metafile(
"Info.xml");
886 fs::path fullpath = pfilename / metafile;
891 fld->ImportFieldMetaData(filename, fieldMetaDataMap);
896 if (fieldMetaDataMap.find(
"Time") != fieldMetaDataMap.end())
898 time = std::stod(fieldMetaDataMap[
"Time"]);
901 for (
auto &var : strFrameData)
903 if (fieldMetaDataMap.find(var) !=
904 fieldMetaDataMap.end())
906 fileData[var] = std::stod(fieldMetaDataMap[var]);
909 if (fileData.size() == strFrameData.size())
917 if (session->DefinesCmdLineArgument(
"set-start-time"))
920 session->GetCmdLineArgument<std::string>(
"set-start-time"));
922 if (fileData.size() == strFrameData.size())
924 int NumDofm1 =
m_vel[0].size() - 1;
927 m_vel[0][i] = fileData[strFrameData[i]];
928 m_vel[1][i] = fileData[strFrameData[i + 6]];
929 m_vel[2][i] = fileData[strFrameData[i + 12]];
931 m_vel[0][NumDofm1] = fileData[strFrameData[5]];
932 m_vel[1][NumDofm1] = fileData[strFrameData[11]];
933 m_vel[2][NumDofm1] = fileData[strFrameData[17]];
940 std::map<int, NekDouble> Dirs;
951 for (
size_t i = 0; i <
m_vel.size(); ++i)
962 tmpVel[2][0] -= tmpVel[1][
m_spacedim] * tmpVel[1][1];
963 tmpVel[2][1] += tmpVel[1][
m_spacedim] * tmpVel[1][0];
972 for (
size_t i = 0; i < tmpVel[0].size(); ++i)
975 << boost::format(
"%25.19e") % tmpVel[1][i] <<
" "
976 << boost::format(
"%25.19e") % tmpVel[2][i] <<
" ";
984 std::map<std::string, std::string> &vParams)
986 TiXmlElement *pForce = session->GetElement(
"Nektar/RIGIDSOLVER");
987 const TiXmlElement *param = pForce->FirstChildElement(
"BOUNDARY");
988 ASSERTL0(param,
"Body surface should be assigned");
990 vParams[
"Boundary"] = param->GetText();
991 const TiXmlElement *pivotElmt = pForce->FirstChildElement(
"PIVOTPOINT");
994 std::string pstr = pivotElmt->GetText();
995 std::replace(pstr.begin(), pstr.end(),
',',
' ');
996 vParams[
"MomentPoint"] = pstr;
1002 for (
auto it : Dirs)
1004 int NumDof =
m_vel[0].size();
1005 int NumDof2 = NumDof << 1;
1006 if (it.first <
m_vel[0].size())
1008 m_vel[1][it.first] = it.second;
1010 else if (it.first < NumDof2)
1012 m_vel[0][it.first - NumDof] = it.second;
1016 m_vel[2][it.first - NumDof2] = it.second;
1025 std::set<int> DirDoFs,
int solveType)
1037 for (
int i = 0; i <
m_rows; ++i)
1039 if (DirDoFs.find(i) == DirDoFs.end())
1046 if (DirDoFs.find(i) != DirDoFs.end())
1054 "2 Dofs if body is free only in x direction.");
1071 for (
int j = 0; j <
m_rows; ++j)
1073 int ind = offset +
m_index[j];
1081 inverseMatrix->SetValue(i, j, value);
1089 inverseMatrix->Invert();
1094 for (
int j = 0; j <
m_rows; ++j)
1098 m_Matrix[i][j] = inverseMatrix->GetValue(i, j);
1107 std::map<int, NekDouble> motionPrescribed)
1109 for (
int i = 0; i <
m_rows; ++i)
1111 if (motionPrescribed.find(i) != motionPrescribed.end())
1116 if (motionPrescribed.find(i2) == motionPrescribed.end())
1120 if (motionPrescribed.find(i0) == motionPrescribed.end())
1125 u[1][i] = motionPrescribed[i];
1126 if (motionPrescribed.find(i2) == motionPrescribed.end())
1128 u[2][i] =
m_coeffs[0] * u[1][i] - bm;
1132 u[2][i] = motionPrescribed[i2];
1134 if (motionPrescribed.find(i0) == motionPrescribed.end())
1136 u[0][i] =
m_coeffs[2] * u[1][i] + bk;
1140 u[0][i] = motionPrescribed[i0];
1165 rhs[i] +=
m_M[i][j] * bm[j] -
m_K[i][j] * bk[j];
1170 rhs[i] -=
m_M[i][j] * u[2][j1] +
m_C[i][j] * u[1][j1] +
1171 m_K[i][j] * u[0][j1];
1178 u[0][j1] =
m_coeffs[2] * u[1][j1] + bk[j];
1179 u[2][j1] =
m_coeffs[0] * u[1][j1] - bm[j];
1198 NekDouble c = cos(theta[2]), s = sin(theta[2]);
1199 NekDouble C00, C01, C10, C11, M0, M1, M2, F0, F1;
1200 M0 = c *
m_M[0][0] - s *
m_M[1][0];
1201 M1 = c *
m_M[0][1] - s *
m_M[1][1];
1202 M2 = c *
m_M[0][iOmega] - s *
m_M[1][iOmega];
1203 C00 =
m_coeffs[0] * M0 - s * u[1][iOmega] * mass;
1204 C01 =
m_coeffs[0] * M1 - c * u[1][iOmega] * mass;
1216 F0 = c * force[0] - s * force[1];
1217 F0 = F0 + M0 * bm[0] + M1 * bm[1] - M2 * u[2][iOmega];
1219 NekDouble det = 1. / (C00 * C11 - C01 * C10);
1220 u[1][0] = det * (C11 * F0 - C01 * F1);
1221 u[1][1] = det * (-C10 * F0 + C00 * F1);
1224 u[0][j] =
m_coeffs[2] * u[1][j] + bk[j];
1225 u[2][j] =
m_coeffs[0] * u[1][j] - bm[j];
1247 if (body != inertial && dim > 2)
1249 for (
int i = 2; i < dim; ++i)
1251 inertial[i] = body[i];
1260 NekDouble x = inertial[0], y = inertial[1];
1263 if (body != inertial && dim > 2)
1265 for (
int i = 2; i < dim; ++i)
1267 body[i] = inertial[i];
#define ASSERTL0(condition, msg)
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
NekDouble Evaluate() const
static std::shared_ptr< FieldIO > CreateForFile(const LibUtilities::SessionReaderSharedPtr session, const std::string &filename)
Construct a FieldIO object for a given input filename.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
Array< OneD, Array< OneD, NekDouble > > m_M
Array< OneD, Array< OneD, NekDouble > > m_Matrix
void SolveFreeVarMat(Array< OneD, Array< OneD, NekDouble > > u, Array< OneD, NekDouble > force, const NekDouble mass)
void SolveOneFree(Array< OneD, Array< OneD, NekDouble > > u, Array< OneD, NekDouble > force, const Array< OneD, NekDouble > theta, const NekDouble uy, const NekDouble mass)
void SolveFreeFixMat(Array< OneD, Array< OneD, NekDouble > > u, Array< OneD, NekDouble > force)
Array< OneD, NekDouble > m_coeffs
std::vector< int > m_index
Array< OneD, Array< OneD, NekDouble > > m_C
Array< OneD, Array< OneD, NekDouble > > m_K
void SetNewmarkBeta(NekDouble beta, NekDouble gamma, NekDouble dt, Array< OneD, NekDouble > M, Array< OneD, NekDouble > C, Array< OneD, NekDouble > K, std::set< int > DirDoFs, int solveType)
void SolvePrescribed(Array< OneD, Array< OneD, NekDouble > > u, std::map< int, NekDouble > motionPrescribed)
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
Array< OneD, NekDouble > m_pivot
void UpdateMRFData(Array< OneD, NekDouble > &MRFData)
void ParserFunctionToMap(const bool allowzero, const LibUtilities::SessionReaderSharedPtr session, const std::string &FuncName, const std::string &var, std::map< int, LibUtilities::EquationSharedPtr > &result, const int i)
Array< OneD, NekDouble > m_C
void LoadParameters(const LibUtilities::SessionReaderSharedPtr session, const TiXmlElement *pSolver)
Newmark_BetaSolver m_bodySolver
NekDouble m_pivotdistance
std::set< int > m_dirDoFs
Array< OneD, NekDouble > m_inertialPosition
void SetNewmarkBetaSolver(Array< OneD, NekDouble > &AddedMass)
void UpdatePrescribed(const NekDouble &time, std::map< int, NekDouble > &Dirs)
NekDouble EvaluateExpression(const LibUtilities::SessionReaderSharedPtr session, std::string expression)
void InitBodySolver(const LibUtilities::SessionReaderSharedPtr session, const TiXmlElement *pSolver, Array< OneD, NekDouble > pivot)
Array< OneD, NekDouble > m_K
NekDouble m_rotaionInertia
void SolveBodyFrame(Array< OneD, Array< OneD, NekDouble > > &bodyVel, const Array< OneD, NekDouble > &forcebody, std::map< int, NekDouble > &Dirs)
void InitObject(const LibUtilities::SessionReaderSharedPtr session, const MultiRegions::ExpListSharedPtr &pField, Array< OneD, NekDouble > pivot)
void SetMovableDoFs(std::vector< bool > &moveDoFs)
std::ofstream m_outputStream
std::map< int, LibUtilities::EquationSharedPtr > m_frameVelFunction
void SetOldFvis(Array< OneD, NekDouble > force)
Array< OneD, NekDouble > m_M
void SetInitialConditions(const LibUtilities::SessionReaderSharedPtr session, Array< OneD, NekDouble > MRFData)
void SolveInertialFrame(Array< OneD, Array< OneD, NekDouble > > &bodyVel, const Array< OneD, NekDouble > &forcebody, std::map< int, NekDouble > &Dirs)
void GetFilterInfo(const LibUtilities::SessionReaderSharedPtr session, std::map< std::string, std::string > &vParams)
Array< OneD, Array< OneD, NekDouble > > m_vel
std::map< int, LibUtilities::EquationSharedPtr > m_extForceFunction
Array< OneD, NekDouble > m_oldFvis
Array< OneD, NekDouble > m_extForceXYZ
void SolveBodyMotion(Array< OneD, Array< OneD, NekDouble > > &bodyVel, const Array< OneD, NekDouble > &forcebody, std::map< int, NekDouble > &Dirs)
void SolveRotOneFree(Array< OneD, Array< OneD, NekDouble > > &bodyVel, const Array< OneD, NekDouble > &forcebody, std::map< int, NekDouble > &Dirs)
void UpdateFrameVelocity(Array< OneD, NekDouble > &aeroforce, const NekDouble &time, Array< OneD, NekDouble > &MRFData)
Updates the forcing array with the current required forcing.
static void Dgetrs(const char &trans, const int &n, const int &nrhs, const double *a, const int &lda, int *ipiv, double *b, const int &ldb, int &info)
General matrix LU backsolve.
static void DoSgetrf(const int &m, const int &n, double *a, const int &lda, int *ipiv, int &info)
General matrix LU factorisation.
std::shared_ptr< FieldIO > FieldIOSharedPtr
static std::string PortablePath(const fs::path &path)
create portable path on different platforms for std::filesystem path.
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Equation > EquationSharedPtr
static FieldMetaDataMap NullFieldMetaDataMap
@ beta
Gauss Radau pinned at x=-1,.
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
static const NekDouble kNekZeroTol
std::shared_ptr< DNekMat > DNekMatSharedPtr
T Dot(int n, const T *w, const T *x)
dot product
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
scalarT< T > sqrt(scalarT< T > in)