Loading...
Searching...
No Matches
ReducedUnsteadyNS.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\*---------------------------------------------------------------------------*/
30
33
34
35#include "ReducedUnsteadyNS.H"
36
37
38// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * //
39
40// Constructor initialization
44
46 :
47 problem(&FOMproblem)
48{
49 N_BC = problem->inletIndex.rows();
50 Nphi_u = problem->B_matrix.rows();
51 Nphi_p = problem->K_matrix.cols();
52
53 // Create locally the velocity modes
54 for (int k = 0; k < problem->liftfield.size(); k++)
55 {
56 Umodes.append((problem->liftfield[k]).clone());
57 }
58
59 for (int k = 0; k < problem->NUmodes; k++)
60 {
61 Umodes.append((problem->Umodes[k]).clone());
62 }
63
64 for (int k = 0; k < problem->NSUPmodes; k++)
65 {
66 Umodes.append((problem->supmodes[k]).clone());
67 }
68
69 // Create locally the pressure modes
70 for (int k = 0; k < problem->NPmodes; k++)
71 {
72 Pmodes.append((problem->Pmodes[k]).clone());
73 }
74
76 FOMproblem);
78 FOMproblem);
79}
80
81// * * * * * * * * * * * * * Operators supremizer * * * * * * * * * * * * * //
82
83// Operator to evaluate the residual for the Supremizer approach
84int newton_unsteadyNS_sup::operator()(const Eigen::VectorXd& x,
85 Eigen::VectorXd& fvec) const
86{
87 Eigen::VectorXd a_dot(Nphi_u);
88 Eigen::VectorXd a_tmp(Nphi_u);
89 Eigen::VectorXd b_tmp(Nphi_p);
90 a_tmp = x.head(Nphi_u);
91 b_tmp = x.tail(Nphi_p);
92
93 // Choose the order of the numerical difference scheme for approximating the time derivative
94 if (problem->timeDerivativeSchemeOrder == "first")
95 {
96 a_dot = (x.head(Nphi_u) - y_old.head(Nphi_u)) / dt;
97 }
98 else
99 {
100 a_dot = (1.5 * x.head(Nphi_u) - 2 * y_old.head(Nphi_u) + 0.5 * yOldOld.head(
101 Nphi_u)) / dt;
102 }
103
104 // Convective term
105 Eigen::MatrixXd cc(1, 1);
106 // Mom Term
107 Eigen::VectorXd M1 = problem->B_matrix * a_tmp * nu;
108 // Gradient of pressure
109 Eigen::VectorXd M2 = problem->K_matrix * b_tmp;
110 // Mass Term
111 Eigen::VectorXd M5 = problem->M_matrix * a_dot;
112 // Pressure Term
113 Eigen::VectorXd M3 = problem->P_matrix * a_tmp;
114 // Penalty term
115 Eigen::MatrixXd penaltyU = Eigen::MatrixXd::Zero(Nphi_u, N_BC);
116
117 // Term for penalty method
118 if (problem->bcMethod == "penalty")
119 {
120 for (int l = 0; l < N_BC; l++)
121 {
122 penaltyU.col(l) = tauU(l,
123 0) * (BC(l) * problem->bcVelVec[l] - problem->bcVelMat[l] *
124 a_tmp);
125 }
126 }
127
128 for (int i = 0; i < Nphi_u; i++)
129 {
130 cc = a_tmp.transpose() * Eigen::SliceFromTensor(problem->C_tensor, 0,
131 i) * a_tmp;
132 fvec(i) = - M5(i) + M1(i) - cc(0, 0) - M2(i);
133
134 if (problem->bcMethod == "penalty")
135 {
136 for (int l = 0; l < N_BC; l++)
137 {
138 fvec(i) += penaltyU(i, l);
139 }
140 }
141 }
142
143 for (int j = 0; j < Nphi_p; j++)
144 {
145 int k = j + Nphi_u;
146 fvec(k) = M3(j);
147 }
148
149 if (problem->bcMethod == "lift")
150 {
151 for (int j = 0; j < N_BC; j++)
152 {
153 fvec(j) = x(j) - BC(j);
154 }
155 }
156
157 return 0;
158}
159
160// Operator to evaluate the Jacobian for the supremizer approach
161int newton_unsteadyNS_sup::df(const Eigen::VectorXd& x,
162 Eigen::MatrixXd& fjac) const
163{
164 Eigen::NumericalDiff<newton_unsteadyNS_sup> numDiff(*this);
165 numDiff.df(x, fjac);
166 return 0;
167}
168
169// * * * * * * * * * * * * * * * Operators PPE * * * * * * * * * * * * * * * //
170
171// Operator to evaluate the residual for the Pressure Poisson Equation (PPE) approach
172int newton_unsteadyNS_PPE::operator()(const Eigen::VectorXd& x,
173 Eigen::VectorXd& fvec) const
174{
175 Eigen::VectorXd a_dot(Nphi_u);
176 Eigen::VectorXd a_tmp(Nphi_u);
177 Eigen::VectorXd b_tmp(Nphi_p);
178 a_tmp = x.head(Nphi_u);
179 b_tmp = x.tail(Nphi_p);
180
181 // Choose the order of the numerical difference scheme for approximating the time derivative
182 if (problem->timeDerivativeSchemeOrder == "first")
183 {
184 a_dot = (x.head(Nphi_u) - y_old.head(Nphi_u)) / dt;
185 }
186 else
187 {
188 a_dot = (1.5 * x.head(Nphi_u) - 2 * y_old.head(Nphi_u) + 0.5 * yOldOld.head(
189 Nphi_u)) / dt;
190 }
191
192 // Convective terms
193 Eigen::MatrixXd cc(1, 1);
194 Eigen::MatrixXd gg(1, 1);
195 // Mom Term
196 Eigen::VectorXd M1 = problem->B_matrix * a_tmp * nu;
197 // Gradient of pressure
198 Eigen::VectorXd M2 = problem->K_matrix * b_tmp;
199 // Mass Term
200 Eigen::VectorXd M5 = problem->M_matrix * a_dot;
201 // Pressure Term
202 Eigen::VectorXd M3 = problem->D_matrix * b_tmp;
203 // BC PPE
204 Eigen::VectorXd M7 = problem->BC3_matrix * a_tmp * nu;
205 // BC PPE time-dependents BCs
206 Eigen::VectorXd M8 = problem->BC4_matrix * a_dot;
207 // Penalty term
208 Eigen::MatrixXd penaltyU = Eigen::MatrixXd::Zero(Nphi_u, N_BC);
209
210 // Term for penalty method
211 if (problem->bcMethod == "penalty")
212 {
213 for (int l = 0; l < N_BC; l++)
214 {
215 penaltyU.col(l) = tauU(l,
216 0) * (BC(l) * problem->bcVelVec[l] - problem->bcVelMat[l] *
217 a_tmp);
218 }
219 }
220
221 for (int i = 0; i < Nphi_u; i++)
222 {
223 cc = a_tmp.transpose() * Eigen::SliceFromTensor(problem->C_tensor, 0,
224 i) * a_tmp;
225 fvec(i) = - M5(i) + M1(i) - cc(0, 0) - M2(i);
226
227 if (problem->bcMethod == "penalty")
228 {
229 for (int l = 0; l < N_BC; l++)
230 {
231 fvec(i) += penaltyU(i, l);
232 }
233 }
234 }
235
236 for (int j = 0; j < Nphi_p; j++)
237 {
238 int k = j + Nphi_u;
239 gg = a_tmp.transpose() * Eigen::SliceFromTensor(problem->gTensor, 0,
240 j) * a_tmp;
241 fvec(k) = M3(j, 0) + gg(0, 0) - M7(j, 0);
242
243 if (problem->timedepbcMethod == "yes")
244 {
245 fvec(k) += M8(j, 0);
246 }
247 }
248
249 if (problem->bcMethod == "lift")
250 {
251 for (int j = 0; j < N_BC; j++)
252 {
253 fvec(j) = x(j) - BC(j);
254 }
255 }
256
257 return 0;
258}
259
260// Operator to evaluate the Jacobian for the supremizer approach
261int newton_unsteadyNS_PPE::df(const Eigen::VectorXd& x,
262 Eigen::MatrixXd& fjac) const
263{
264 Eigen::NumericalDiff<newton_unsteadyNS_PPE> numDiff(*this);
265 numDiff.df(x, fjac);
266 return 0;
267}
268
269
270// * * * * * * * * * * * * * Solve Functions supremizer * * * * * * * * * * * //
271
272void reducedUnsteadyNS::solveOnline_sup(Eigen::MatrixXd vel,
273 int startSnap)
274{
276 "The time step dt must be smaller than exportEvery.");
278 "The time step dt must be smaller than storeEvery.");
280 "The variable storeEvery must be an integer multiple of the time step dt.");
282 "The variable exportEvery must be an integer multiple of the time step dt.");
284 "The variable exportEvery must be an integer multiple of the variable storeEvery.");
285 int numberOfStores = round(storeEvery / dt);
286
287 if (problem->bcMethod == "lift")
288 {
290 }
291 else if (problem->bcMethod == "penalty")
292 {
293 vel_now = vel;
294 }
295
296 // Create and resize the solution vector
297 y.resize(Nphi_u + Nphi_p, 1);
298 y.setZero();
300 Umodes);
302 Pmodes);
303 int nextStore = 0;
304 int counter2 = 0;
305
306 // Change initial condition for the lifting function
307 if (problem->bcMethod == "lift")
308 {
309 for (int j = 0; j < N_BC; j++)
310 {
311 y(j) = vel_now(j, 0);
312 }
313 }
314
315 // Set some properties of the newton object
320 newton_object_sup.BC.resize(N_BC);
322
323 for (int j = 0; j < N_BC; j++)
324 {
325 newton_object_sup.BC(j) = vel_now(j, 0);
326 }
327
328 // Set number of online solutions
329 int Ntsteps = static_cast<int>((finalTime - tstart) / dt);
330 int onlineSize = static_cast<int>(Ntsteps / numberOfStores);
331 online_solution.resize(onlineSize);
332 // Set the initial time
333 time = tstart;
334 // Counting variable
335 int counter = 0;
336 // Create vector to store temporal solution and save initial condition as first solution
337 Eigen::MatrixXd tmp_sol(Nphi_u + Nphi_p + 1, 1);
338 tmp_sol(0) = time;
339 tmp_sol.col(0).tail(y.rows()) = y;
340 online_solution[counter] = tmp_sol;
341 counter ++;
342 counter2++;
343 nextStore += numberOfStores;
344 // Create nonlinear solver object
345 Eigen::HybridNonLinearSolver<newton_unsteadyNS_sup> hnls(newton_object_sup);
346 // Set output colors for fancy output
350
351 while (time < finalTime)
352 {
353 time = time + dt;
354
355 // Set time-dependent BCs
356 if (problem->timedepbcMethod == "yes" )
357 {
358 for (int j = 0; j < N_BC; j++)
359 {
360 newton_object_sup.BC(j) = vel_now(j, counter);
361 }
362 }
363
364 Eigen::VectorXd res(y);
365 res.setZero();
366 hnls.solve(y);
367
368 if (problem->bcMethod == "lift")
369 {
370 for (int j = 0; j < N_BC; j++)
371 {
372 if (problem->timedepbcMethod == "no" )
373 {
374 y(j) = vel_now(j, 0);
375 }
376 else if (problem->timedepbcMethod == "yes" )
377 {
378 y(j) = vel_now(j, counter);
379 }
380 }
381 }
382
383 newton_object_sup.operator()(y, res);
386 std::cout << "################## Online solve N° " << counter <<
387 " ##################" << std::endl;
388 Info << "Time = " << time << endl;
389
390 if (res.norm() < 1e-5)
391 {
392 std::cout << green << "|F(x)| = " << res.norm() << " - Minimun reached in " <<
393 hnls.iter << " iterations " << def << std::endl << std::endl;
394 }
395 else
396 {
397 std::cout << red << "|F(x)| = " << res.norm() << " - Minimun reached in " <<
398 hnls.iter << " iterations " << def << std::endl << std::endl;
399 }
400
401 tmp_sol(0) = time;
402 tmp_sol.col(0).tail(y.rows()) = y;
403
404 if (counter == nextStore)
405 {
406 if (counter2 >= online_solution.size())
407 {
408 online_solution.append(tmp_sol);
409 }
410 else
411 {
412 online_solution[counter2] = tmp_sol;
413 }
414
415 nextStore += numberOfStores;
416 counter2 ++;
417 }
418
419 counter ++;
420 }
421
422 // Export the solution
423 ITHACAstream::exportMatrix(online_solution, "red_coeff", "python",
424 "./ITHACAoutput/red_coeff");
425 ITHACAstream::exportMatrix(online_solution, "red_coeff", "matlab",
426 "./ITHACAoutput/red_coeff");
427}
428
429// * * * * * * * * * * * * * * * Solve Functions PPE * * * * * * * * * * * * * //
430
431void reducedUnsteadyNS::solveOnline_PPE(Eigen::MatrixXd vel,
432 int startSnap)
433{
435 "The time step dt must be smaller than exportEvery.");
437 "The time step dt must be smaller than storeEvery.");
439 "The variable storeEvery must be an integer multiple of the time step dt.");
441 "The variable exportEvery must be an integer multiple of the time step dt.");
443 "The variable exportEvery must be an integer multiple of the variable storeEvery.");
444 int numberOfStores = round(storeEvery / dt);
445
446 if (problem->bcMethod == "lift")
447 {
449 }
450 else if (problem->bcMethod == "penalty")
451 {
452 vel_now = vel;
453 }
454
455 // Create and resize the solution vector
456 y.resize(Nphi_u + Nphi_p, 1);
457 y.setZero();
458 // Set Initial Conditions
460 Umodes);
462 Pmodes);
463 int nextStore = 0;
464 int counter2 = 0;
465
466 // Change initial condition for the lifting function
467 if (problem->bcMethod == "lift")
468 {
469 for (int j = 0; j < N_BC; j++)
470 {
471 y(j) = vel_now(j, 0);
472 }
473 }
474
475 // Set some properties of the newton object
480 newton_object_PPE.BC.resize(N_BC);
482
483 for (int j = 0; j < N_BC; j++)
484 {
485 newton_object_PPE.BC(j) = vel_now(j, 0);
486 }
487
488 // Set number of online solutions
489 int Ntsteps = static_cast<int>((finalTime - tstart) / dt);
490 int onlineSize = static_cast<int>(Ntsteps / numberOfStores);
491 online_solution.resize(onlineSize);
492 // Set the initial time
493 time = tstart;
494 // Counting variable
495 int counter = 0;
496 // Create vector to store temporal solution and save initial condition as first solution
497 Eigen::MatrixXd tmp_sol(Nphi_u + Nphi_p + 1, 1);
498 tmp_sol(0) = time;
499 tmp_sol.col(0).tail(y.rows()) = y;
500 online_solution[counter] = tmp_sol;
501 counter ++;
502 counter2++;
503 nextStore += numberOfStores;
504 // Create nonlinear solver object
505 Eigen::HybridNonLinearSolver<newton_unsteadyNS_PPE> hnls(newton_object_PPE);
506 // Set output colors for fancy output
510
511 // Start the time loop
512 while (time < finalTime)
513 {
514 time = time + dt;
515
516 // Set time-dependent BCs
517 if (problem->timedepbcMethod == "yes" )
518 {
519 for (int j = 0; j < N_BC; j++)
520 {
521 newton_object_PPE.BC(j) = vel_now(j, counter);
522 }
523 }
524
525 Eigen::VectorXd res(y);
526 res.setZero();
527 hnls.solve(y);
528
529 if (problem->bcMethod == "lift")
530 {
531 for (int j = 0; j < N_BC; j++)
532 {
533 if (problem->timedepbcMethod == "no" )
534 {
535 y(j) = vel_now(j, 0);
536 }
537 else if (problem->timedepbcMethod == "yes" )
538 {
539 y(j) = vel_now(j, counter);
540 }
541 }
542 }
543
544 newton_object_PPE.operator()(y, res);
547 std::cout << "################## Online solve N° " << counter <<
548 " ##################" << std::endl;
549 Info << "Time = " << time << endl;
550
551 if (res.norm() < 1e-5)
552 {
553 std::cout << green << "|F(x)| = " << res.norm() << " - Minimun reached in " <<
554 hnls.iter << " iterations " << def << std::endl << std::endl;
555 }
556 else
557 {
558 std::cout << red << "|F(x)| = " << res.norm() << " - Minimun reached in " <<
559 hnls.iter << " iterations " << def << std::endl << std::endl;
560 }
561
562 tmp_sol(0) = time;
563 tmp_sol.col(0).tail(y.rows()) = y;
564
565 if (counter == nextStore)
566 {
567 if (counter2 >= online_solution.size())
568 {
569 online_solution.append(tmp_sol);
570 }
571 else
572 {
573 online_solution[counter2] = tmp_sol;
574 }
575
576 nextStore += numberOfStores;
577 counter2 ++;
578 }
579
580 counter ++;
581 }
582
583 // Export the solution
584 ITHACAstream::exportMatrix(online_solution, "red_coeff", "python",
585 "./ITHACAoutput/red_coeff");
586 ITHACAstream::exportMatrix(online_solution, "red_coeff", "matlab",
587 "./ITHACAoutput/red_coeff");
588}
589
590Eigen::MatrixXd reducedUnsteadyNS::penalty_sup(Eigen::MatrixXd& vel_now,
591 Eigen::MatrixXd& tauIter,
592 int startSnap)
593{
594 // Initialize new value on boundaries
595 Eigen::MatrixXd valBC = Eigen::MatrixXd::Zero(N_BC, timeStepPenalty);
596 // Initialize old values on boundaries
597 Eigen::MatrixXd valBC0 = Eigen::MatrixXd::Zero(N_BC, timeStepPenalty);
598 int Iter = 0;
599 Eigen::VectorXd diffvel = (vel_now.col(timeStepPenalty - 1) - valBC.col(
600 timeStepPenalty - 1));
601 diffvel = diffvel.cwiseAbs();
602
603 while (diffvel.maxCoeff() > tolerancePenalty && Iter < maxIterPenalty)
604 {
605 if ((valBC.col(timeStepPenalty - 1) - valBC0.col(timeStepPenalty - 1)).sum() !=
606 0)
607 {
608 for (int j = 0; j < N_BC; j++)
609 {
610 tauIter(j, 0) = tauIter(j, 0) * diffvel(j) / tolerancePenalty;
611 }
612 }
613
614 std::cout << "Solving for penalty factor(s): " << tauIter << std::endl;
615 std::cout << "number of iterations: " << Iter << std::endl;
616 // Set the old boundary value to the current value
617 valBC0 = valBC;
618 y.resize(Nphi_u + Nphi_p, 1);
619 y.setZero();
621 Umodes);
623 Pmodes);
624 // Set some properties of the newton object
628 newton_object_sup.BC.resize(N_BC);
630
631 // Set boundary conditions
632 for (int j = 0; j < N_BC; j++)
633 {
634 newton_object_sup.BC(j) = vel_now(j, 0);
635 }
636
637 // Create nonlinear solver object
638 Eigen::HybridNonLinearSolver<newton_unsteadyNS_sup> hnls(newton_object_sup);
639 // Set output colors for fancy output
643 // Set initially for convergence check
644 Eigen::VectorXd res(y);
645 res.setZero();
646
647 // Start the time loop
648 for (int i = 1; i < timeStepPenalty; i++)
649 {
650 // Set boundary conditions
651 for (int j = 0; j < N_BC; j++)
652 {
653 if (problem->timedepbcMethod == "yes" )
654 {
655 newton_object_sup.BC(j) = vel_now(j, i);
656 }
657 else
658 {
659 newton_object_sup.BC(j) = vel_now(j, 0);
660 }
661 }
662
663 Eigen::VectorXd res(y);
664 res.setZero();
665 hnls.solve(y);
666 newton_object_sup.operator()(y, res);
668
669 if (res.norm() < 1e-5)
670 {
671 std::cout << green << "|F(x)| = " << res.norm() << " - Minimun reached in " <<
672 hnls.iter << " iterations " << def << std::endl << std::endl;
673 }
674 else
675 {
676 std::cout << red << "|F(x)| = " << res.norm() << " - Minimun reached in " <<
677 hnls.iter << " iterations " << def << std::endl << std::endl;
678 }
679
680 volVectorField U_rec("U_rec", Umodes[0] * 0);
681
682 for (int j = 0; j < Nphi_u; j++)
683 {
684 U_rec += Umodes[j] * y(j);
685 }
686
687 for (int k = 0; k < problem->inletIndex.rows(); k++)
688 {
689 int BCind = problem->inletIndex(k, 0);
690 int BCcomp = problem->inletIndex(k, 1);
691 valBC(k, i) = U_rec.boundaryFieldRef()[BCind][0].component(BCcomp);
692 }
693 }
694
695 for (int j = 0; j < N_BC; j++)
696 {
697 diffvel(j) = abs(abs(vel_now(j, timeStepPenalty - 1)) - abs(valBC(j,
698 timeStepPenalty - 1)));
699 }
700
701 std::cout << "max error: " << diffvel.maxCoeff() << std::endl;
702 // Count the number of iterations
703 Iter ++;
704 }
705
706 std::cout << "Final penalty factor(s): " << tauIter << std::endl;
707 std::cout << "Iterations: " << Iter - 1 << std::endl;
708 return tauIter;
709}
710
711Eigen::MatrixXd reducedUnsteadyNS::penalty_PPE(Eigen::MatrixXd& vel_now,
712 Eigen::MatrixXd& tauIter,
713 int startSnap)
714{
715 // Initialize new value on boundaries
716 Eigen::MatrixXd valBC = Eigen::MatrixXd::Zero(N_BC, timeStepPenalty);
717 // Initialize old values on boundaries
718 Eigen::MatrixXd valBC0 = Eigen::MatrixXd::Zero(N_BC, timeStepPenalty);
719 int Iter = 0;
720 Eigen::VectorXd diffvel = (vel_now.col(timeStepPenalty - 1) - valBC.col(
721 timeStepPenalty - 1));
722 diffvel = diffvel.cwiseAbs();
723
724 while (diffvel.maxCoeff() > tolerancePenalty && Iter < maxIterPenalty)
725 {
726 if ((valBC.col(timeStepPenalty - 1) - valBC0.col(timeStepPenalty - 1)).sum() !=
727 0)
728 {
729 for (int j = 0; j < N_BC; j++)
730 {
731 tauIter(j, 0) = tauIter(j, 0) * diffvel(j) / tolerancePenalty;
732 }
733 }
734
735 std::cout << "Solving for penalty factor(s): " << tauIter << std::endl;
736 std::cout << "number of iterations: " << Iter << std::endl;
737 // Set the old boundary value to the current value
738 valBC0 = valBC;
739 y.resize(Nphi_u + Nphi_p, 1);
740 y.setZero();
742 Umodes);
744 Pmodes);
745 // Set some properties of the newton object
750 newton_object_PPE.BC.resize(N_BC);
752
753 // Set boundary conditions
754 for (int j = 0; j < N_BC; j++)
755 {
756 newton_object_PPE.BC(j) = vel_now(j, 0);
757 }
758
759 // Create nonlinear solver object
760 Eigen::HybridNonLinearSolver<newton_unsteadyNS_PPE> hnls(newton_object_PPE);
761 // Set output colors for fancy output
765 // Set initially for convergence check
766 Eigen::VectorXd res(y);
767 res.setZero();
768
769 // Start the time loop
770 for (int i = 1; i < timeStepPenalty; i++)
771 {
772 // Set boundary conditions
773 for (int j = 0; j < N_BC; j++)
774 {
775 if (problem->timedepbcMethod == "yes" )
776 {
777 newton_object_PPE.BC(j) = vel_now(j, i);
778 }
779 else
780 {
781 newton_object_PPE.BC(j) = vel_now(j, 0);
782 }
783 }
784
785 Eigen::VectorXd res(y);
786 res.setZero();
787 hnls.solve(y);
788 newton_object_PPE.operator()(y, res);
791
792 if (res.norm() < 1e-5)
793 {
794 std::cout << green << "|F(x)| = " << res.norm() << " - Minimun reached in " <<
795 hnls.iter << " iterations " << def << std::endl << std::endl;
796 }
797 else
798 {
799 std::cout << red << "|F(x)| = " << res.norm() << " - Minimun reached in " <<
800 hnls.iter << " iterations " << def << std::endl << std::endl;
801 }
802
803 volVectorField U_rec("U_rec", Umodes[0] * 0);
804
805 for (int j = 0; j < Nphi_u; j++)
806 {
807 U_rec += Umodes[j] * y(j);
808 }
809
810 for (int k = 0; k < problem->inletIndex.rows(); k++)
811 {
812 int BCind = problem->inletIndex(k, 0);
813 int BCcomp = problem->inletIndex(k, 1);
814 valBC(k, i) = U_rec.boundaryFieldRef()[BCind][0].component(BCcomp);
815 }
816 }
817
818 for (int j = 0; j < N_BC; j++)
819 {
820 diffvel(j) = abs(abs(vel_now(j, timeStepPenalty - 1)) - abs(valBC(j,
821 timeStepPenalty - 1)));
822 }
823
824 std::cout << "max error: " << diffvel.maxCoeff() << std::endl;
825 // Count the number of iterations
826 Iter ++;
827 }
828
829 std::cout << "Final penalty factor(s): " << tauIter << std::endl;
830 std::cout << "Iterations: " << Iter - 1 << std::endl;
831 return tauIter;
832}
833
834void reducedUnsteadyNS::reconstruct(bool exportFields, fileName folder)
835{
836 if (exportFields)
837 {
838 mkDir(folder);
840 }
841
842 int counter = 0;
843 int nextwrite = 0;
844 List < Eigen::MatrixXd> CoeffU;
845 List < Eigen::MatrixXd> CoeffP;
846 List <double> tValues;
847 CoeffU.resize(0);
848 CoeffP.resize(0);
849 tValues.resize(0);
850 int exportEveryIndex = round(exportEvery / storeEvery);
851
852 for (int i = 0; i < online_solution.size(); i++)
853 {
854 if (counter == nextwrite)
855 {
856 Eigen::MatrixXd currentUCoeff;
857 Eigen::MatrixXd currentPCoeff;
858 currentUCoeff = online_solution[i].block(1, 0, Nphi_u, 1);
859 currentPCoeff = online_solution[i].bottomRows(Nphi_p);
860 CoeffU.append(currentUCoeff);
861 CoeffP.append(currentPCoeff);
862 nextwrite += exportEveryIndex;
863 double timeNow = online_solution[i](0, 0);
864 tValues.append(timeNow);
865 }
866
867 counter++;
868 }
869
870 volVectorField uRec("uRec", Umodes[0] * 0);
871 volScalarField pRec("pRec", problem->Pmodes[0] * 0);
872 uRecFields = problem->L_U_SUPmodes.reconstruct(uRec, CoeffU, "uRec");
873 pRecFields = problem->Pmodes.reconstruct(pRec, CoeffP, "pRec");
874
875 if (exportFields)
876 {
878 "uRec");
880 "pRec");
881 }
882}
883
884Eigen::MatrixXd reducedUnsteadyNS::setOnlineVelocity(Eigen::MatrixXd vel)
885{
886 assert(problem->inletIndex.rows() == vel.rows()
887 && "Imposed boundary conditions dimensions do not match given values matrix dimensions");
888 Eigen::MatrixXd vel_scal;
889 vel_scal.resize(vel.rows(), vel.cols());
890
891 for (int k = 0; k < problem->inletIndex.rows(); k++)
892 {
893 int p = problem->inletIndex(k, 0);
894 int l = problem->inletIndex(k, 1);
895 scalar area = gSum(problem->liftfield[0].mesh().magSf().boundaryField()[p]);
896 scalar u_lf = gSum(problem->liftfield[k].mesh().magSf().boundaryField()[p] *
897 problem->liftfield[k].boundaryField()[p]).component(l) / area;
898
899 for (int i = 0; i < vel.cols(); i++)
900 {
901 vel_scal(k, i) = vel(k, i) / u_lf;
902 }
903 }
904
905 return vel_scal;
906}
907//************************************************************************* //
#define M_Assert(Expr, Msg)
Header file of the reducedUnsteadyNS class.
Class to change color to the output stream.
Definition colormod.H:24
GeometricField< Type, PatchField, GeoMesh > reconstruct(GeometricField< Type, PatchField, GeoMesh > &inputField, Eigen::MatrixXd Coeff, word Name)
Function to reconstruct the solution starting from the coefficients, in this case the field is passed...
Definition Modes.C:275
Eigen::VectorXd y
Vector to store the solution during the Newton procedure.
PtrList< volScalarField > Pmodes
List of pointers to store the modes for pressure.
List< Eigen::MatrixXd > online_solution
List of Eigen matrices to store the online solution.
int Nphi_p
Number of pressure modes.
scalar nu
Reduced viscosity in case of parametrized viscosity.
Eigen::MatrixXd tauU
Penalty Factor.
PtrList< volScalarField > pRecFields
Reconstructed pressure fields list.
Eigen::MatrixXd vel_now
Online inlet velocity vector.
PtrList< volVectorField > Umodes
List of pointers to store the modes for velocity.
PtrList< volVectorField > uRecFields
Recontructed velocity fields list.
int N_BC
Number of parametrized boundary conditions.
int Nphi_u
Number of velocity modes.
newton_unsteadyNS_PPE newton_object_PPE
Function object to call the non linear solver PPE approach.
Eigen::MatrixXd setOnlineVelocity(Eigen::MatrixXd vel)
Sets the online velocity.
double exportEvery
A variable for exporting the fields.
reducedUnsteadyNS()
Construct Null.
scalar tolerancePenalty
Tolerance for the residual of the boundary values, there is the same tolerance for velocity and tempe...
scalar finalTime
Scalar to store the final time if the online simulation.
Eigen::MatrixXd penalty_sup(Eigen::MatrixXd &vel_now, Eigen::MatrixXd &tauIter, int startSnap=0)
Method to determine the penalty factors iteratively.
newton_unsteadyNS_sup newton_object_sup
Function object to call the non linear solver sup approach.
int timeStepPenalty
Number of timesteps calculated for the iterative penalty method.
void solveOnline_PPE(Eigen::MatrixXd vel_now, int startSnap=0)
Method to perform an online solve using a PPE stabilisation method.
void solveOnline_sup(Eigen::MatrixXd vel_now, int startSnap=0)
Method to perform an online solve using a supremizer stabilisation method.
scalar tstart
Scalar to store the initial time if the online simulation.
void reconstruct(bool exportFields=false, fileName folder="./online_rec")
Method to reconstruct the solutions from an online solve with a supremizer stabilisation technique.
unsteadyNS * problem
Pointer to the FOM problem.
Eigen::MatrixXd tauIter
Penalty Factor determined with iterative solver.
scalar time
Scalar to store the current time.
scalar maxIterPenalty
Maximum number of iterations to be done for the computation of the penalty factor.
double dt
Scalar to store the time increment.
Eigen::MatrixXd penalty_PPE(Eigen::MatrixXd &vel_now, Eigen::MatrixXd &tauIter, int startSnap=0)
Method to determine the penalty factors iteratively.
double storeEvery
A variable for storing the reduced coefficients.
Eigen::MatrixXi inletIndex
Matrix that contains informations about the inlet boundaries.
List< Eigen::MatrixXd > bcVelVec
Boundary term for penalty method - vector.
Definition steadyNS.H:218
label NPmodes
Number of pressure modes used for the projection.
Definition steadyNS.H:143
Eigen::MatrixXd BC4_matrix
PPE BC4.
Definition steadyNS.H:194
Eigen::MatrixXd BC3_matrix
PPE BC3.
Definition steadyNS.H:191
Eigen::Tensor< double, 3 > C_tensor
Diffusion term.
Definition steadyNS.H:167
PtrList< volScalarField > Pfield
List of pointers used to form the pressure snapshots matrix.
Definition steadyNS.H:86
volVectorModes supmodes
List of pointers used to form the supremizer modes.
Definition steadyNS.H:104
volVectorModes Umodes
List of pointers used to form the velocity modes.
Definition steadyNS.H:101
PtrList< volVectorField > Ufield
List of pointers used to form the velocity snapshots matrix.
Definition steadyNS.H:89
label NUmodes
Number of velocity modes used for the projection.
Definition steadyNS.H:140
PtrList< volVectorField > liftfield
List of pointers used to form the list of lifting functions.
Definition steadyNS.H:110
volVectorModes L_U_SUPmodes
List of pointers containing the total number of lift, supremizer and velocity modes.
Definition steadyNS.H:116
Eigen::MatrixXd B_matrix
Diffusion term.
Definition steadyNS.H:157
Eigen::MatrixXd D_matrix
Laplacian term PPE.
Definition steadyNS.H:173
label NSUPmodes
Number of supremizer modes used for the projection.
Definition steadyNS.H:146
Eigen::Tensor< double, 3 > gTensor
Divergence of momentum PPE.
Definition steadyNS.H:179
Eigen::MatrixXd K_matrix
Gradient of pressure matrix.
Definition steadyNS.H:163
List< Eigen::MatrixXd > bcVelMat
Boundary term for penalty method - matrix.
Definition steadyNS.H:221
Eigen::MatrixXd P_matrix
Div of velocity.
Definition steadyNS.H:170
Eigen::MatrixXd M_matrix
Mass Matrix.
Definition steadyNS.H:160
volScalarModes Pmodes
List of pointers used to form the pressure modes.
Definition steadyNS.H:98
word bcMethod
Boundary Method.
Definition steadyNS.H:317
Implementation of a parametrized full order unsteady NS problem and preparation of the the reduced ...
Definition unsteadyNS.H:62
word timeDerivativeSchemeOrder
Definition unsteadyNS.H:99
word timedepbcMethod
Time-dependent Boundary Method.
Definition unsteadyNS.H:93
@ FG_GREEN
Definition colormod.H:14
@ FG_DEFAULT
Definition colormod.H:16
@ FG_RED
Definition colormod.H:13
Matrix< VectorType, Dynamic, Dynamic > SliceFromTensor(Eigen::Tensor< VectorType, 3 > &tensor, label dim, label index1)
void exportFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &field, word folder, word fieldname)
Function to export a scalar of vector field.
void exportMatrix(Eigen::Matrix< T, -1, dim > &matrix, word Name, word type, word folder)
Export the reduced matrices in numpy (type=python), matlab (type=matlab) and txt (type=eigen) format ...
Eigen::VectorXd getCoeffs(GeometricField< Type, PatchField, GeoMesh > &snapshot, PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, label Nmodes, bool consider_volumes)
Projects a snapshot on a basis function and gets the coefficients of the projection.
bool isInteger(double ratio)
This function checks if ratio is an integer.
void createSymLink(word folder)
Creates symbolic links to 0, system and constant.
volScalarField & p
label i
Definition pEqn.H:46
Newton object for the resolution of the reduced problem using a PPE approach.
int df(const Eigen::VectorXd &x, Eigen::MatrixXd &fjac) const
int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
Newton object for the resolution of the reduced problem using a supremizer approach.
int df(const Eigen::VectorXd &x, Eigen::MatrixXd &fjac) const
int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const