Finite Element Domain Decomposition Library
FEDDLib
Loading...
Searching...
No Matches
FSI_def.hpp
1#ifndef FSI_def_hpp
2#define FSI_def_hpp
3
4#include "feddlib/problems/abstract/TimeProblem.hpp"
5#include "feddlib/problems/specific/NavierStokes.hpp"
6#include "feddlib/problems/specific/LinElas.hpp"
7#include "feddlib/problems/specific/NonLinElasticity.hpp"
8#include "feddlib/problems/specific/Geometry.hpp"
9#include "feddlib/core/Mesh/MeshUnstructured.hpp"
10#include "feddlib/core/General/ExporterParaView.hpp"
11#include "feddlib//core/FE/FE.hpp"
12#include "feddlib/core/General/BCBuilder.hpp"
13
14
15// TODO: [JK] Why are all these functions in the global namespace?
16
17double OneFunc(double* x, int* parameter)
18{
19 return 1.0;
20}
21
22void drag2D(double* x, double* res, double t, const double* parameters)
23{
24 res[0] = 1.;
25 res[1] = 0.;
26
27 return;
28}
29
30void drag3D(double* x, double* res, double t, const double* parameters)
31{
32 res[0] = 1.;
33 res[1] = 0.;
34 res[2] = 0.;
35
36 return;
37}
38
39void lift2D(double* x, double* res, double t, const double* parameters)
40{
41 res[0] = 0.;
42 res[1] = 1.;
43
44 return;
45}
46
47void lift3D(double* x, double* res, double t, const double* parameters)
48{
49 res[0] = 0.;
50 res[1] = 1.;
51 res[2] = 0.;
52
53 return;
54}
55void pressureRamp(double* x, double* res, double* parameters){
56
57 double pressureValue = parameters[1];
58 double flag = parameters[3];
59 double ramp = parameters[2];
60 res[0] =0.;
61
62 if(parameters[0]+1.e-12 < ramp)
63 pressureValue = parameters[0]*pressureValue/ramp;
64 else
65 pressureValue = parameters[1];
66
67 res[0] = pressureValue; // Usually we check here for the correct flag. But as the boundary condition is limited to the outlet anyway, we have no issues
68
69
70 return;
71}
72
73namespace FEDD {
74// Funktionen fuer die rechte Seite der Struktur/ Fluid/ Geometrie sind im jeweiligen Problem
75
76template<class SC,class LO,class GO,class NO>
77FSI<SC,LO,GO,NO>::FSI(const DomainConstPtr_Type &domainVelocity, std::string FETypeVelocity,
78 const DomainConstPtr_Type &domainPressure, std::string FETypePressure,
79 const DomainConstPtr_Type &domainStructure, std::string FETypeStructure,
80 const DomainConstPtr_Type &domainInterface, std::string FETypeInterface,
81 const DomainConstPtr_Type &domainGeometry, std::string FETypeGeometry,
82 ParameterListPtr_Type parameterListFluid, ParameterListPtr_Type parameterListStructure,
83 ParameterListPtr_Type parameterListFSI, ParameterListPtr_Type parameterListGeometry,
84 Teuchos::RCP<SmallMatrix<int> > &defTS):
85NonLinearProblem<SC,LO,GO,NO>( parameterListFSI, domainVelocity->getComm() ),
86// hasSourceTerm = drittes Arguement. assembleSourceTerm() fuer NS nicht programmiert.
87// Deswegen hier erstmal false (default Parameter).
88// Fuer Struktur hingegen ist default Parameter true, da programmiert.
89P_(),
90problemFluid_(),
91problemStructure_(),
92problemStructureNonLin_(),
93problemGeometry_(),
94meshDisplacementOld_rep_(),
95meshDisplacementNew_rep_(),
96u_rep_(),
97w_rep_(),
98u_minus_w_rep_(),
99p_rep_(),
100defTS_(defTS),
101timeSteppingTool_(),
102materialModel_( parameterListStructure->sublist("Parameter").get("Material model","linear") ),
103valuesForExport_(0),
104exporterTxtDrag_(),
105exporterGeo_()
106{
107 this->nonLinearTolerance_ = this->parameterList_->sublist("Parameter").get("relNonLinTol",1.0e-6);
108 geometryExplicit_ = this->parameterList_->sublist("Parameter").get("Geometry Explicit",true);
109
110 this->initNOXParameters();
111 counterP = 0;
112
113 std::string linearization = parameterListFSI->sublist("General").get("Linearization","FixedPoint");
114
115 TEUCHOS_TEST_FOR_EXCEPTION( !(linearization == "Newton" || linearization == "NOX") && materialModel_ != "linear", std::runtime_error, "Nonlinear material models can only be used with Newton's method or FixedPoint (nonlinear material Jacobian will still be used).");
116
117 this->addVariable( domainVelocity, FETypeVelocity, "u_f", domainVelocity->getDimension() ); // Fluid-Geschw.
118 this->addVariable( domainPressure, FETypePressure, "p", 1); // Fluid-Druck
119 this->addVariable( domainStructure, FETypeStructure, "d_s", domainStructure->getDimension() ); // Struktur
120 this->addVariable( domainInterface, FETypeInterface, "lambda", domainInterface->getDimension() ); // Interface
121 this->addVariable( domainGeometry, FETypeGeometry, "d_f", domainGeometry->getDimension() ); // Geometrie
122 this->dim_ = this->getDomain(0)->getDimension();
123
124 problemFluid_ = Teuchos::rcp( new FluidProblem_Type( domainVelocity, FETypeVelocity, domainPressure, FETypePressure, parameterListFluid ) );
125 problemFluid_->initializeProblem();
126 problemFluid_->infoParameter(false,"Fluid");
127
128 if (materialModel_=="linear"){
129 problemStructure_ = Teuchos::rcp( new StructureProblem_Type( domainStructure, FETypeStructure, parameterListStructure ) );
130 problemStructure_->initializeProblem();
131 problemStructure_->infoParameter(false,"Solid");
132 }
133 else{
134 problemStructureNonLin_ = Teuchos::rcp( new StructureNonLinProblem_Type( domainStructure, FETypeStructure, parameterListStructure) );
135 problemStructureNonLin_->initializeProblem();
136 problemStructureNonLin_->infoParameter(false, "Solid");
137 }
138
139 problemGeometry_ = Teuchos::rcp( new GeometryProblem_Type( domainGeometry, FETypeGeometry, parameterListGeometry ) );
140 problemGeometry_->initializeProblem();
141 problemGeometry_->infoParameter(false,"Geometry");
142 //We initialize the subproblems. In the main routine, we need to call initializeFSI(). There, we first initialize the vectors of the FSI problem and then we set the pointers of the subproblems to the vectors of the full monolithic FSI system. This way all values are only saved once in the subproblems and can be used by the monolithic FSI system.
143
144 meshDisplacementNew_rep_ = Teuchos::rcp( new MultiVector_Type( this->getDomain(4)->getMapVecFieldRepeated() ) );
145 meshDisplacementOld_rep_ = Teuchos::rcp( new MultiVector_Type( this->getDomain(4)->getMapVecFieldRepeated() ) );
146 u_rep_ = Teuchos::rcp( new MultiVector_Type( this->getDomain(0)->getMapVecFieldRepeated() ) );
147 w_rep_ = Teuchos::rcp( new MultiVector_Type( this->getDomain(0)->getMapVecFieldRepeated() ) );
148 u_minus_w_rep_ = Teuchos::rcp( new MultiVector_Type( this->getDomain(0)->getMapVecFieldRepeated() ) );
149
150 // Exporting benchmark values
151 if ( parameterListFSI->sublist("General").get("Export Extra Data",false) ){
152 if (this->dim_==2)
153 findDisplacementTurek2DBenchmark();
154 else if (this->dim_==3)
155 findDisplacementRichter3DBenchmark();
156 }
157 if ( parameterListFSI->sublist("General").get("Export drag and lift",false) ){
158 exporterTxtDrag_ = Teuchos::rcp(new ExporterTxt () );
159 exporterTxtDrag_->setup( "drag_force", this->comm_ );
160 exporterTxtLift_ = Teuchos::rcp(new ExporterTxt () );
161 exporterTxtLift_->setup( "lift_force", this->comm_ );
162 }
163 p_rep_ = Teuchos::rcp( new MultiVector_Type( this->getDomain(1)->getMapRepeated() ) );
164
165 // if ( this->parameterList_->sublist("Timestepping Parameter").get("Checkpointing", false)){
166 // exporterBoundaryCondition_ = Teuchos::rcp(new ExporterTxt () );
167 // exporterBoundaryCondition_->setup( "boundaryConditionFluid", this->comm_ );
168 // }
169}
170
171template<class SC,class LO,class GO,class NO>
172void FSI<SC,LO,GO,NO>::findDisplacementTurek2DBenchmark(){
173 valuesForExport_.resize(1);
174 vec_dbl_Type x = {0.6,0.2};
175 //we save the local index as a double
176 valuesForExport_[0] = this->getDomain(2)->findInPointsUnique( x );
177}
178
179template<class SC,class LO,class GO,class NO>
180void FSI<SC,LO,GO,NO>::findDisplacementRichter3DBenchmark(){
181 valuesForExport_.resize(1);
182 vec_dbl_Type x = {0.45,0.15,0.15};
183 //we save the local index as a double
184 valuesForExport_[0] = this->getDomain(2)->findInPointsUnique( x );
185}
186
187template<class SC,class LO,class GO,class NO>
188FSI<SC,LO,GO,NO>::~FSI()
189{
190 if (!exporterGeo_.is_null()) {
191 exporterGeo_->closeExporter();
192 }
193}
194
195template<class SC,class LO,class GO,class NO>
196void FSI<SC,LO,GO,NO>::info()
197{
198 this->infoProblem();
199 this->infoNonlinProblem();
200}
201
202// Alle linearen Probleme
203template<class SC,class LO,class GO,class NO>
204void FSI<SC,LO,GO,NO>::assemble( std::string type ) const
205{
206 if (type == "") {
207 if (this->verbose_)
208 {
209 std::cout << "-- Assembly FSI ... " << std::endl;
210 }
211
212 // P_.reset(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), 10 ) );
213
214 this->problemFluid_->assemble();
215
216 // steady rhs wird hier assembliert.
217 // rhsFunc auf 0 (=x) und 0 (=y) abaendern bei LinElas!
218 if (materialModel_=="linear")
219 this->problemStructure_->assemble();
220 else
221 this->problemStructureNonLin_->assemble();
222
223 this->problemGeometry_->assemble();
224
225 if ( geometryExplicit_ && this->parameterList_->sublist("Exporter").get("Export GE geometry solution",false)){
226 exporterGeo_ = Teuchos::rcp(new Exporter_Type());
227
228 DomainConstPtr_Type dom = this->getDomain(4);
229
230 int exportEveryXTimesteps = this->parameterList_->sublist("Exporter").get( "Export every X timesteps", 1 );
231 std::string suffix = this->parameterList_->sublist("Exporter").get("Geometry Suffix", "" );
232 std::string varName = "d_f" + suffix;
233
234 MeshPtr_Type meshNonConst = Teuchos::rcp_const_cast<Mesh_Type>( dom->getMesh() );
235 exporterGeo_->setup(varName, meshNonConst, dom->getFEType(), exportEveryXTimesteps, this->parameterList_);
236
237 MultiVectorConstPtr_Type exportVector = this->problemGeometry_->getSolution()->getBlock(0);
238
239 exporterGeo_->addVariable( exportVector, varName, "Vector", this->dim_, dom->getMapUnique() );
240 }
241
242
243 if (!geometryExplicit_) {
244 // RW fuer die Geometrie-Matrix H setzen, weil wenn wir das spaeter im FSI-System
245 // machen, dann wird aufgrund der RW auf dem Interface auch der Kopplungsblock
246 // zur Struktur C4 ausgenullt, was wir nicht wollen.
247 this->problemGeometry_->setBoundariesSystem(); // RW im System setzen (mit den Flags von oben)
248 this->problemGeometry_->getRhs()->putScalar(0.0);
249 }
250
251 // ###########################
252 // Kopplungsbloecke
253 // ###########################
254 // ACHTUNG: Anders als im Matlab-Code!!!
255 // Matlab: C1_T hat so viele Zeilen wie das komplette Fluid-System (u + p)
256 // FEDDLib: C1_T hat so viele Zeilen wie das Geschwindigkeitssystem (nur u)
257 // Bemerkung: Verteilung der Zeilen wird angegeben (Range-Map).
258 // Interface wird von der Fluid-Seite aus gehalten, deswegen auch
259 // getDomain(0) bei C2, obwohl es in der Struktur-Spalte ist.
260 MatrixPtr_Type C1_T(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), 1 ) ); // Fluid-Kopplung
261 MatrixPtr_Type C1(new Matrix_Type( this->getDomain(0)->getInterfaceMapVecFieldUnique(), 1 ) ); // Fluid-Spalte
262 MatrixPtr_Type C2(new Matrix_Type( this->getDomain(0)->getInterfaceMapVecFieldUnique(), 1 ) ); // Struktur-Spalte
263 MatrixPtr_Type C3_T(new Matrix_Type( this->getDomain(2)->getMapVecFieldUnique(), 1 ) ); // Struktur-Kopplung
264
265
266 // Nur vorhanden, falls geometrisch implizit
267 MatrixPtr_Type C4(new Matrix_Type( this->getDomain(4)->getMapVecFieldUnique(), 1 ) ); // Geometrie (=Fluid)
268
269 // Fluid-Bloecke
270 this->feFactory_->assemblyFSICoupling(this->dim_, this->domain_FEType_vec_.at(0), C1, C1_T, 0, 0,
271 this->getDomain(0)->getInterfaceMapVecFieldUnique(), this->getDomain(0)->getMapVecFieldUnique(), true);
272
273 // Struktur-Bloecke
274 // ACHTUNG: Die Interface-Variable \lambda wird eindeutig von der Fluid-Seite gehalten.
275 // Deswegen auch getDomain(0) fuer die Spalten der Kopplungsbloecke.
276 this->feFactory_->assemblyFSICoupling(this->dim_, this->domain_FEType_vec_.at(2), C2, C3_T, 0, 2,
277 this->getDomain(0)->getInterfaceMapVecFieldUnique(), this->getDomain(2)->getMapVecFieldUnique(), true);
278
279
280 // Falls geometrisch implizit
281 if(!geometryExplicit_)
282 {
283 // TODO: Wegen IndicesGlobalMatched_ vlt .sicherheitshalber FEloc = 0 nehmen.
284 // TODO: Check C4
285 this->feFactory_->assemblyGeometryCoupling(this->dim_, this->domain_FEType_vec_.at(4), C4, 4,
286 this->getDomain(0)->getGlobalInterfaceMapUnique(),
287 this->getDomain(2)->getMapVecFieldUnique(),
288 this->getDomain(4)->getMapVecFieldUnique(), true);
289 }
290
291 MatrixPtr_Type dummyC;
292 // we need to set the dummy coupling conditions for monolithic preconditioning with FROSch
293 if ( !this->getDomain(0)->getGlobalInterfaceMapVecFieldPartial().is_null() ) {
294 dummyC.reset(new Matrix_Type( this->getDomain(0)->getInterfaceMapVecFieldUnique(), 1 ) );
295 this->feFactory_->assemblyDummyCoupling(this->dim_, this->domain_FEType_vec_.at(0), dummyC, 0,true);
296 }
297
298 // ###########################
299 // Korrekte Skalierung der entsprechenden Bloecke
300 // ###########################
301 double dt = this->parameterList_->sublist("Timestepping Parameter").get("dt",0.02);
302
303 C2->resumeFill();
304 C3_T->resumeFill();
305
306 C2->scale( -(1.0/dt) ); // this will be used in a first order approximation of the solid velocity
307 C3_T->scale( -1.0 );
308
309 // ACHTUNG: Die Interface-Variable \lambda wird eindeutig von der Fluid-Seite gehalten.
310 // Deswegen auch getDomain(0) fuer die Spalten von C3_T.
311 C2->fillComplete(this->getDomain(2)->getMapVecFieldUnique(), this->getDomain(0)->getInterfaceMapVecFieldUnique());
312 C3_T->fillComplete(this->getDomain(0)->getInterfaceMapVecFieldUnique(), this->getDomain(2)->getMapVecFieldUnique());
313
314 // C2 in Membervariable C2_ speichern, fuer rechte Seite im Interface-Block:
315 // C2*d_s^n
316 C2_ = C2;
317
318 if(!geometryExplicit_)
319 {
320 C4->resumeFill();
321 C4->scale(-1.0);
322 // Domain = Spalten = Struktur; Range = Zeilen = Geometrie
323 C4->fillComplete(this->getDomain(2)->getMapVecFieldUnique(), this->getDomain(4)->getMapVecFieldUnique());
324 }
325
326
327
328 // ###########################
329 // Bloecke hinzufuegen
330 // ###########################
331 if(geometryExplicit_)
332 this->system_.reset(new BlockMatrix_Type(4));
333 else
334 this->system_.reset(new BlockMatrix_Type(5));
335
336 // Fluid
337 this->system_->addBlock( this->problemFluid_->system_->getBlock(0,0), 0, 0 );
338 this->system_->addBlock( this->problemFluid_->system_->getBlock(0,1), 0, 1 );
339 this->system_->addBlock( this->problemFluid_->system_->getBlock(1,0), 1, 0 );
340 if (this->getDomain(0)->getFEType()=="P1")
341 this->system_->addBlock( this->problemFluid_->system_->getBlock(1,1), 1, 1 );
342
343 // Struktur
344 if (materialModel_=="linear")
345 this->system_->addBlock( this->problemStructure_->system_->getBlock(0,0), 2, 2 );
346 else
347 this->system_->addBlock( this->problemStructureNonLin_->system_->getBlock(0,0), 2, 2 );
348 // Kopplung
349 this->system_->addBlock( C1_T, 0, 3 );
350 this->system_->addBlock( C3_T, 2, 3 );
351 this->system_->addBlock( C1, 3, 0 );
352 this->system_->addBlock( C2, 3, 2 );
353
354 if (!dummyC.is_null())
355 this->system_->addBlock( dummyC, 3, 3 );
356
357 if(!geometryExplicit_)
358 {
359 // Geometrie
360 this->system_->addBlock( this->problemGeometry_->system_->getBlock(0,0), 4, 4 );
361 // Kopplung
362 this->system_->addBlock( C4, 4, 2 );
363 }
364
365 // Sollte (bzw. muss) erst aufgerufen werden, wenn alle Bloecke aus assemble()
366 // in das ganze System hineingeschrieben worden ist. Ansonsten findet
367 // blockExists() keinen Block
368 // this->initializeVectors();
369 // this->initializeVectorsNonLinear();
370 //NOX
371
372 // We set the vector from the partial problems
373 this->setFromPartialVectorsInit();
374
375 // Fuer die Zeitprobleme
376 timeSteppingTool_ = Teuchos::rcp(new TimeSteppingTools(sublist(this->parameterList_,"Timestepping Parameter") , this->comm_));
377 ParameterListPtr_Type plStructure;
378 if (materialModel_=="linear")
379 plStructure = this->problemStructure_->getParameterList();
380 else
381 plStructure = this->problemStructureNonLin_->getParameterList();
382
383 setupSubTimeProblems(this->problemFluid_->getParameterList(), plStructure);
384
385 if (this->verbose_)
386 {
387 std::cout << "done -- " << std::endl;
388 }
389 }
390 else
391 reAssemble(type);
392}
393
394
395template<class SC,class LO,class GO,class NO>
396void FSI<SC,LO,GO,NO>::reAssemble(std::string type) const
397{
398
399 double dt = this->parameterList_->sublist("Timestepping Parameter").get("dt",0.02);
400
401 // Fluid-Dichte
402 double density = this->problemFluid_->getParameterList()->sublist("Parameter").get("Density",1.);
403 double viscosity = this->problemFluid_->getParameterList()->sublist("Parameter").get("Viscosity",1.);
404
405 if(type == "UpdateMeshDisplacement")
406 {
407 if(this->verbose_)
408 std::cout << "-- Reassembly (UpdateMeshDisplacement)" << '\n';
409
410 // Da dieser Abschnitt zu Beginn der neuen Zeititeration aufgerufen wird, muss
411 // auch die alte Gitterverschiebung durch die neue Loesung aktualisiert werden.
412 updateMeshDisplacement();
413 return;
414 }
415
416 if(type == "SolveGeometryProblem")
417 {
418 if(this->verbose_)
419 std::cout << "-- Reassembly (SolveGeometryProblem)" << '\n';
420
421 solveGeometryProblem();
422 return;
423 }
424
425 if(type == "UpdateTime")
426 {
427 if(this->verbose_)
428 std::cout << "-- Reassembly (UpdateTime)" << '\n';
429
430 updateTime();
431 return;
432 }
433
434 if(type == "UpdateFluidInTime")
435 {
436 if(this->verbose_)
437 std::cout << "-- Reassembly (UpdateFluidInTime)" << '\n';
438
439 updateFluidInTime();
440 return;
441 }
442
443 if(type == "MoveMesh")
444 {
445 if(this->verbose_)
446 std::cout << "-- Reassembly (MoveMesh)" << '\n';
447
448 moveMesh();
449 return;
450 }
451
452 if(type == "AddInterfaceBlockRHS")
453 {
454 if(this->verbose_)
455 std::cout << "-- Reassembly (AddInterfaceBlockRHS)" << '\n';
456
457 addInterfaceBlockRHS();
458 return;
459 }
460
461 if(type == "ComputeFluidRHSInTime")
462 {
463 if(this->verbose_)
464 std::cout << "-- Reassembly (ComputeFluidRHSInTime)" << '\n';
465
466 computeFluidRHSInTime( );
467 return;
468 }
469 if(type == "ComputeSolidRHSInTime")
470 {
471 if(this->verbose_)
472 std::cout << "-- Reassembly (ComputeSolidRHSInTime)" << '\n';
473
474 computeSolidRHSInTime( );
475 return;
476 }
477 if(type == "ComputePressureRHSInTime")
478 {
479 if(this->verbose_)
480 std::cout << "-- Reassembly (ComputePressureRHSInTime)" << '\n';
481
482 computePressureRHSInTime();
483 return;
484 }
485
486
487 // ###############
488 // Berechne die Gittergeschwindigkeit w und FSI-Konvektion-Anteil (u-w)
489 // ###############
490 MultiVectorConstPtr_Type fluidSolution = this->solution_->getBlock(0);
491 u_rep_->importFromVector(fluidSolution, true);
492 u_minus_w_rep_->importFromVector(fluidSolution, true); // u_minus_w_rep_ = *u_rep_;
493
494 MultiVectorConstPtr_Type geometrySolution;
495 if(geometryExplicit_)
496 {
497 geometrySolution = this->problemGeometry_->getSolution()->getBlock(0);
498 }
499 else
500 {
501 geometrySolution = this->solution_->getBlock(4);
502 }
503 meshDisplacementNew_rep_->importFromVector(geometrySolution, true);
504
505 *w_rep_ = *meshDisplacementNew_rep_;
506 w_rep_->update(-1.0, *meshDisplacementOld_rep_, 1.0);
507 w_rep_->scale( 1.0/dt );
508
509 u_minus_w_rep_->update( -1.0, *w_rep_, 1.0 );
510
511 // Selbiges fuer den Druck
512 MultiVectorConstPtr_Type pressureSolution = this->solution_->getBlock(1);
513 p_rep_->importFromVector(pressureSolution, true);
514
515
516 // ###############
517 // Neu-Assemblierung zu Beginn der neuen Zeititeration im Falle von geometrisch explizit,
518 // da das Geometrieproblem zu Beginn der neuen Zeititeration geloest wird und sich somit
519 // das Gitter danach bewegt.
520 // ###############
521 if(type == "ForTime")
522 {
523 if(this->verbose_)
524 std::cout << "-- Reassembly (ForTime)" << '\n';
525
526 // Do we need ForTime at this point? see DAESolverInTime, is it only needed for extrapolation?
527 if(geometryExplicit_)
528 {
529 // ACHTUNG: Fluid-Loesung wird hier auf Null gesetzt, wegen initializeVectors().
530 // Somit dann auch die problemTimeFluid_ wodurch eine falsche BDF2-RHS entsteht.
531 // Rufe im DAESolverInTime deswegen erneut setPartialSolutions() auf.
532
533
534 this->problemFluid_->assembleConstantMatrices(); // Die Steifikeitsmatrix wird weiter unten erst genutzt
535
536 // Es ist P = P_
537 P_.reset(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getDimension() * this->getDomain(0)->getApproxEntriesPerRow() ) );
538// counterP++;
539// std::string outNameMeshVelo = "meshVelo" + to_string(counterP) + ".mm";
540// w_rep_->writeMM(outNameMeshVelo);
541// Teuchos::ArrayRCP<SC> values = w_rep_->getDataNonConst(0);
542// for (int i=0; i<values.size()/2; i++) {
543// values[2*i] = i;
544// }
545 this->feFactory_->assemblyAdditionalConvection( this->dim_, this->domain_FEType_vec_.at(0), P_, w_rep_, true );
546 P_->resumeFill();
547 P_->scale(density);
548 P_->scale(-1.0);
549// P_->scale(.0);
550 P_->fillComplete( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getMapVecFieldUnique());
551// std::string outNameP = "P" + to_string(counterP) + ".mm";
552// std::cout << "write P:"<<std::endl;
553// P_->writeMM( "P.mm" );
554 // Druck und Divergenz hinzufuegen
555 this->system_->addBlock( this->problemFluid_->system_->getBlock(0,1), 0, 1 );
556 this->system_->addBlock( this->problemFluid_->system_->getBlock(1,0), 1, 0 );
557 if (this->problemFluid_->system_->blockExists(1,1))
558 this->system_->addBlock( this->problemFluid_->system_->getBlock(1,1), 1, 1 );
559 }
560
561 return; // Damit wir nicht den ganzen Rest auch noch machen!
562 }
563
564
565 // ###############
566 // Neu-Assemblierung
567 // ###############
568 // Fluid: A+P+N+W
569 MatrixPtr_Type APNW = Teuchos::rcp(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getDimension() * this->getDomain(0)->getApproxEntriesPerRow() ) );
570
571 if(geometryExplicit_)
572 {
573
574 if(type == "FixedPoint")
575 {
576 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "should always be called by the residual and never here.");
577 }
578 else if(type == "Newton")
579 {
580 if(this->verbose_){
581 std::cout << "-- Reassembly GE (Newton)" << '\n';
582 std::cout << "-- Reassembly GE (Newton) ... full reassembly" << '\n';
583 }
584
585 problemFluid_->reAssemble( "Newton" );
586
587 if (materialModel_ != "linear")
588 this->problemStructureNonLin_->reAssemble("Newton");
589
590 }
591 }
592 else
593 {
594 if(type == "FixedPoint")
595 {
596 TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "should always be called by the residual and never here.");
597 }
598 else if(type == "Newton")
599 {
600 if(this->verbose_){
601 std::cout << "-- Reassembly GI (Newton)" << '\n';
602 std::cout << "-- Reassembly GI (Newton) ... only W" << '\n';
603 }
604
605 problemFluid_->reAssemble( "Newton" );
606
607 // TODO: Shape
608 // domain(0) = domain(4)
609 MatrixPtr_Type shapeVelocity = Teuchos::rcp(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getDimension() * this->getDomain(0)->getApproxEntriesPerRow() ) );
610 MatrixPtr_Type shapeDiv = Teuchos::rcp(new Matrix_Type( this->getDomain(1)->getMapUnique(), this->getDomain(1)->getDimension() * this->getDomain(1)->getApproxEntriesPerRow() ) ); // shape fuer div-Nebenbedingung
611
612 this->feFactory_->assemblyShapeDerivativeVelocity(this->dim_, this->domain_FEType_vec_.at(4), this->domain_FEType_vec_.at(1),
613 shapeVelocity, 4, u_rep_, w_rep_, p_rep_, dt, density, viscosity, true);
614 this->feFactory_->assemblyShapeDerivativeDivergence(this->dim_, this->domain_FEType_vec_.at(4), this->domain_FEType_vec_.at(1),
615 shapeDiv, 1, 4, this->getDomain(1)->getMapUnique(), this->getDomain(4)->getMapVecFieldUnique(), u_rep_, true);
616 shapeDiv->resumeFill();
617 shapeDiv->scale(-1.0);
618 shapeDiv->fillComplete(this->getDomain(4)->getMapVecFieldUnique(), this->getDomain(1)->getMapUnique());
619
620 // Shape Reinschreiben
621 this->system_->addBlock(shapeVelocity, 0, 4);
622 this->system_->addBlock(shapeDiv, 1, 4);
623
624 if (materialModel_ != "linear")
625 this->problemStructureNonLin_->reAssemble("Newton");
626
627 }
628 }
629
630 this->system_->addBlock( problemFluid_->getSystem()->getBlock( 0, 0 ), 0, 0 );
631
632 if (materialModel_ != "linear")
633 this->system_->addBlock( this->problemStructureNonLin_->getSystem()->getBlock(0,0), 2, 2 );
634}
635
636template<class SC,class LO,class GO,class NO>
637void FSI<SC,LO,GO,NO>::reAssembleExtrapolation(BlockMultiVectorPtrArray_Type previousSolutions)
638{
639 std::cout << "FSI<SC,LO,GO,NO>::reAssembleExtrapolation(BlockMultiVectorPtrArray_Type previousSolutions)"<< std::endl;
640 // double dt = this->parameterList_->sublist("Timestepping Parameter").get("dt",0.02);
641 // // Fluid-Dichte
642 // double density = this->problemFluid_->getParameterList()->sublist("Parameter").get("Density",1.);
643
644 // // ###############
645 // // w bestimmen
646 // // ###############
647 // MultiVectorConstPtr_Type geometrySolution;
648 // if(geometryExplicit_)
649 // {
650 // geometrySolution = this->problemGeometry_->getSolution()->getBlock(0);
651 // }
652 // else
653 // {
654 // geometrySolution = this->solution_->getBlock(4);
655 // }
656 // meshDisplacementNew_rep_->importFromVector(geometrySolution, true);
657
658
659 // *w_rep_ = *meshDisplacementNew_rep_;
660 // // update(): this = alpha*A + beta*this
661 // w_rep_->update(-1.0, *meshDisplacementOld_rep_, 1.0);
662 // w_rep_->scale(1.0/dt);
663
664
665 // // ###############
666 // // u extrapolieren
667 // // ###############
668 // // Beachte: getBlock(0) ist hier der Richtige, da dies der u-Variable in FSI entspricht.
669 // if (previousSolutions.size() >= 2)
670 // {
671 // MultiVectorPtr_Type extrapolatedVector = Teuchos::rcp( new MultiVector_Type( previousSolutions[0]->getBlock(0) ) );
672
673 // // Extrapolation fuer BDF2
674 // // update(): this = alpha*A + beta*this
675 // extrapolatedVector->update( -1., *previousSolutions[1]->getBlock(0), 2. );
676
677 // u_rep_->importFromVector(extrapolatedVector, true);
678 // }
679 // else if(previousSolutions.size() == 1)
680 // {
681 // MultiVectorConstPtr_Type u = previousSolutions[0]->getBlock(0);
682 // u_rep_->importFromVector(u, true);
683 // }
684 // else if (previousSolutions.size() == 0)
685 // {
686 // MultiVectorConstPtr_Type u = this->solution_->getBlock(0);
687 // u_rep_->importFromVector(u, true);
688 // }
689
690 // // (u-w)
691 // *u_minus_w_rep_ = *u_rep_;
692 // // update(): this = alpha*A + beta*this
693 // u_minus_w_rep_->update(-1.0, *w_rep_, 1.0);
694
695
696 // // ###############
697 // // Neu assemblieren
698 // // ###############
699
700 // MatrixPtr_Type APN = Teuchos::rcp(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getDimension() * this->getDomain(0)->getApproxEntriesPerRow() ) );
701
702 // MatrixPtr_Type N = Teuchos::rcp(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getDimension() * this->getDomain(0)->getApproxEntriesPerRow() ) );
703 // this->feFactory_->assemblyAdvectionVecField( this->dim_, this->domain_FEType_vec_.at(0), N, u_minus_w_rep_, true );
704
705 // P_.reset(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getDimension() * this->getDomain(0)->getApproxEntriesPerRow() ) );
706
707 // this->feFactory_->assemblyAdditionalConvection( this->dim_, this->domain_FEType_vec_.at(0), P_, w_rep_, true );
708 // P_->resumeFill();
709 // P_->scale(density);
710 // P_->scale(-1.0);
711 // P_->fillComplete( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getMapVecFieldUnique());
712
713
714 // N->resumeFill();
715 // N->scale(density);
716 // N->fillComplete( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getMapVecFieldUnique());
717
718 // this->problemFluid_->A_->addMatrix(1.0, APN, 0.0);
719 // P_->addMatrix(1.0, APN, 1.0);
720 // N->addMatrix(1.0, APN, 1.0);
721
722 // APN->fillComplete( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getMapVecFieldUnique() );
723
724 // this->system_->addBlock( APN, 0, 0 );
725}
726
727// Residual of FSI is defined as:
728// GI (Geometry Implicit)
729// |b_f | | F(u,p,d_f) 0 C_1^T 0 |
730//R= |b_s | - | 0 S C_3^T 0 |
731// |C_2*d_s | | C_1 C_2 0 0 |
732// |0 | | 0 C_4 0 G |
733//
734// GE (Geometry Implicit)
735// |b_f | | F(u,p,d_f) 0 C_1^T 0 |
736//R= |b_s | - | 0 S C_3^T 0 |
737// |C_2*d_s | | C_1 C_2 0 0 |
738
739template<class SC,class LO,class GO,class NO>
740void FSI<SC,LO,GO,NO>::calculateNonLinResidualVec(std::string type, double time) const
741{
742
743 MultiVectorConstPtr_Type geometrySolution;
744
745 if(geometryExplicit_)
746 geometrySolution = this->problemGeometry_->getSolution()->getBlock(0);
747 else {
748 moveMesh();
749 geometrySolution = this->solution_->getBlock(4);
750 }
751
752 meshDisplacementNew_rep_->importFromVector(geometrySolution, true);
753
754 MultiVectorConstPtr_Type fluidSolution = this->solution_->getBlock(0);
755 u_rep_->importFromVector(fluidSolution, true);
756 u_minus_w_rep_->importFromVector(fluidSolution, true); // u_minus_w_rep_ = *u_rep_;
757
758 *w_rep_ = *meshDisplacementNew_rep_;
759 w_rep_->update(-1.0, *meshDisplacementOld_rep_, 1.0);
760 double dt = this->parameterList_->sublist("Timestepping Parameter").get("dt",0.02);
761 w_rep_->scale(1.0/dt);
762
763 u_minus_w_rep_->update(-1.0, *w_rep_, 1.0);
764
765 if (!geometryExplicit_) {
766
767 P_.reset(new Matrix_Type( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getDimension() * this->getDomain(0)->getApproxEntriesPerRow() ) );
768 double density = this->problemTimeFluid_->getParameterList()->sublist("Parameter").get("Density",1000.e-0);
769
770 this->feFactory_->assemblyAdditionalConvection( this->dim_, this->domain_FEType_vec_.at(0), P_, w_rep_, true );
771 P_->resumeFill();
772 P_->scale(density);
773 P_->scale(-1.0);
774 P_->fillComplete( this->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getMapVecFieldUnique());
775
776 problemFluid_->assembleConstantMatrices();
777
778 this->system_->addBlock( this->problemFluid_->system_->getBlock(0,1), 0, 1 );
779 this->system_->addBlock( this->problemFluid_->system_->getBlock(1,0), 1, 0 );
780 if (this->problemFluid_->system_->blockExists(1,1))
781 this->system_->addBlock( this->problemFluid_->system_->getBlock(1,1), 1, 1 );
782 // TEUCHOS_TEST_FOR_EXCEPTION(this->problemFluid_->system_->blockExists(1,1) , std::runtime_error, "Stabilization is used. Account for it."); ???
783 }
784 if ( this->verbose_ )
785 std::cout << "Warning: Wrong consideration of temporal discretization for multi-stage RK methods!" << std::endl;
786
787 this->problemFluid_->calculateNonLinResidualVecWithMeshVelo( "reverse", time, u_minus_w_rep_, P_ );
788 this->system_->addBlock( problemFluid_->getSystem()->getBlock( 0, 0 ), 0, 0 );
789
790 // we need to account for the coupling in the residuals
791 if (materialModel_!="linear"){
792 this->problemStructureNonLin_->calculateNonLinResidualVec( "reverse", time );
793 this->residualVec_->addBlock( this->problemStructureNonLin_->getResidualVector()->getBlockNonConst(0) , 2);
794 // we need to add a possible source term
795 }
796 else{
797 MultiVectorPtr_Type residualSolidFSI =
798 Teuchos::rcp_const_cast<MultiVector_Type>( this->residualVec_->getBlock(2) );
799 this->problemStructure_->getSystem()->getBlock(0,0)->apply( *this->problemStructure_->getSolution()->getBlock(0), *residualSolidFSI, Teuchos::NO_TRANS, -1. ); // y= -Ax + 0*y
800 MultiVectorPtr_Type resSolidNonConst = Teuchos::rcp_const_cast<MultiVector_Type> ( this->residualVec_->getBlock(2) );
801 resSolidNonConst->update(1., *this->problemStructure_->getRhs()->getBlock(0), 1.);
802 // we need to add a possible source term
803 }
804
805 MultiVectorPtr_Type residualFluidVelocityFSI =
806 Teuchos::rcp_const_cast<MultiVector_Type>( this->residualVec_->getBlock(0) ); // residual of fluid part
807
808 MultiVectorPtr_Type residualSolidFSI =
809 Teuchos::rcp_const_cast<MultiVector_Type>( this->residualVec_->getBlock(2) ); // residual of solid part
810
811 MultiVectorPtr_Type residualCouplingFSI =
812 Teuchos::rcp_const_cast<MultiVector_Type>( this->residualVec_->getBlock(3) ); // residual of interface / lambda
813 residualCouplingFSI->update( 1. , *this->rhs_->getBlock(3), 0. ); // change to -1 for standard
814
815 //Now we need to add the coupling blocks
816 // adding C_1^T * \lambda to fluid residual
817 this->system_->getBlock(0,3)->apply( *this->solution_->getBlock(3) , *residualFluidVelocityFSI, Teuchos::NO_TRANS, -1., 1. );
818
819 // adding C_3 ^T * \lambda to solid residual
820 this->system_->getBlock(2,3)->apply( *this->solution_->getBlock(3) , *residualSolidFSI, Teuchos::NO_TRANS, -1., 1. );
821
822 // adding C_1 * u to coupling/lambda
823 this->system_->getBlock(3,0)->apply( *this->solution_->getBlock(0) , *residualCouplingFSI, Teuchos::NO_TRANS, -1., 1. );
824
825 // adding C_2 * d_s to coupling/lambda
826 this->system_->getBlock(3,2)->apply( *this->solution_->getBlock(2) , *residualCouplingFSI, Teuchos::NO_TRANS, -1., 1. );
827
828 if (!geometryExplicit_) {
829 // If we have GI coupling we need to add that component to residual as well
830 MultiVectorPtr_Type residualGeometryFSI =
831 Teuchos::rcp_const_cast<MultiVector_Type>( this->residualVec_->getBlock(4) );
832
833 residualGeometryFSI->update( 1. , *this->rhs_->getBlock(4), 0. ); // change to -1 for standard
834 // G * d_f
835 this->system_->getBlock(4,4)->apply( *this->solution_->getBlock(4) , *residualGeometryFSI, Teuchos::NO_TRANS, -1., 1. );
836 // C_4 * d_f
837 this->system_->getBlock(4,2)->apply( *this->solution_->getBlock(2) , *residualGeometryFSI, Teuchos::NO_TRANS, -1., 1. );
838
839 }
840 // might also be called in the sub calculateNonLinResidualVec() methods which where used above
841 if (type == "reverse")
842 this->bcFactory_->setBCMinusVector( this->residualVec_, this->solution_, time );
843 else if (type == "standard"){
844 this->residualVec_->scale(-1.);
845 this->bcFactory_->setVectorMinusBC( this->residualVec_, this->solution_, time );
846 }
847
848
849}
850
851template <class SC, class LO, class GO, class NO>
852void FSI<SC, LO, GO, NO>::calculateNonLinResidualVec(SmallMatrix<double> &coeff, std::string type, double time, BlockMatrixPtr_Type systemMass)
853{
855
856 // for FSI we need to reassemble the massmatrix system if the mesh was moved for geometry implicit computations
857 bool geometryExplicit = this->parameterList_->sublist("Parameter").get("Geometry Explicit",true);
858 if( !geometryExplicit ) {
859 MatrixPtr_Type massmatrix;
860 this->setFluidMassmatrix( massmatrix );
861 systemMass->addBlock( massmatrix, 0, 0 );
862 }
863}
864
865// Muss derzeit nur am Anfang jeder Zeititeration aufgerufen werden, damit
866// problemTimeFluid_ und problemTimeStructure_ die aktuelle Loesung haben.
867// ACHTUNG: Wenn wir irgendwann einmal anfangen reAssemble() auf problemFluid_ und
868// problemStructure_ aufzurufen, dann muessen wir in jeder nichtlinearen Iteration
869// diese setPartialSolutions() aufrufen, damit problemFluid_ und problemStructure_
870// den korrekten nichtlinearen Term ausrechnen koennen.
871// CH: Ist das noch relevant?
872// We need to build FSI so this method is not needed anymore
873template<class SC,class LO,class GO,class NO>
874void FSI<SC,LO,GO,NO>::setFromPartialVectorsInit() const
875{
876
877 //Fluid velocity
878 this->solution_->addBlock( this->problemFluid_->getSolution()->getBlockNonConst(0), 0 );
879 this->residualVec_->addBlock( this->problemFluid_->getResidualVector()->getBlockNonConst(0), 0 );
880 this->residualVec_->addBlock( this->problemFluid_->getResidualVector()->getBlockNonConst(0), 0 );
881 this->rhs_->addBlock( this->problemFluid_->getRhs()->getBlockNonConst(0), 0 );
882 this->sourceTerm_->addBlock( this->problemFluid_->getSourceTerm()->getBlockNonConst(0), 0 );
883
884 //Fluid pressure
885 this->solution_->addBlock( this->problemFluid_->getSolution()->getBlockNonConst(1), 1 );
886 this->residualVec_->addBlock( this->problemFluid_->getResidualVector()->getBlockNonConst(1), 1 );
887 this->rhs_->addBlock( this->problemFluid_->getRhs()->getBlockNonConst(1), 1 );
888 this->previousSolution_->addBlock( this->problemFluid_->getPreviousSolution()->getBlockNonConst(1), 1 );
889 this->sourceTerm_->addBlock( this->problemFluid_->getSourceTerm()->getBlockNonConst(1), 1 );
890
891 if (materialModel_=="linear"){
892 this->solution_->addBlock( this->problemStructure_->getSolution()->getBlockNonConst(0), 2 );
893 // we dont have a residual vector for linear problems
894 this->rhs_->addBlock( this->problemStructure_->getRhs()->getBlockNonConst(0), 2 );
895 this->sourceTerm_->addBlock( this->problemStructure_->getSourceTerm()->getBlockNonConst(0), 2 );
896 }
897 else{
898 this->solution_->addBlock( this->problemStructureNonLin_->getSolution()->getBlockNonConst(0), 2 );
899 this->residualVec_->addBlock( this->problemStructureNonLin_->getResidualVector()->getBlockNonConst(0), 2 );
900 this->rhs_->addBlock( this->problemStructureNonLin_->getRhs()->getBlockNonConst(0), 2 );
901 this->previousSolution_->addBlock( this->problemStructureNonLin_->getPreviousSolution()->getBlockNonConst(0), 2 );
902 this->sourceTerm_->addBlock( this->problemStructureNonLin_->getSourceTerm()->getBlockNonConst(0), 2 );
903 }
904
905 if(!geometryExplicit_){
906 this->solution_->addBlock( this->problemGeometry_->getSolution()->getBlockNonConst(0), 4 );
907 // we dont have a previous solution for linear problems
908 this->rhs_->addBlock( this->problemGeometry_->getRhs()->getBlockNonConst(0), 4 );
909 this->sourceTerm_->addBlock( this->problemGeometry_->getSourceTerm()->getBlockNonConst(0), 4 );
910 }
911}
912
913template<class SC,class LO,class GO,class NO>
914void FSI<SC,LO,GO,NO>::updateMeshDisplacement() const
915{
916
917 *meshDisplacementOld_rep_ = *meshDisplacementNew_rep_;
918
919}
920
921
922template<class SC,class LO,class GO,class NO>
923void FSI<SC,LO,GO,NO>::solveGeometryProblem() const
924{
925 DomainPtr_Type domainFluid = Teuchos::rcp_const_cast<Domain_Type>(this->getDomain(0));
926 DomainPtr_Type domainStruct = Teuchos::rcp_const_cast<Domain_Type>(this->getDomain(2));
927
928 // Hole die dof-Map
929 MapConstPtr_Type interfaceMapFluidVecField = domainFluid->getInterfaceMapVecFieldUnique();
930 MapConstPtr_Type interfaceMapStructureVecField = domainStruct->getInterfaceMapVecFieldUnique();
931
932 MapConstPtr_Type interfaceMapGlobalFluidVecField = domainFluid->getGlobalInterfaceMapVecFieldUnique();
933 MapConstPtr_Type interfaceMapGlobalStructureVecField = domainStruct->getGlobalInterfaceMapVecFieldUnique();
934
935 MeshUnstrPtr_Type meshUnstructuredFluid = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domainFluid->getMesh() );
936 vec3D_GO_ptr_Type indicesGlobalMatchedOriginFluid = meshUnstructuredFluid->getMeshInterface()->getIndicesGlobalMatchedOrigin();
937
938 // Strukturloesung holen
939 MultiVectorConstPtr_Type struc_sol_unique = this->solution_->getBlock(2);
940
941 // Extrahiere nun aus der globalen Strukturloesung die Loesung auf dem Interface (in parallel).
942 MultiVectorPtr_Type interfaceSolutionStruct = Teuchos::rcp( new MultiVector_Type( interfaceMapStructureVecField, 1 ) );
943
944 {
945 int flagCounter = 0;
946 Teuchos::ArrayRCP< SC > valuesInterface = interfaceSolutionStruct->getDataNonConst(0); //single MultiVector
947 Teuchos::ArrayRCP< SC > valuesStructure = struc_sol_unique->getDataNonConst(0); //single MultiVector
948
949 for(UN i = 0; i < valuesInterface.size(); i++)
950 {
951 GO interfaceIDGlobal = interfaceMapGlobalStructureVecField->getGlobalElement( i ); // ID (vektorwertig, also dofID) in der Interface-Nummerierung
952// GO nodeID; // nodeID der interfaceID in der Interface-Nummerierung
953// LO localDofNumber; // Ranges from 0 to dofs-1
954// toNodeID(this->dim_, interfaceID, nodeID, localDofNumber); //This function assumes NodeWise ordering.
955//
956// // Ggf. ist die ID auf einer anderen Flag.
957// // Bei nur einer Interface-Flag kommt man nicht hier hinein.
958// while( nodeID > indicesGlobalMatchedOriginFluid->at(flagCounter).at(0).size()-1 )
959// {
960// nodeID = nodeID - indicesGlobalMatchedOriginFluid->at(flagCounter).at(0).size();
961// flagCounter = flagCounter + 1; // hier steht dann die korrekte Flag
962// }
963//
964// // Beachte: at(1) ist Struktur!!!
965// // GlobaleID des Interface-Knotens in der Struktur-Nummerierung
966// GO globalInterfaceIDNode = indicesGlobalMatchedOriginFluid->at(flagCounter).at(1).at(nodeID);
967// GO globalInterfaceIDinStructure; // dofID
968// toDofID(this->dim_, globalInterfaceIDNode, localDofNumber, globalInterfaceIDinStructure);
969
970 // LokaleID auf dem Prozessor vom Interface-Knoten.
971 LO localInterfaceIDinStructure = domainStruct->getMapVecFieldUnique()->getLocalElement(interfaceIDGlobal);
972
973 valuesInterface[i] = valuesStructure[localInterfaceIDinStructure];
974 }
975 }
976
977 MultiVectorPtr_Type interfaceSolutionFluid = Teuchos::rcp( new MultiVector_Type( interfaceMapFluidVecField, 1 ) );
978 interfaceSolutionFluid->importFromVector( interfaceSolutionStruct );
979
980 {
981 // Strukturlsg als RW setzen (per Hand)
982 this->problemGeometry_->setBoundariesSystem(); // RW im System setzen (mit den Flags von oben)
983 this->problemGeometry_->getRhs()->putScalar(0.0);
984
985 Teuchos::ArrayRCP< SC > valuesInterface = interfaceSolutionFluid->getDataNonConst(0); //single MultiVector
986 Teuchos::ArrayRCP< SC > valuesFluidRhs = this->problemGeometry_->getRhs()->getBlock(0)->getDataNonConst(0); //single MultiVector
987
988 int flagCounter = 0;
989 for(UN i = 0; i < valuesInterface.size(); i++)
990 {
991 GO interfaceIDGlobal = interfaceMapGlobalFluidVecField->getGlobalElement( i );
992// GO interfaceID = interfaceMapFluidVecField->getGlobalElement( i ); // dofID in der Interface-Nummerierung
993// GO nodeID; // dofID der interfaceID in der Interface-Nummerierung
994// LO localDofNumber; // Ranges from 0 to dofs-1
995// toNodeID(this->dim_, interfaceID, nodeID, localDofNumber);//This function assumes NodeWise ordering.
996//
997// // Ggf. ist die ID auf einer anderen Flag.
998// // Bei nur einer Interface-Flag kommt man nicht hier hinein.
999// while(nodeID > indicesGlobalMatchedOriginFluid->at(flagCounter).at(0).size()-1)
1000// {
1001// nodeID = nodeID - indicesGlobalMatchedOriginFluid->at(flagCounter).at(0).size();
1002// flagCounter = flagCounter + 1; // hier steht dann die korrekte Flag
1003// }
1004//
1005// // Beachte: at(0) ist Fluid!!!
1006// // GlobaleID des Interface-Knotens in der Fluid-Nummerierung
1007// GO globalInterfaceIDNode = indicesGlobalMatchedOriginFluid->at(flagCounter).at(0).at(nodeID);
1008// GO globalInterfaceIDinFluid; // dofID
1009// toDofID(this->dim_, globalInterfaceIDNode, localDofNumber, globalInterfaceIDinFluid);
1010
1011 // LokaleID auf dem Prozessor des Interface-Knotens.
1012 LO localInterfaceIDinFluid = domainFluid->getMapVecFieldUnique()->getLocalElement(interfaceIDGlobal);
1013
1014 valuesFluidRhs[localInterfaceIDinFluid] = valuesInterface[i];
1015
1016 // valuesFluidRhs[localInterfaceIDinFluid.at(i)] = valuesInterface[i];
1017 }
1018
1019 this->problemGeometry_->solve();
1020
1021 if (!exporterGeo_.is_null())
1022 this->exporterGeo_->save( this->timeSteppingTool_->currentTime() );
1023
1024
1025 }
1026
1027
1028
1029}
1030
1031
1032template<class SC,class LO,class GO,class NO>
1033void FSI<SC,LO,GO,NO>::setupSubTimeProblems(ParameterListPtr_Type parameterListFluid, ParameterListPtr_Type parameterListStructure) const
1034{
1035 if(this->verbose_)
1036 std::cout << "-- Setup FSI Sub-TimeProblems \n" << std::flush;
1037
1038 double dt = timeSteppingTool_->get_dt();
1039 double beta = timeSteppingTool_->get_beta();
1040
1041 int sizeFluid = this->problemFluid_->getSystem()->size();
1042 int sizeStructure;
1043 if (materialModel_=="linear")
1044 sizeStructure = this->problemStructure_->getSystem()->size();
1045 else
1046 sizeStructure = this->problemStructureNonLin_->getSystem()->size();
1047
1048 problemTimeFluid_.reset(new TimeProblem<SC,LO,GO,NO>(*this->problemFluid_, this->comm_));
1049 if (materialModel_=="linear")
1050 problemTimeStructure_.reset(new TimeProblem<SC,LO,GO,NO>(*this->problemStructure_, this->comm_));
1051 else
1052 problemTimeStructure_.reset(new TimeProblem<SC,LO,GO,NO>(*this->problemStructureNonLin_, this->comm_));
1053
1054 // ######################
1055 // Fluid: Mass-, Problem, SourceTerm Koeffizienten
1056 // ######################
1057 SmallMatrix<double> massCoeffFluid(sizeFluid);
1058 SmallMatrix<double> problemCoeffFluid(sizeFluid);
1059 SmallMatrix<int> defFluid(sizeFluid);
1060
1061 double coeffSourceTermFluid = 0.0;
1062 if ( this->getParameterList()->sublist("Timestepping Parameter").get("Class","Multistep") == "Multistep" ) {
1063 for (int i=0; i<sizeFluid; i++) {
1064 for (int j=0; j<sizeFluid; j++) {
1065 if ((*defTS_)[i][j]==1 && i==j) {
1066 defFluid[i][j] = 1;
1067 massCoeffFluid[i][j] = timeSteppingTool_->getInformationBDF(0) / dt;
1068 }
1069 else{
1070 massCoeffFluid[i][j] = 0.0;
1071 }
1072 }
1073 }
1074 for (int i=0; i<sizeFluid; i++) {
1075 for (int j=0; j<sizeFluid; j++){
1076 if ((*defTS_)[i][j]==1){
1077 problemCoeffFluid[i][j] = timeSteppingTool_->getInformationBDF(1);
1078 coeffSourceTermFluid = timeSteppingTool_->getInformationBDF(1);
1079 }
1080 else{
1081 problemCoeffFluid[i][j] = 1.;
1082 }
1083 }
1084 }
1085 this->problemTimeFluid_->setTimeDef(defFluid);
1086 this->problemTimeFluid_->setTimeParameters(massCoeffFluid,problemCoeffFluid);
1087 }
1088 else{
1089 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Implement other FSI fluid time stepping than BDF.");
1090 }
1091 // ######################
1092 // Struktur: Mass-, Problem, SourceTerm Koeffizienten
1093 // ######################
1094 // Koeffizienten vor der Massematrix und vor der Systemmatrix des steady-Problems
1095 SmallMatrix<double> massCoeffStructure(sizeStructure);
1096 SmallMatrix<double> problemCoeffStructure(sizeStructure);
1097 SmallMatrix<int> defStructure(sizeStructure);
1098 double coeffSourceTermStructure = 0.0; // Koeffizient fuer den Source-Term (= rechte Seite der DGL); mit Null initialisieren
1099
1100 // Koeffizient vor der Massematrix
1101 for(int i = 0; i < sizeStructure; i++)
1102 {
1103 for(int j = 0; j < sizeStructure; j++)
1104 {
1105 // Falls in dem Block von timeStepDef_ zeitintegriert werden soll.
1106 // i == j, da vektorwertige Massematrix blockdiagonal ist
1107 if((*defTS_)[i + sizeFluid][j + sizeFluid] == 1 && i == j) // Weil: (u_f, p, d_s,...) und timeStepDef_ von FSI
1108 {
1109 defStructure[i][j] = 1;
1110 // Vorfaktor der Massematrix in der LHS
1111 massCoeffStructure[i][j] = 1.0/(dt*dt*beta);
1112 }
1113 else
1114 {
1115 massCoeffStructure[i][j] = 0.;
1116 }
1117 }
1118 }
1119
1120 // Die anderen beiden Koeffizienten
1121 for(int i = 0; i < sizeStructure; i++)
1122 {
1123 for(int j = 0; j < sizeStructure; j++)
1124 {
1125 if((*defTS_)[i + sizeFluid][j + sizeFluid] == 1)
1126 {
1127 problemCoeffStructure[i][j] = 1.0;
1128 // Der Source Term ist schon nach der Assemblierung mit der Dichte \rho skaliert worden
1129 coeffSourceTermStructure = 1.0; // ACHTUNG FUER SOURCE TERM, DER NICHT IN DER ZEIT DISKRETISIERT WIRD!
1130 }
1131 else // Die steady-Systemmatrix ist nicht zwingend blockdiagonal
1132 {
1133 problemCoeffStructure[i][j] = 1.0;
1134 }
1135 }
1136 }
1137 this->problemTimeStructure_->setTimeDef(defStructure);
1138 this->problemTimeStructure_->setTimeParameters(massCoeffStructure,problemCoeffStructure);
1139
1140 this->problemTimeFluid_->assemble( "MassSystem" );
1141 this->problemTimeStructure_->assemble( "MassSystem" );
1142}
1143
1144
1145template<class SC,class LO,class GO,class NO>
1146void FSI<SC,LO,GO,NO>::setFluidMassmatrix( MatrixPtr_Type& massmatrix ) const
1147{
1148 //######################
1149 // Massematrix fuer FSI combineSystems(), ggf nichtlinear.
1150 //######################
1151 double density = this->problemTimeFluid_->getParameterList()->sublist("Parameter").get("Density",1000.e-0);
1152 int size = this->problemTimeFluid_->getSystem()->size();
1153
1154 this->problemTimeFluid_->systemMass_.reset(new BlockMatrix_Type(size));
1155 {
1156 massmatrix = Teuchos::rcp(new Matrix_Type( this->problemTimeFluid_->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getApproxEntriesPerRow() ) );
1157 // 0 = Fluid
1158 this->feFactory_->assemblyMass( this->dim_, this->problemTimeFluid_->getFEType(0), "Vector", massmatrix, 0, true );
1159 massmatrix->resumeFill();
1160 massmatrix->scale(density);
1161 massmatrix->fillComplete( this->problemTimeFluid_->getDomain(0)->getMapVecFieldUnique(), this->problemTimeFluid_->getDomain(0)->getMapVecFieldUnique() );
1162
1163 this->problemTimeFluid_->systemMass_->addBlock(massmatrix, 0, 0);
1164 }
1165}
1166
1167
1168// Function to compute the pressure boundary conditions for the fluid component
1169// Note it already contains some code connected to restarts
1170template<class SC,class LO,class GO,class NO>
1171void FSI<SC,LO,GO,NO>::computePressureRHSInTime() const{
1172
1173 // Type of pressure boundary condition
1174 std::string pressureRB = this->parameterList_->sublist("Parameter Fluid").get("Pressure Boundary Condition","None");
1175
1176 // bool restart = this->parameterList_->sublist("Timestepping Parameter").get("Restart", false);
1177 // double timeStepRestart = this->parameterList_->sublist("Timestepping Parameter").get("Time step", 0.0);
1178
1179 // Resistance boundary condition based on 'A parallel two-level method for simulating blood flows in branching arteries
1180 // with the resistive boundary condition -- Wu, Cai 2011'
1181 // We assemble
1182 // \int_{\Gamma_O} R flowrateOutlet \phi_f n ds + nu_f \int_{\Omega_O} \phi_f \cdot (\nabla u_f) \cdot n ds
1183 if (pressureRB == "Resistance")
1184 {
1185 if(this->verbose_)
1186 std::cout << " --- Computing resistance boundary condition .. " << std::endl;
1187
1188 // Value added to the RHS of the fluid component
1189 MultiVectorPtr_Type FERhs = Teuchos::rcp(new MultiVector_Type( this->getDomain(0)->getMapVecFieldRepeated() ));
1190
1191 // Parameters for pressure ramp
1192 vec_dbl_Type funcParameter(1,0.);
1193 funcParameter[0] = timeSteppingTool_->t_;
1194
1195 // We need the outlet are thus we need to know the flags, as they are not always the same
1196 int flagInlet =this->parameterList_->sublist("General").get("Flag Inlet Fluid", 4);
1197 int flagOutlet = this->parameterList_->sublist("General").get("Flag Outlet Fluid", 5);
1198
1199 // We compute the initial flow rate in the first timestep
1200 if (timeSteppingTool_->currentTime()==0.) {
1201 double flowRateInlet_n_1 = 0.;
1202 this->feFactory_->assemblyFlowRate(this->dim_, flowRateInlet_n_1, this->getDomain(0)->getFEType() , this->dim_, flagOutlet , u_rep_);
1203 flowRateOutlet_n_1_ = flowRateInlet_n_1;
1204 }
1205 // else if(restart && timeStepRestart +1e-8 > timeSteppingTool_->currentTime() )
1206 // {
1207 // if(this->verbose_)
1208 // cout << " WARNING: Absorbing boundary condition is computed but the initial values usally corresponding to T=0 now correspond to the restart time " << endl;
1209
1210 // double flowRateInlet_n_1 = 0.;
1211 // this->feFactory_->assemblyFlowRate(this->dim_, flowRateInlet_n_1, this->getDomain(0)->getFEType() , this->dim_, flagOutlet , u_rep_);
1212 // flowRateOutlet_n_1_ = flowRateInlet_n_1;
1213
1214 // }
1215
1216 // Then we compute the flowrate in the current time step
1217 double flowRateInlet_n = 0.;
1218 this->feFactory_->assemblyFlowRate(this->dim_, flowRateInlet_n, this->getDomain(0)->getFEType() , this->dim_, flagOutlet , u_rep_);
1219 flowRateOutlet_n_ = flowRateInlet_n;
1220
1221 vec_dbl_Type flowRateOutlet_timesteps(2);
1222 flowRateOutlet_timesteps[0] = flowRateOutlet_n_1_;
1223 flowRateOutlet_timesteps[1] = flowRateOutlet_n_;
1224
1225 MultiVectorConstPtr_Type u = this->solution_->getBlock(0);
1226 u_rep_->importFromVector(u, true);
1227
1228 // We compute the pressure value set on the outlet of the domain based on the resitive boundary
1229 pressureOutlet_ = this->feFactory_->assemblyResistanceBoundary(this->dim_, this->getDomain(0)->getFEType(),FERhs, u_rep_,flowRateOutlet_timesteps, funcParameter, pressureRamp,this->parameterList_,0);
1230
1231 flowRateOutlet_n_1_ = flowRateOutlet_n_;
1232
1233 this->sourceTerm_->getBlockNonConst(0)->exportFromVector( FERhs, false, "Add" );
1234
1235 //double density = this->parameterList_->sublist("Parameter").get("Density",1.);
1236 //this->problemTimeFluid_->getSourceTerm()->scale(density);
1237 // Fuege die rechte Seite der DGL (f bzw. f_{n+1}) der rechten Seite hinzu (skaliert mit coeffSourceTerm)
1238 // Die Skalierung mit der Dichte erfolgt schon in der Assemblierungsfunktion!
1239
1240 // addSourceTermToRHS() aus DAESolverInTime
1241 double coeffSourceTermStructure = 1.0;
1242 // BlockMultiVectorPtr_Type tmpSourceterm = Teuchos::rcp(new BlockMultiVector_Type(1)) ;
1243 // tmpSourceterm->addBlock(this->sourceTerm_->getBlockNonConst(1),0);
1244
1245
1246 this->problemTimeFluid_->getRhs()->getBlockNonConst(0)->update(coeffSourceTermStructure, *this->sourceTerm_->getBlockNonConst(0), 1.);
1247 this->rhs_->addBlock( this->problemTimeFluid_->getRhs()->getBlockNonConst(0), 0 );
1248
1249 if(this->verbose_)
1250 std::cout << " .. done " << std::endl;
1251
1252
1253 }
1254 // Absorbing boundary condition implemented as introduced in
1255 // 'AN EFFECTIVE FLUID-STRUCTURE INTERACTION FORMULATION FOR VASCULAR DYNAMICS BY GENERALIZED
1256 // ROBIN CONDITIONS, Nobile, Vergara, 2008'
1257 if (pressureRB == "Absorbing" || pressureRB == "Absorbing Paper")
1258 {
1259 if(this->verbose_)
1260 std::cout << " Computing absorbing boundary condition .. " << std::endl;
1261
1262 MultiVectorPtr_Type FERhs = Teuchos::rcp(new MultiVector_Type( this->getDomain(0)->getMapVecFieldRepeated() ));
1263
1264 // Parameters for pressure ramp
1265 vec_dbl_Type funcParameter(1,0.);
1266 funcParameter[0] = timeSteppingTool_->t_;
1267
1268 MultiVectorConstPtr_Type u = this->solution_->getBlock(0);
1269 u_rep_->importFromVector(u, true);
1270
1271 int flagInlet =this->parameterList_->sublist("General").get("Flag Inlet Fluid", 4);
1272 int flagOutlet = this->parameterList_->sublist("General").get("Flag Outlet Fluid", 5);
1273
1274 if (timeSteppingTool_->currentTime()==0.) {
1275 double areaInlet_init = 0.;
1276 double areaOutlet_init = 0.;
1277
1278 this->feFactory_->assemblyArea(this->dim_,areaInlet_init, flagInlet);
1279 this->feFactory_->assemblyArea(this->dim_, areaOutlet_init, flagOutlet);
1280
1281 areaInlet_init_ = areaInlet_init;
1282 areaOutlet_init_ = areaOutlet_init;
1283
1284 double flowRateInlet_n_1 = 0.;
1285 this->feFactory_->assemblyFlowRate(this->dim_, flowRateInlet_n_1, this->getDomain(0)->getFEType() , this->dim_, flagOutlet , u_rep_);
1286 flowRateOutlet_n_1_ = flowRateInlet_n_1;
1287
1288 if ( this->parameterList_->sublist("Timestepping Parameter").get("Checkpointing", false)){
1289 exporterBoundaryCondition_->exportData( "Area_Inlet ", areaInlet_init );
1290 exporterBoundaryCondition_->exportData( "Area_Outlet ", areaInlet_init );
1291 }
1292 }
1293 // else if(restart && timeStepRestart +1e-8 > timeSteppingTool_->currentTime() )
1294 // {
1295 // if(this->verbose_)
1296 // cout << " WARNING: Absorbing boundary condition is computed but the initial values usally corresponding to T=0 now correspond to the restart time " << endl;
1297 // double areaInlet_init = 0.;
1298 // double areaOutlet_init = 0.;
1299
1300 // this->feFactory_->assemblyArea(this->dim_,areaInlet_init, flagInlet);
1301 // this->feFactory_->assemblyArea(this->dim_, areaOutlet_init, flagOutlet);
1302
1303 // areaInlet_init_ = 0.0253605;//areaInlet_init;
1304 // areaOutlet_init_ = 0.025605; //areaOutlet_init;
1305
1306 // double flowRateInlet_n_1 = 0.;
1307 // this->feFactory_->assemblyFlowRate(this->dim_, flowRateInlet_n_1, this->getDomain(0)->getFEType() , this->dim_, flagOutlet , u_rep_);
1308 // flowRateOutlet_n_1_ = flowRateInlet_n_1;
1309 // }
1310 double flowRateInlet_n = 0.;
1311 this->feFactory_->assemblyFlowRate(this->dim_, flowRateInlet_n, this->getDomain(0)->getFEType() , this->dim_, flagOutlet , u_rep_);
1312 flowRateOutlet_n_ = flowRateInlet_n;
1313
1314 vec_dbl_Type flowRateOutlet_timesteps(2);
1315 flowRateOutlet_timesteps[0] = flowRateOutlet_n_1_;
1316 flowRateOutlet_timesteps[1] = flowRateOutlet_n_;
1317
1318 // The traditional approach differs slightly from the approach used in Comparison of arterial wall models in fluid–structure interaction
1319 // simulations D. Balzani, A. Heinlein, A. Klawonn, O. Rheinbach, J. Schröder, 2023, and its predecessor. Thus, absorbing paper refers to
1320 // the aforementioned paper.
1321 if(pressureRB == "Absorbing Paper"){
1322
1323 double unsteadyStart = this->parameterList_->sublist("Parameter Fluid").get("Unsteady Start",0.1);
1324 if( unsteadyStart +1e-10 > timeSteppingTool_->currentTime() && unsteadyStart -1e-10 < timeSteppingTool_->currentTime() )
1325 {
1326 double areaOutlet_T = 0.;
1327 this->feFactory_->assemblyArea(this->dim_, areaOutlet_T, flagOutlet);
1328 areaOutlet_T_ = areaOutlet_T;
1329 if(this->verbose_)
1330 std::cout << " ---- Absorbing boundary condition: Start of unsteady Phase with areaOutlet_T=" << areaOutlet_T_<< " ---- " << std::endl;
1331 }
1332
1333 pressureOutlet_ = this->feFactory_->assemblyAbsorbingBoundaryPaper(this->dim_, this->getDomain(0)->getFEType(),FERhs, u_rep_,flowRateOutlet_timesteps, funcParameter, pressureRamp,areaOutlet_init_, areaOutlet_T_,this->parameterList_,0);
1334
1335 }
1336 else{
1337 double rampTime = this->parameterList_->sublist("Parameter").get("Max Ramp Time",0.1);
1338 if( rampTime < timeSteppingTool_->currentTime() && rampTime + 0.05 > timeSteppingTool_->currentTime() )
1339 {
1340 double areaOutlet_T = 0.;
1341 this->feFactory_->assemblyArea(this->dim_, areaOutlet_T, flagOutlet);
1342 areaOutlet_T_ = areaOutlet_T;
1343 if(this->verbose_)
1344 std::cout << " ---- Absorbing boundary condition: Start of unsteady Phase with areaOutlet_T=" << areaOutlet_T_<< " ---- " << std::endl;
1345 }
1346 pressureOutlet_ = this->feFactory_->assemblyAbsorbingBoundary(this->dim_, this->getDomain(0)->getFEType(),FERhs, u_rep_,flowRateOutlet_timesteps, funcParameter, pressureRamp,areaOutlet_init_,areaOutlet_T_,this->parameterList_,0);
1347
1348 }
1349
1350 // Adding the assembled RHS on the Fluid component to the fluid RHS
1351 this->sourceTerm_->getBlockNonConst(0)->exportFromVector( FERhs, false, "Add" );
1352
1353 flowRateOutlet_n_1_ = flowRateOutlet_n_;
1354 if ( this->parameterList_->sublist("Timestepping Parameter").get("Checkpointing", false)){
1355 exporterBoundaryCondition_->exportData( "FlowrateOutlet_Previous_Timestep", flowRateOutlet_n_1_ );
1356 }
1357 // addSourceTermToRHS() aus DAESolverInTime
1358 double coeffSourceTermStructure = 1.0;
1359
1360
1361 this->problemTimeFluid_->getRhs()->getBlockNonConst(0)->update(coeffSourceTermStructure, *this->sourceTerm_->getBlockNonConst(0), 1.);
1362 this->rhs_->addBlock( this->problemTimeFluid_->getRhs()->getBlockNonConst(0), 0 );
1363
1364 if(this->verbose_)
1365 std::cout << " .. done " << std::endl;
1366
1367
1368 }
1369
1370}
1371
1372// TODO: updateMultistepRhsFSI() einbauen!
1373template<class SC,class LO,class GO,class NO>
1374void FSI<SC,LO,GO,NO>::computeFluidRHSInTime( ) const
1375{
1376 //######################
1377 // RHS nach BDF2
1378 //######################
1379 int sizeFluid = this->problemFluid_->getSystem()->size();
1380 double dt = timeSteppingTool_->get_dt();
1381 int nmbBDF = timeSteppingTool_->getBDFNumber();
1382
1383 vec_dbl_Type coeffPrevSteps(nmbBDF);
1384 for(int i = 0; i < coeffPrevSteps.size(); i++)
1385 {
1386 coeffPrevSteps.at(i) = timeSteppingTool_->getInformationBDF(i+2) / dt;
1387 }
1388
1389 if (timeSteppingTool_->currentTime()==0.) {
1390 SmallMatrix<double> tmpmassCoeff(sizeFluid);
1391 SmallMatrix<double> tmpproblemCoeff(sizeFluid);
1392 for (int i=0; i<sizeFluid; i++) {
1393 for (int j=0; j<sizeFluid; j++) {
1394 if ((*defTS_)[i][j]==1 && i==j) {
1395 tmpmassCoeff[i][j] = 1. / dt;
1396 }
1397 else{
1398 tmpmassCoeff[i][j] = 0.;
1399 }
1400 }
1401 }
1402 for (int i=0; i<sizeFluid; i++) {
1403 for (int j=0; j<sizeFluid; j++){
1404 if ((*defTS_)[i][j]==1){
1405 tmpproblemCoeff[i][j] = 1.; // ist das richtig? Vermutlich schon, da BDF so geschrieben ist, dass zu berechnende Lsg den Koeffizienten 1 hat
1406 }
1407 else{
1408 tmpproblemCoeff[i][j] = 1.;
1409 }
1410 }
1411 }
1412 this->problemTimeFluid_->setTimeParameters(tmpmassCoeff, tmpproblemCoeff);
1413 }
1414 if (timeSteppingTool_->currentTime()==0.) {
1415 vec_dbl_Type tmpcoeffPrevSteps(1, 1. / dt);
1416 this->problemTimeFluid_->updateMultistepRhsFSI(tmpcoeffPrevSteps,1);/*apply (mass matrix_t / dt) to u_t*/
1417 }
1418 else{
1419 this->problemTimeFluid_->updateMultistepRhsFSI(coeffPrevSteps,nmbBDF);/*apply (mass matrix_t / dt) to u_t and more*/
1420 }
1421
1422 // TODO
1423 if (this->problemTimeFluid_->hasSourceTerm()) {
1424 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Check sourceterm.");
1425 }
1426
1427 // Wieder zu den eigentlichen Parametern zuruecksetzen, nachdem die temporaeren
1428 // genommen wurden.
1429 if (timeSteppingTool_->currentTime()==0.) {
1430 SmallMatrix<double> massCoeffFluid(sizeFluid);
1431 SmallMatrix<double> problemCoeffFluid(sizeFluid);
1432
1433 for (int i=0; i<sizeFluid; i++) {
1434 for (int j=0; j<sizeFluid; j++) {
1435 if ((*defTS_)[i][j]==1 && i==j) {
1436 massCoeffFluid[i][j] = timeSteppingTool_->getInformationBDF(0) / dt;
1437 }
1438 else{
1439 massCoeffFluid[i][j] = 0.0;
1440 }
1441 }
1442 }
1443 for (int i=0; i<sizeFluid; i++) {
1444 for (int j=0; j<sizeFluid; j++){
1445 if ((*defTS_)[i][j]==1){
1446 problemCoeffFluid[i][j] = timeSteppingTool_->getInformationBDF(1);
1447 }
1448 else{
1449 problemCoeffFluid[i][j] = 1.;
1450 }
1451 }
1452 }
1453
1454 this->problemTimeFluid_->setTimeParameters(massCoeffFluid, problemCoeffFluid);
1455 }
1456}
1457
1458
1459// Am Anfang der Zeititeration erst updateSolutionMultiPreviousStep() aufrufen und dann erst updateMultistepRhs(),
1460// damit die previousSolution_ initialisiert sind. Genauso fuer SystemMass
1461// TODO: updateSystemMassMultiPreviousStep() fertig programmieren
1462template<class SC,class LO,class GO,class NO>
1463void FSI<SC,LO,GO,NO>::updateFluidInTime() const
1464{
1465 int nmbBDF = timeSteppingTool_->getBDFNumber();
1466
1467 if(nmbBDF<2 && !this->parameterList_->sublist("General").get("Linearization","FixedPoint").compare("Extrapolation")) {
1468 if (timeSteppingTool_->currentTime()!=0.){
1469 this->problemTimeFluid_->updateSolutionMultiPreviousStep(2);
1470 this->problemTimeFluid_->updateSystemMassMultiPreviousStep(2);
1471 }
1472 else{
1473 this->problemTimeFluid_->updateSolutionMultiPreviousStep(1);
1474 this->problemTimeFluid_->updateSystemMassMultiPreviousStep(1);
1475 }
1476 }
1477 else{
1478 this->problemTimeFluid_->updateSolutionMultiPreviousStep(nmbBDF);
1479 this->problemTimeFluid_->updateSystemMassMultiPreviousStep(nmbBDF);
1480 }
1481}
1482
1483template<class SC,class LO,class GO,class NO>
1484void FSI<SC,LO,GO,NO>::computeSolidRHSInTime() const {
1485 //######################
1486 // RHS nach Newmark
1487 //######################
1488 double dt = timeSteppingTool_->get_dt();
1489 double beta = timeSteppingTool_->get_beta();
1490 double gamma = timeSteppingTool_->get_gamma();
1491
1492 // Temporaerer Koeffizienten fuer die Skalierung der Massematrix in der rechten Seite des Systems in UpdateNewmarkRhs()
1493 vec_dbl_Type coeffTemp(1);
1494 coeffTemp.at(0) = 1.0;
1495
1496 // Update u und berechne u' und u'' mit Hilfe der Newmark-Vorschrift
1497 this->problemTimeStructure_->updateSolutionNewmarkPreviousStep(dt, beta, gamma);
1498
1499 // Stelle die rechte Seite des zeitdiskretisierten Systems auf (ohne f_{n+1}).
1500 // Bei Newmark lautet dies:
1501 // M*[\frac{1}{dt^2*beta}*u_n + \frac{1}{dt*beta}*u'_n + \frac{0.5 - beta}{beta}*u''_n],
1502 // wobei u' = v (velocity) und u'' = w (acceleration).
1503 this->problemTimeStructure_->updateNewmarkRhs(dt, beta, gamma, coeffTemp);
1504
1505 //can we get rid of this?
1506 double time = timeSteppingTool_->currentTime() + dt;
1507
1508 // TODO: SourceTerm wird in jedem Zeitschritt neu berechnet; auch wenn konstant!!!
1509 // if(time == 0){nur dann konstanten SourceTerm berechnen}
1510 if (this->problemTimeStructure_->hasSourceTerm())
1511 {
1512 this->problemTimeStructure_->assembleSourceTerm( time );
1513
1514 // Fuege die rechte Seite der DGL (f bzw. f_{n+1}) der rechten Seite hinzu (skaliert mit coeffSourceTerm)
1515 // Die Skalierung mit der Dichte erfolgt schon in der Assemblierungsfunktion!
1516
1517 // addSourceTermToRHS() aus DAESolverInTime
1518 double coeffSourceTermStructure = 1.0;
1519 BlockMultiVectorPtr_Type tmpPtr = this->problemTimeStructure_->getSourceTerm();
1520 this->problemTimeStructure_->getRhs()->update(coeffSourceTermStructure, *tmpPtr, 1.);
1521 }
1522
1523}
1524
1525template<class SC,class LO,class GO,class NO>
1526void FSI<SC,LO,GO,NO>::setSolidMassmatrix( MatrixPtr_Type& massmatrix ) const
1527{
1528 //######################
1529 // Massematrix
1530 //######################
1531 double density = this->problemTimeStructure_->getParameterList()->sublist("Parameter").get("Density",1000.e-0);
1532 int size = this->problemTimeStructure_->getSystem()->size();
1533
1534 if(timeSteppingTool_->currentTime() == 0.0)
1535 {
1536 this->problemTimeStructure_->systemMass_.reset(new BlockMatrix_Type(size));
1537 {
1538
1539 massmatrix = Teuchos::rcp(new Matrix_Type( this->problemTimeStructure_->getDomain(0)->getMapVecFieldUnique(), this->getDomain(0)->getApproxEntriesPerRow() ) );
1540 // 2 = Struktur
1541 this->feFactory_->assemblyMass(this->dim_, this->problemTimeStructure_->getFEType(0), "Vector", massmatrix, 2, true);
1542 massmatrix->resumeFill();
1543 massmatrix->scale(density);
1544 massmatrix->fillComplete( this->problemTimeStructure_->getDomain(0)->getMapVecFieldUnique(), this->problemTimeStructure_->getDomain(0)->getMapVecFieldUnique());
1545
1546 this->problemTimeStructure_->systemMass_->addBlock( massmatrix, 0, 0 );
1547 }
1548 }
1549}
1550
1551
1552// Damit die richtige timeSteppingTool_->currentTime() genommen wird.
1553template<class SC,class LO,class GO,class NO>
1554void FSI<SC,LO,GO,NO>::updateTime() const
1555{
1556 timeSteppingTool_->t_ = timeSteppingTool_->t_ + timeSteppingTool_->dt_prev_;
1557}
1558
1559template<class SC,class LO,class GO,class NO>
1560void FSI<SC,LO,GO,NO>::moveMesh() const
1561{
1562
1563 MultiVectorConstPtr_Type displacementUniqueConst;
1564 if(geometryExplicit_)
1565 {
1566 displacementUniqueConst = this->problemGeometry_->getSolution()->getBlock(0);
1567 }
1568 else
1569 {
1570 displacementUniqueConst = this->solution_->getBlock(4);
1571 }
1572 MultiVectorPtr_Type displacementRepeated = Teuchos::rcp( new MultiVector_Type( this->problemGeometry_->getDomain(0)->getMapVecFieldRepeated() ) );
1573
1574 displacementRepeated->importFromVector( displacementUniqueConst );
1575 MultiVectorPtr_Type displacementUnique = Teuchos::rcp_const_cast<MultiVector_Type>(displacementUniqueConst);
1576
1577
1578 // Verschiebe die Gitter fuer Fluid-Velocity und Fluid-Druck
1579 // ACHTUNG: Klappt nur, weil die P2-Knoten hinter den P1-Knoten kommen.
1580 // Sonst muessen fuer den Druck die P1-Knoten extrahiert werden.
1581 // TODO: Wahrscheinlich reicht nur FSI-Domain, da selbes Objekt bei problemFluid_ und problemTimeFluid_.
1582 ( Teuchos::rcp_const_cast<Domain_Type>(this->getDomain(0)) )->moveMesh(displacementUnique, displacementRepeated);
1583 ( Teuchos::rcp_const_cast<Domain_Type>(this->getDomain(1)) )->moveMesh(displacementUnique, displacementRepeated);
1584 ( Teuchos::rcp_const_cast<Domain_Type>(this->problemFluid_->getDomain(0)) )->moveMesh(displacementUnique, displacementRepeated);
1585 ( Teuchos::rcp_const_cast<Domain_Type>(this->problemFluid_->getDomain(1)) )->moveMesh(displacementUnique, displacementRepeated);
1586 ( Teuchos::rcp_const_cast<Domain_Type>(this->problemTimeFluid_->getDomain(0)) )->moveMesh(displacementUnique, displacementRepeated);
1587 ( Teuchos::rcp_const_cast<Domain_Type>(this->problemTimeFluid_->getDomain(1)) )->moveMesh(displacementUnique, displacementRepeated);
1588}
1589
1590
1591template<class SC,class LO,class GO,class NO>
1592void FSI<SC,LO,GO,NO>::addInterfaceBlockRHS() const
1593{
1594 MultiVectorPtr_Type vectorToAdd = Teuchos::rcp( new MultiVector_Type( this->rhs_->getBlock(3) ) );
1595
1596 C2_->apply(*(this->solution_->getBlock(2)), *vectorToAdd);
1597 this->rhs_->addBlock(vectorToAdd, 3);
1598}
1599
1600
1601// template<class SC,class LO,class GO,class NO>
1602// void FSI<SC,LO,GO,NO>::evalModelImpl(const Thyra::ModelEvaluatorBase::InArgs<SC> &inArgs,
1603// const Thyra::ModelEvaluatorBase::OutArgs<SC> &outArgs
1604// ) const
1605// {
1606// TEUCHOS_TEST_FOR_EXCEPTION( true, std::logic_error, "implement NOX for steady FSI.");
1607// std::string type = this->parameterList_->sublist("General").get("Preconditioner Method","Monolithic");
1608// // if ( !type.compare("Monolithic"))
1609// // evalModelImplMonolithic( inArgs, outArgs );
1610// // else if ( !type.compare("FaCSI")){
1611// // evalModelImplBlock( inArgs, outArgs );
1612// // }
1613// // else
1614// // TEUCHOS_TEST_FOR_EXCEPTION( true, std::logic_error, "Unkown preconditioner/solver type.");
1615// }
1616
1617template<class SC,class LO,class GO,class NO>
1618void FSI<SC,LO,GO,NO>::getValuesOfInterest( vec_dbl_Type& values ){
1619 if (this->dim_==2)
1620 getValuesOfInterest2DBenchmark( values );
1621 else if(this->dim_==3)
1622 getValuesOfInterest3DBenchmark( values);
1623
1624}
1625
1626template<class SC,class LO,class GO,class NO>
1627void FSI<SC,LO,GO,NO>::getValuesOfInterest2DBenchmark( vec_dbl_Type& values ){
1628
1629
1630 if ( valuesForExport_[0] >= 0. ) { // we set the displacement of the 2D Turek Benchmark in x and y direction
1631 LO loc = valuesForExport_[0] + 10*Teuchos::ScalarTraits<SC>::eps();
1632 values[0] = this->getSolution()->getBlock(2)->getData(0)[2*loc];
1633 values[1] = this->getSolution()->getBlock(2)->getData(0)[2*loc+1];
1634 }
1635}
1636
1637template<class SC,class LO,class GO,class NO>
1638void FSI<SC,LO,GO,NO>::getValuesOfInterest3DBenchmark( vec_dbl_Type& values ){
1639
1640 if ( valuesForExport_[0] >= 0. ) { // we set the displacement of the 3D Richter Benchmark in x, y, and z direction
1641 LO loc = valuesForExport_[0] + 10*Teuchos::ScalarTraits<SC>::eps();
1642 values[0] = this->getSolution()->getBlock(2)->getData(0)[3*loc];
1643 values[1] = this->getSolution()->getBlock(2)->getData(0)[3*loc+1];
1644 values[2] = this->getSolution()->getBlock(2)->getData(0)[3*loc+2];
1645 }
1646}
1647
1648template<class SC,class LO,class GO,class NO>
1649void FSI<SC,LO,GO,NO>::computeValuesOfInterestAndExport(){
1650 if ( this->getParameterList()->sublist("General").get("Export drag and lift",false) ) {
1651
1652 int dim = this->dim_;
1653 TEUCHOS_TEST_FOR_EXCEPTION( this->parameterList_->sublist("Parameter").get("Criterion","Residual") == "Update", std::runtime_error, "Wrong nonlinear criterion to calculate the drag coefficient. The last system is the Newton system but we need the fixed point system. Either use Criterion=Residual or implement for Criterion=Update." );
1654
1655 TEUCHOS_TEST_FOR_EXCEPTION( this->problemFluid_->hasSourceTerm(), std::runtime_error, "We need to substract the additional source term: drag = < F*u + B_T*p + C1_T*lamba - f, v >" );
1656
1657 Teuchos::Array<SC> drag(1);
1658 Teuchos::Array<SC> lift(1);
1659
1660 BlockMultiVectorPtr_Type uDrag = Teuchos::rcp( new BlockMultiVector_Type( this->problemFluid_->getSolution() ) );
1661 BlockMultiVectorPtr_Type uLift = Teuchos::rcp( new BlockMultiVector_Type( this->problemFluid_->getSolution() ) );
1662 // should be the last fixed point system without boundary conditions or the last extrapolation system without boundary values.
1663 // We need to reassemble B and BT, because we might have set Dirichlet boundary conditions in BT (less likely in B)
1664 this->problemFluid_->assembleDivAndStab();
1665
1666 this->problemFluid_->getSystem()->apply( *this->problemFluid_->getSolution(), *uDrag );
1667 this->problemFluid_->getSystem()->apply( *this->problemFluid_->getSolution(), *uLift );
1668
1669 MultiVectorPtr_Type C1T_lambda = Teuchos::rcp( new MultiVector_Type( this->getSolution()->getBlock(0) ) );
1670 this->system_->getBlock(0,3)->apply( *this->getSolution()->getBlock(3), *C1T_lambda );
1671
1672 uDrag->getBlockNonConst(0)->update( 1., *C1T_lambda, 1. ); // velocity + C1_T * lambda
1673 uLift->getBlockNonConst(0)->update( 1., *C1T_lambda, 1. ); // velocity + C1_T * lambda
1674
1675 BCPtr_Type bcFactoryDrag = Teuchos::rcp( new BC_Type( ) );
1676 BCPtr_Type bcFactoryLift = Teuchos::rcp( new BC_Type( ) );
1677
1678 DomainConstPtr_Type domainVelocityConst = this->problemFluid_->getDomain(0);
1679 DomainPtr_Type domainVelocity = Teuchos::rcp_const_cast<Domain_Type>(domainVelocityConst);
1680 if( dim == 2 ){
1681 bcFactoryDrag->addBC(drag2D, 4, 0, domainVelocity, "Dirichlet", dim); // obstacle
1682 bcFactoryDrag->addBC(drag2D, 5, 0, domainVelocity, "Dirichlet", dim); // interface; check main fsi for matching flags at the obstacle and interface
1683 bcFactoryLift->addBC(lift2D, 4, 0, domainVelocity, "Dirichlet", dim);
1684 bcFactoryLift->addBC(lift2D, 5, 0, domainVelocity, "Dirichlet", dim);
1685 }
1686 else if( dim == 3 ){
1687 bcFactoryDrag->addBC(drag3D, 3, 0, domainVelocity, "Dirichlet", dim); // check main fsi for matching
1688 bcFactoryDrag->addBC(drag3D, 6, 0, domainVelocity, "Dirichlet", dim); // check main fsi for matching flags at the obstacle and interface
1689 bcFactoryLift->addBC(lift3D, 3, 0, domainVelocity, "Dirichlet", dim);
1690 bcFactoryLift->addBC(lift3D, 6, 0, domainVelocity, "Dirichlet", dim);
1691 }
1692
1693 BlockMultiVectorPtr_Type vD = Teuchos::rcp( new BlockMultiVector_Type( this->problemFluid_->getSolution() ) );
1694 BlockMultiVectorPtr_Type vL = Teuchos::rcp( new BlockMultiVector_Type( this->problemFluid_->getSolution() ) );
1695
1696 vD->putScalar(0.);
1697 vL->putScalar(0.);
1698
1699 bcFactoryDrag->setRHS( vD );
1700 bcFactoryLift->setRHS( vL );
1701
1702 uDrag->dot( vD, drag() );
1703 uLift->dot( vL, lift() );
1704
1705// double density = this->problemFluid_->getParameterList()->sublist("Parameter").get("Density",1.);
1706// double uMean = this->getParameterList()->sublist("Parameter").get("MeanVelocity",2.0);
1707// double L = 0.;
1708// if ( dim == 2)
1709// L = 2.*0.05;
1710// else
1711// L = 1.;
1712//
1713// drag[0] *= -(2./(density*uMean*uMean*L));
1714// lift[0] *= -(2./(density*uMean*uMean*L));
1715
1716 drag[0] *= -1.;
1717 lift[0] *= -1.;
1718
1719 exporterTxtDrag_->exportData( drag[0] );
1720 exporterTxtLift_->exportData( lift[0] );
1721 }
1722}
1723
1724template<class SC,class LO,class GO,class NO>
1725void FSI<SC,LO,GO,NO>::initializeGE(){
1726/*All vectors (solution, rhs, previousSolution,...) should be initialized at this point (initializeProblem() was called)
1727 Therefore, all these BlockMVectors should have a length of 5 since the geometry problem is included in the general setup. We need to resize these BlockMVs here if the Geometry Explicit (GE) system is used.
1728*/
1729 if (geometryExplicit_) {
1730 this->solution_->resize( 4 );
1731 this->rhs_->resize( 4 );
1732 this->sourceTerm_->resize( 4 );
1733 this->rhsFuncVec_.resize( 4 );
1734 this->previousSolution_->resize( 4 );
1735 this->residualVec_->resize( 4 );
1736 this->initVectorSpaces(); //reinitialize NOX vector spaces
1737 }
1738}
1739
1740}
1741#endif
virtual void calculateNonLinResidualVec(std::string type="standard", double time=0.) const override
Virtual function which is implemented in the specific non-linear problem classes to calculate the non...
Definition FSI_def.hpp:740
virtual void getValuesOfInterest(vec_dbl_Type &values)
Virtual class to extract values of interest that are computed during the solve.
Definition FSI_def.hpp:1618
virtual void assemble(std::string type="") const
assemble of type exectuted by the derived specific non-linear problem classes
Definition FSI_def.hpp:204
Definition NonLinearProblem_decl.hpp:28
virtual void calculateNonLinResidualVec(std::string type="standard", double time=0.) const =0
Virtual function which is implemented in the specific non-linear problem classes to calculate the non...
This class represents a templated small Matrix of type T. Primarily created for 2x2 and 3x3 matrices....
Definition SmallMatrix.hpp:20
Definition TimeSteppingTools.hpp:22
Adaptive Mesh Refinement.
Definition AdaptiveMeshRefinement_decl.hpp:36