Loading...
Searching...
No Matches
ReducedFsi.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ██╗████████╗██╗ ██╗ █████╗ ██████╗ █████╗ ███████╗██╗ ██╗
3 ██║╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██╔════╝██║ ██║
4 ██║ ██║ ███████║███████║██║ ███████║█████╗█████╗ ██║ ██║
5 ██║ ██║ ██╔══██║██╔══██║██║ ██╔══██║╚════╝██╔══╝ ╚██╗ ██╔╝
6 ██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ╚████╔╝
7 ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝
8
9 * In real Time Highly Advanced Computational Applications for Finite Volumes
10 * Copyright (C) 2017 by the ITHACA-FV authors
11-------------------------------------------------------------------------------
12
13License
14 This file is part of ITHACA-FV
15
16 ITHACA-FV is free software: you can redistribute it and/or modify
17 it under the terms of the GNU Lesser General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 ITHACA-FV is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU Lesser General Public License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with ITHACA-FV. If not, see <http://www.gnu.org/licenses/>.
28
29\*---------------------------------------------------------------------------*/
32#include "ReducedFsi.H"
33
34// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * //
35
36// Null Constructor
38
39
41
42{
43 for (int i = 0; i < problem->Umodes.size(); i++)
44 {
45 Umodes.append((problem->Umodes.toPtrList()[i]).clone());
46 }
47
48 for (int i = 0; i < problem->Pmodes.size(); i++)
49 {
50 Pmodes.append((problem->Pmodes.toPtrList()[i]).clone());
51 }
52
53 for (int i = 0; i < problem->Dmodes.size(); i++)
54 {
55 Dmodes.append((problem->Dmodes.toPtrList()[i]).clone());
56 }
57
58 //problem->restart();
59 //Info << "################ ctor of POD-I Fsi ##################" << endl;
60}
61void ReducedFsi::PODI(Eigen::MatrixXd coeffL2, Eigen::MatrixXd muu,
62 label NPdModes)
63{
64 if (NPdModes == 0)
65 {
66 NPdModes = Dmodes.size();
67 }
68
69 problem->samples.resize(NPdModes);
70 problem->rbfSplines.resize(NPdModes);
71 Eigen::MatrixXd weights;
72
73 for (label i = 0; i < NPdModes; i++) // i is the nnumber of th mode
74 {
75 word weightName = "wRBF_M" + name(i + 1);
76
77 if (ITHACAutilities::check_file("./ITHACAoutput/weights/" + weightName))
78 {
79 problem->samples[i] = new SPLINTER::DataTable(true, true);
80
81 for (label j = 0; j < coeffL2.cols();
82 j++) // j is the number of the nut snapshot
83 {
84 problem->samples[i]->addSample(muu.row(j), coeffL2(i, j));
85 }
86
87 ITHACAstream::ReadDenseMatrix(weights, "./ITHACAoutput/weights/", weightName);
88 problem->rbfSplines[i] = new SPLINTER::RBFSpline(*(problem->samples)[i],
89 SPLINTER::RadialBasisFunctionType::THIN_PLATE_SPLINE, weights);
90 Info << "Constructing RadialBasisFunction for mode " << i + 1 << endl;
91 }
92 else
93 {
94 problem->samples[i] = new SPLINTER::DataTable(true, true);
95
96 for (label j = 0; j < coeffL2.cols();
97 j++) // j is the number of the nut snapshot
98 {
99 problem->samples[i]->addSample(muu.row(j), coeffL2(i, j));
100 }
101
102 problem->rbfSplines[i] = new SPLINTER::RBFSpline(*(problem->samples)[i],
103 SPLINTER::RadialBasisFunctionType::THIN_PLATE_SPLINE);
104 ITHACAstream::SaveDenseMatrix(problem->rbfSplines[i]->weights,
105 "./ITHACAoutput/weights/", weightName);
106 Info << "Constructing RadialBasisFunction for mode " << i + 1 << endl;
107 }
108 }
109}
110
111
112
114 int NmodesPproj,
115 int NmodesDproj,
116 fileName folder)
117{
118 Eigen::MatrixXd a = Eigen::VectorXd::Zero(NmodesUproj);
119 Eigen::MatrixXd b = Eigen::VectorXd::Zero(NmodesPproj);
120 Time& runTime = problem->_runTime();
121 dynamicFvMesh& mesh = problem->meshPtr();
122 //const pointMesh& pMesh = pointMesh::New(mesh);
123 fv::options& fvOptions = problem->_fvOptions();
124 pimpleControl& pimple = problem->_pimple();
125 volScalarField& p = problem->_p();
126 volVectorField& U = problem->_U();
127 surfaceScalarField& phi = problem->_phi();
128 pointVectorField& pointDisplacement = problem->_pointDisplacement();//????
129 IOMRFZoneList& MRF = problem->_MRF();
130 singlePhaseTransportModel& laminarTransport = problem->_laminarTransport();
131 //autoPtr<incompressible::turbulenceModel> turbulence = problem->turbulence;
132 autoPtr<incompressible::turbulenceModel> turbulence(
133 incompressible::turbulenceModel::New(U,
134 phi, laminarTransport));
135 instantList Times = runTime.times();
136 runTime.setEndTime(finalTime);
137 PODI(problem->coeffL2, problem->CylDispl, NmodesDproj);
138 runTime.setTime(Times[1], 1);
139 runTime.setDeltaT(timeStep);
140 nextWrite = startTime;
141 label pRefCell = 0;
142 scalar pRefValue = 0.0;
143 bool correctPhi = problem->correctPhi;
144 bool checkMeshCourantNo = problem->checkMeshCourantNo;
145 bool moveMeshOuterCorrectors = problem->moveMeshOuterCorrectors;
146 scalar cumulativeContErr = problem->cumulativeContErr;
147#include "createUfIfPresent.H"
148 turbulence->validate();
149 dictionary dictCoeffs(
150 problem->dyndict->findDict("sixDoFRigidBodyMotionCoeffs"));
151 Foam::functionObjects::forces romforces("romforces", mesh, dictCoeffs);
152 sixDoFRigidBodyMotion sDRBM(dictCoeffs, dictCoeffs, runTime );
153 Foam::dimensionedVector g("g", dimAcceleration, Zero);
154 dictCoeffs.readIfPresent("g", g);
155 // Eigen::VectorXd pdCoeff;
156 // pdCoeff.resize(NmodesDproj);
157 bool firstIter = false;
158 Eigen::MatrixXd pdCoeff(NmodesDproj, 1);
159 //- Current time index (used for updating)
160 label curTimeIndex_ = -1;
161 // pointField points0 = mesh.points();
162 Eigen::MatrixXd muEval(1, 1);
163 //Eigen::VectorXd b_ref = Pmodes.project(p, NmodesPproj);
164 //Eigen::VectorXd a_ref = Umodes.project(U, NmodesUproj);
165 //Info << " ==== b_ref === " << b_ref << endl;
166 //Info << " ==== a_ref === " << a_ref << endl;
167 //exit(0);
168 // double lambda0 = 1.0; // Initial weight
169 // double lambda_t = 0.0;
170 // double alpha = 0.125;
171
172 // PIMPLE algorithm starts here
173 //Info<< "\nStarting time loop\n" << endl;
174 //std::ofstream res_p, res_u;
175 //res_u.open("./res_u", std::ios_base::app);
176 //res_p.open("./res_p", std::ios_base::app);
177 //Errors << "Time, res_u, res_p" << endl;
178 while (runTime.run())
179 {
180 runTime.setEndTime(finalTime);
181 runTime++;
182 //p.storePrevIter();
183 Info << "Time = " << runTime.timeName() << nl << endl;
184 //res_u << runTime.timeName() << endl;
185 //res_p << runTime.timeName() << endl;
186
187 while (pimple.loop())
188 {
189#include "CourantNo.H"
190
191 if (pimple.firstIter() || moveMeshOuterCorrectors)
192 {
193#include"CylinderMotion.H"
194
195 if (mesh.changing())
196 {
197 //MRF.update();
198 if (correctPhi)
199 {
200 // Calculate absolute flux
201 // from the mapped surface velocity
202 phi = mesh.Sf() & Uf();
203 // Make the flux relative to the mesh motion
204 fvc::makeRelative(phi, U);
205 }
206
207 if (checkMeshCourantNo)
208 {
209#include "meshCourantNo.H"
210 }
211 }
212 }
213
214 // Solve the Momentum equation
215 //MRF.correctBoundaryVelocity(U);
216 fvVectorMatrix UEqn
217 (
218 fvm::ddt(U)
219 + fvm::div(phi, U)
220 //+ MRF.DDt(U)
221 + turbulence->divDevReff(U)
222 == fvOptions(U)
223 );
224 //fvVectorMatrix& UEqn = tUEqn.ref();
225 UEqn.relax();
226 fvOptions.constrain(UEqn);
227 List<Eigen::MatrixXd> RedLinSysU;
228
229 if (pimple.momentumPredictor())
230 {
231 //solve(UEqn == -fvc::grad(p));
232 RedLinSysU = Umodes.project(UEqn, NmodesUproj, "G");
233 volVectorField gradpfull = -fvc::grad(p);
234 Eigen::MatrixXd projGrad = Umodes.project(gradpfull, NmodesUproj);
235 RedLinSysU[1] = RedLinSysU[1] + projGrad;
236 //a = RedLinSysU[0].householderQr().solve(RedLinSysU[1]);
237 //Eigen::MatrixXd I_u = 1e-6*Eigen::MatrixXd::Identity(NmodesUproj,NmodesUproj );
238 //a = (RedLinSysU[0] - I_u).ldlt().solve(RedLinSysU[1]);
239 //a=RedLinSysU[0].llt().solve(RedLinSysU[1]);
240 a = RedLinSysU[0].colPivHouseholderQr().solve(RedLinSysU[1]);
241 //a = RedLinSysU[0].completeOrthogonalDecomposition().solve(RedLinSysU[1]);
242 //a=RedLinSysU[0].fullPivLu().solve(RedLinSysU[1]);
243 //Eigen::ConjugateGradient<Eigen::MatrixXd> cg;
244 //cg.setTolerance(1e-6); // Tighter than default (1e-2)
245 //cg.setMaxIterations(300); // Prevent excessive iterations
246 //cg.compute(RedLinSysU[0]);
247 //Eigen::JacobiSVD<Eigen::MatrixXd> svd(RedLinSysU[0]);
248 /*Eigen::JacobiSVD<Eigen::MatrixXd> svd(
249 RedLinSysU[0],
250 Eigen::ComputeThinU | Eigen::ComputeThinV);
251 svd.setThreshold(1e-6); // Truncate small singular values
252 if (svd.rank() < NmodesUproj)
253 {
254 Warning << "Rank-deficient matrix! Rank = " << svd.rank() << endl;
255 }
256 P a = svd.solve(RedLinSysU[1]);*/
257 //Eigen::MatrixXd A_reg = RedLinSysU[0] + 1e-6 *Eigen::MatrixXd::Identity(NmodesUproj, NmodesUproj);
258 //a = A_reg.ldlt().solve(RedLinSysU[1]);
259 //Eigen::MatrixXd aNew = cg.solve(RedLinSysU[1]);
260 //Info << "res_u = " << (RedLinSysU[0] * a - RedLinSysU[1]).norm() << endl;
261 //res_u << (RedLinSysU[0] * a - RedLinSysU[1]).norm() << endl;
262 /*
263 if (cg.info() != Eigen::Success)
264 {
265 Warning << "ROM velocity solve failed. Using previous coefficients." << endl;
266 }*/
267 //lambda_t = lambda0 * std::exp(-alpha * problem->_runTime().value());
268 //Eigen::VectorXd a_cal = (a + lambda_t * a_ref) / (1.0 + lambda_t);
269 //a_ref = a;
270 Umodes.reconstruct(U, a, "U");
271 //U.correctBoundaryConditions();
272 fvOptions.correct(U);
273 //volVectorField errorU = U -problem->Ufield[0];
274 //Info << "errorU= " << errorU.boundaryFieldRef() << endl;
275 //exit(0);
276 }
277
278 // --- Pressure corrector loop
279 while (pimple.correct())
280 {
281 volScalarField rAU(1.0 / UEqn.A());
282 volVectorField HbyA(constrainHbyA(rAU * UEqn.H(), U, p)); //p
283 surfaceScalarField phiHbyA("phiHbyA", fvc::flux(HbyA));
284 tmp<volScalarField> rAtU(rAU);
285 // Update the pressure BCs to ensure flux consistency
286 constrainPressure(p, U, phiHbyA, rAtU(), MRF); //p
287 List<Eigen::MatrixXd> RedLinSysP;
288
289 // Non-orthogonal pressure corrector loop
290 while (pimple.correctNonOrthogonal())
291 {
292 fvScalarMatrix pEqn
293 (
294 fvm::laplacian(rAtU(), p)
295 ==
296 fvc::div(phiHbyA)
297 );
298 pEqn.setReference(pRefCell, pRefValue);
299 //pEqn.solve(mesh.solver(p.select(pimple.finalInnerIter()))); //p
300 RedLinSysP = Pmodes.project(pEqn, NmodesPproj, "G");
302 //b = RedLinSysP[0].householderQr().solve(RedLinSysP[1]);
303 b = RedLinSysP[0].colPivHouseholderQr().solve(RedLinSysP[1]);
304 //b = RedLinSysP[0].ldlt().solve(RedLinSysP[1]);
305 //Eigen::VectorXd b_cal = (b + lambda_t * b_ref) / (1.0 + lambda_t);
306 //b_ref = b;
307 //b =RedLinSysP[0].fullPivLu().solve(RedLinSysP[1]);
308 //Eigen::MatrixXd I_p = 1e-6*Eigen::MatrixXd::Identity(NmodesPproj,NmodesPproj );
309 //b = (RedLinSysP[0] - I_p).ldlt().solve(RedLinSysP[1]);
310 //b = RedLinSysP[0].ldlt().solve(RedLinSysP[1]);
311 // Solve pressure ROM system (with iterative solver)
312 /*
313 Eigen::ConjugateGradient<Eigen::MatrixXd> cgP;
314 cgP.setTolerance(1e-6);
315 cgP.compute(RedLinSysP[0]);
316 Eigen::MatrixXd bNew = cgP.solve(RedLinSysP[1]);*/
317 //Info << "res_p = " << (RedLinSysP[0] * b - RedLinSysP[1]).norm() << endl;
318 //res_p << (RedLinSysP[0] * b - RedLinSysP[1]).norm() << endl;
319 Pmodes.reconstruct(p, b, "p");
320
321 //p.correctBoundaryConditions();
322 //volScalarField errorp = p -problem->Pfield[0] ;
323 //Info << "errorp= " << errorp.internalField() << endl;
324 //exit(0);
325 if (pimple.finalNonOrthogonalIter())
326 {
327 phi = phiHbyA - pEqn.flux();
328 }
329 }
330
331 // Explicitly relax pressure for momentum corrector
332 p.relax();
334 U = HbyA - rAtU * fvc::grad(p); //p
335 U.correctBoundaryConditions();
336 fvOptions.correct(U);
337 //volVectorField error = U -problem->Ufield[0] ;
338 //Info << "Initial error: " << error.internalField() << endl;
339 //exit(0);
340 // Correct Uf if the mesh is moving
341 fvc::correctUf(Uf, U, phi);
342 // Make the fluxes relative to the mesh motion
343 fvc::makeRelative(phi, U);
344 }// end of the pimple.correct()
345 }// end of the pimple.loop()
346
347 if (checkWrite(runTime))
348 {
349 centerofmassy.append(sDRBM.centreOfMass().y());
350 pdcoeffrbf.append(pdCoeff(0, 0));
351 CoeffP.append(b);
352 CoeffU.append(a);
353 romforcey.append(romforces.forceEff().y());
354 romforcex.append(romforces.forceEff().x());
355
356 if (runTime.time().value() + runTime.deltaT().value() >= finalTime)
357 {
358 Info << "===== Storing final mesh =====" << endl;
359 OnlineMeshes.append(problem->meshPtr.ptr()); // Transfer ownership
360 // NOTE: meshPtr is now empty! Handle accordingly.
361 }
362
363 ListOfpoints.append(mesh.points().clone());
364 //std::ofstream of(folder + name(counter) + "/" + runTime.timeName());
365 UredFields.append(U.clone());
366 PredFields.append(p.clone());
367 Dfield.append(pointDisplacement.clone());
368 counter++;
369 nextWrite += writeEvery;
370 }
371 } // end of the runTime.run() loop
372
373 //res_u.close();
374 //res_p.close();
375} // end of the method Solve
376
377
378bool ReducedFsi::checkWrite(Time& timeObject)
379{
380 scalar diffnow = mag(nextWrite - atof(timeObject.timeName().c_str()));
381 scalar diffnext = mag(nextWrite - atof(timeObject.timeName().c_str()) -
382 timeObject.deltaTValue());
383
384 if ( diffnow < diffnext)
385 {
386 return true;
387 }
388 else
389 {
390 return false;
391 }
392}
393
394void ReducedFsi::prepareRomData(const word& outputPath)
395{
396 word fullPath = "./" + outputPath;
397
398 if (!ITHACAutilities::check_folder(fullPath))
399 {
400 mkDir(fullPath);
401 problem->exportFoamFieldToNpy(fullPath, "romforcex", romforcex);
402 problem->exportFoamFieldToNpy(fullPath, "romforcey", romforcey);
403 problem->exportFoamFieldToNpy(fullPath, "CentreOfMassY", centerofmassy);
404 }
405}
void solveOnline_Pimple(int NmodesUproj, int NmodesPproj, int NmodesDproj, fileName folder="./ITHACAoutput/Online/")
Definition ReducedFsi.C:113
fsiBasic * problem
Full problem.
Definition ReducedFsi.H:54
void prepareRomData(const word &outputPath)
Routine to save forces and center of mass.
Definition ReducedFsi.C:394
List< scalar > romforcey
List to save ROM lift and drag forces.
Definition ReducedFsi.H:73
bool checkWrite(Time &timeObject)
Method to save snapshots at a given time.
Definition ReducedFsi.C:378
void PODI(Eigen::MatrixXd coeffL2, Eigen::MatrixXd muu, label NPdModes)
Method to construct PODI.
Definition ReducedFsi.C:61
ReducedFsi()
Construct Null.
Definition ReducedFsi.C:37
volScalarModes Pmodes
The respective modes.
Definition ReducedFsi.H:56
PtrList< dynamicFvMesh > OnlineMeshes
PtrList to save the meshes.
Definition ReducedFsi.H:60
PtrList< pointVectorField > Dfield
List of Online nodes displacement.
Definition ReducedFsi.H:84
List< Eigen::MatrixXd > CoeffU
List of POD coefficients.
Definition ReducedFsi.H:78
Implementation of a parametrized full order unsteady NS problem and preparation of the the reduced ...
Definition fsiBasic.H:76
void ReadDenseMatrix(MatrixType &Matrix, word folder, word MatrixName)
Read a dense matrix from a binary format file.
void SaveDenseMatrix(MatrixType &Matrix, word folder, word MatrixName)
Save a dense matrix to a binary format file.
bool check_folder(word folder)
Checks if a folder exists.
bool check_file(std::string fileName)
Function that returns true if a file exists.