LifeV
FSIExactJacobian.cpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6  Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8  This file is part of LifeV.
9 
10  LifeV is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  LifeV is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 
27 #include <lifev/fsi/solver/FSIExactJacobian.hpp>
28 
29 namespace LifeV
30 {
31 
32 // ===================================================
33 // Constructors & Destructor
34 // ===================================================
36  super(),
37  M_rhsNew(),
38  M_beta(),
39  M_aitkFS(),
41  M_epetraOper(),
43  M_recomputeShapeDer (true)
44 {
45 
46 }
47 
48 
49 
51 {}
52 
53 // ===================================================
54 // Methods
55 // ===================================================
56 void FSIExactJacobian::solveJac (vector_Type& _muk,
57  const vector_Type& _res,
58  const Real _linearRelTol)
59 {
60  if (this->isFluid() && this->isLeader() )
61  {
62  std::cout << " f- ";
63  }
64  if (this->isSolid() && this->isLeader() )
65  {
66  std::cout << " s- ";
67  }
68 
69  this->displayer().leaderPrint ( "FSI --- solveJac: NormInf res " , _res.normInf(), "\n" );
70  _muk *= 0.;
71 
72  M_linearSolver.setTolerance ( _linearRelTol );
73  M_linearSolver.setMaxNumIterations ( 100 );
74 
75  vector_Type res (_res);
76 
77  M_linearSolver.setOperator (M_epetraOper);
78 
79  this->displayer().leaderPrint ( "FSI --- Solving Jacobian FSI system... " );
80 
81  M_recomputeShapeDer = true;
82  M_linearSolver.solve (_muk, res);
83 
84  this->displayer().leaderPrint ( "FSI --- Solving the Jacobian FSI system done.\n" );
85 }
86 
87 void FSIExactJacobian::evalResidual (vector_Type& res,
88  const vector_Type& disp,
89  const UInt iter)
90 {
91  if (this->isSolid() )
92  {
93  std::cout << "FSI --- Residual computation g(x_" << iter << " )\n";
94  }
95 
96  setLambdaSolidOld (disp);
97 
98 
99  eval (disp, iter);
100 
101  res = this->lambdaSolid();
102  res -= disp;
103 
104  if (this->isSolid() )
105  {
106  M_solid->updateJacobian (M_solid->displacement() );
107  }
108 
109  this->displayer().leaderPrint ("FSI --- NormInf res = " , res.normInf(), "\n" );
110  if (this->isSolid() )
111  {
112  this->displayer().leaderPrint ("FSI --- NormInf res_d = " , this->solid().residual().normInf(), "\n" );
113  }
114 
115 }
116 
117 
119 {
120  //vector_Type dispFluidDomainRep( M_fluid->matrixNoBC().getMap(), Repeated);
121  vector_Type dispFluidDomain ( M_fluid->matrixNoBC().map(), Unique, Zero);
122  dispFluidDomain.setCombineMode (Zero);
123  vector_Type dispFluidMesh (this->derVeloFluidMesh().map(), Repeated);
124  //if statement: in order not to iterate the mesh for each linear residual calculation, needed just for exact Jac case.
125  if (false && this->M_data->dataFluid()->isSemiImplicit() == true)
126  {
127  //to be corrected: up to now also in the semi implicit case the harmonic extension eq.
128  //is solved at each GMRES iteration
129 
130  //vector_Type solidDisplacementRepeated(this->M_solid->disp(), Repeated);
131 
132  // this->transferSolidOnInterface(sldsp, lambdaSolid());
133 
134  // vector_Type repLambdaSolid(lambdaSolid(), Repeated);
135 
136  //this->transferInterfaceOnFluid(repLambdaSolid, dispFluidMesh);
137  this->transferSolidOnFluid (this->M_solid->displacement(), dispFluidMesh);
138  }
139  else
140  {
141  this->transferMeshMotionOnFluid (M_meshMotion->disp(),
142  dispFluidMesh);
143  }
144  //dispFluidDomainRep = dispFluidMesh;//import
145  dispFluidDomain = dispFluidMesh; //import
146 
147 
148  this->derVeloFluidMesh() = dispFluidMesh;
149  this->derVeloFluidMesh() *= M_fluidTimeAdvance->coefficientFirstDerivative (0) / (M_data->dataFluid()->dataTime()->timeStep() );
150  this->displayer().leaderPrint ( " norm inf dw = " , derVeloFluidMesh().normInf(), "\n" );
151  *M_rhsNew *= 0.;
152 
153  double alpha = this->M_fluidTimeAdvance->coefficientFirstDerivative ( 0 ) / M_data->dataFluid()->dataTime()->timeStep();
154 
155  if (!this->M_fluid->stabilization() ) //if using P1Bubble
156  {
157 
158  this->M_fluid->updateLinearSystem ( M_fluid->matrixNoBC(),
159  alpha,
160  M_fluidTimeAdvance->singleElement (0),
161  *M_fluid->solution(),
162  dispFluidMesh,
163  veloFluidMesh(),
164  derVeloFluidMesh(),
165  *M_rhsNew );
166  }
167  else
168  {
170  {
171  M_recomputeShapeDer = false;
172  M_matrShapeDer.reset (new matrix_Type (M_fluid->matrixNoBC().map() /*, M_mmFESpace->map()*/) );
173  this->M_fluid->updateShapeDerivatives (
174  *M_matrShapeDer,
175  alpha,
176  M_fluidTimeAdvance->singleElement (0),
177  *M_fluid->solution(),
178  //dispFluidMesh,
179  veloFluidMesh(),
180  (UInt) 0,
181  *M_mmFESpace,
182  true,
183  false
184  //this->derVeloFluidMesh(),
185  //*M_rhsNew
186  );
187  M_matrShapeDer->globalAssemble();
188  *M_matrShapeDer *= -1;
189  //M_matrShapeDer->spy("matrsd");
190  }
191  *M_rhsNew = (*M_matrShapeDer) * dispFluidDomain;
192  M_fluid->updateLinearRightHandSideNoBC (*M_rhsNew);
193  }
194 
195  this->M_fluid->solveLinearSystem ( *this->M_BCh_du );
196 }
197 
198 
200 {
201  M_solid->iterateLin ( M_BCh_dz );
202 }
203 
204 void
206 {
207  setLinearFluid (true);
208  setLinearSolid (true);
209 
210  super::setupFEspace();
211 }
212 
213 void
215 {
216  super::setupFluidSolid();
217 
218  M_epetraOper.setOperator (this);
219 
220  if ( this->isFluid() )
221  {
222  M_rhsNew.reset (new vector_Type (this->M_fluid->getMap() ) );
223  M_beta.reset (new vector_Type (this->M_fluid->getMap() ) );
224  }
225 
226 }
227 
228 void
229 FSIExactJacobian::setDataFile ( const GetPot& dataFile )
230 {
231  super::setDataFile ( dataFile );
232 
233  M_aitkFS.setDefaultOmega ( M_data->defaultOmega(), 0.001 );
234  M_aitkFS.setOmegaRange ( M_data->OmegaRange() );
235 
236  M_linearSolver.setCommunicator ( M_epetraComm );
237  M_linearSolver.setDataFromGetPot (dataFile, "jacobian");
238 
239 }
240 
241 
243 {
244  FSIFactory_Type::instance().registerProduct ( "exactJacobian", &createEJ );
245 
246  solid_Type::material_Type::isotropicLaw_Type::StructureIsotropicMaterialFactory::instance().registerProduct ( "linearVenantKirchhoff", &super::createVenantKirchhoffLinear );
247  solid_Type::material_Type::isotropicLaw_Type::StructureIsotropicMaterialFactory::instance().registerProduct ( "nonLinearVenantKirchhoff", &super::createVenantKirchhoffNonLinear );
248 }
249 
250 // ===================================================
251 // Private Methods
252 // ===================================================
253 
254 
255 UInt
257 {
258  if ( this->isFluid() )
259  {
260  UInt numLM = super::imposedFluxes();
261 
262  std::vector<bcName_Type> fluxVector = M_BCh_du->findAllBCWithType ( Flux );
263  if ( numLM != ( static_cast<UInt> ( fluxVector.size() ) ) )
264  {
265  ERROR_MSG ("Different number of fluxes imposed on Fluid and on LinearFluid");
266  }
267 
268  UInt offset = M_uFESpace->map().map (Unique)->NumGlobalElements()
269  + M_pFESpace->map().map (Unique)->NumGlobalElements();
270 
271  for ( UInt i = 0; i < numLM; ++i )
272  {
273  M_BCh_du->setOffset ( fluxVector[i], offset + i );
274  }
275 
276  return numLM;
277  }
278  else
279  {
280  return 0;
281  }
282 }
283 
284 //
285 // Residual computation
286 //
287 
288 void FSIExactJacobian::eval (const vector_Type& _disp,
289  const UInt iter)
290 {
291  LifeChrono chronoFluid, chronoSolid, chronoInterface;
292 
293  bool recomputeMatrices ( iter == 0 || ( !this->M_data->dataFluid()->isSemiImplicit() &&
294  ( M_data->updateEvery() > 0 &&
295  (iter % M_data->updateEvery() == 0) ) ) );
296 
297  if (iter == 0)
298  {
299  if (isFluid() )
300  {
301  this->M_fluid->resetPreconditioner();
302  }
303  //this->M_solid->resetPrec();
304  }
305 
306 
307  this->setLambdaFluid (_disp);
308 
309 
310  vector_Type sigmaFluidUnique (this->sigmaFluid(), Unique);
311 
312  M_epetraWorldComm->Barrier();
313  chronoFluid.start();
314 
315  if (isFluid() )
316  {
317  M_meshMotion->iterate (*M_BCh_mesh);
318  // M_meshMotion->updateDispDiff();
319 
320 
321  // copying displacement to a repeated indeces displacement, otherwise the mesh wont know
322  // the value of the displacement for some points
323 
324 
325  if ( iter == 0 || !this->M_data->dataFluid()->isSemiImplicit() )
326  {
327  *M_beta *= 0.;
328 
329  if ( iter == 0 )
330  {
331  M_ALETimeAdvance->updateRHSFirstDerivative (M_data->dataFluid()->dataTime()->timeStep() );
332  M_ALETimeAdvance->shiftRight (M_meshMotion->disp() );
333  M_ALETimeAdvance->extrapolation (M_meshMotion->disp() ); //closer initial solution
334  }
335  else
336  {
337  M_ALETimeAdvance->setSolution (M_meshMotion->disp() );
338  }
339 
340  vector_Type meshDispRepeated ( M_meshMotion->disp(), Repeated );
341  this->moveMesh (meshDispRepeated);
342  vector_Type vel ( this->M_ALETimeAdvance->firstDerivative( ) );
343  transferMeshMotionOnFluid ( vel, veloFluidMesh() );
344  M_fluidTimeAdvance->extrapolation (*M_beta); //explicit
345  *M_beta -= veloFluidMesh();//implicit
346 
347 
348  //the conservative formulation as it is now is of order 1. To have higher order (TODO) we need to store the mass matrices computed at the previous time steps.
349  if (M_data->dataFluid()->conservativeFormulation() )
350  //*M_rhs = M_fluid->matrixMass()*M_fluidTimeAdvance->rhsContributionFirstDerivative();
351  {
352  *M_rhs = M_fluidMassTimeAdvance->rhsContributionFirstDerivative();
353  }
354 
355 
356  if (recomputeMatrices)
357  {
358  double alpha = M_fluidTimeAdvance->coefficientFirstDerivative (0) / M_data->dataFluid()->dataTime()->timeStep();
359  this->M_fluid->updateSystem ( alpha, *M_beta, *M_rhs );
360  }
361  else
362  {
363  this->M_fluid->updateRightHandSide ( *M_rhs );
364  }
365  if (!M_data->dataFluid()->conservativeFormulation() )
366  {
367  *M_rhs = M_fluid->matrixMass() * M_fluidTimeAdvance->rhsContributionFirstDerivative();
368  this->M_fluid->updateRightHandSide ( *M_rhs );
369  }
370  }
371 
372  this->M_fluid->iterate ( *M_BCh_u );
373 
374  this->transferFluidOnInterface (this->M_fluid->residual(), sigmaFluidUnique);
375  }
376 
377  M_epetraWorldComm->Barrier();
378  chronoFluid.stop();
379  this->displayer().leaderPrintMax (" Fluid solution total time: ", chronoFluid.diff() );
380 
381  if ( false && this->isFluid() )
382  {
383  vector_Type vel (this->fluid().velocityFESpace().map() );
384  vector_Type press (this->fluid().pressureFESpace().map() );
385 
386  vel.subset (*this->M_fluid->solution() );
387  press.subset (*this->M_fluid->solution(), this->fluid().velocityFESpace().dim() *this->fluid().pressureFESpace().fieldDim() );
388 
389  std::cout << "norm_inf( vel ) " << vel.normInf() << std::endl;
390  std::cout << "norm_inf( press ) " << press.normInf() << std::endl;
391 
392  //this->M_fluid->postProcess();
393  }
394 
395  chronoInterface.start();
396 
397  this->setSigmaFluid ( sigmaFluidUnique );
398  this->setSigmaSolid ( sigmaFluidUnique );
399 
400 
401 
402  vector_Type lambdaSolidUnique (this->lambdaSolid(), Unique);
403  vector_Type lambdaDotSolidUnique (this->lambdaDotSolid(), Unique);
404  vector_Type sigmaSolidUnique (this->sigmaSolid(), Unique);
405 
406  chronoInterface.stop();
407  M_epetraWorldComm->Barrier();
408  chronoSolid.start();
409 
410  if (this->isSolid() )
411  {
412  this->M_solid->iterate ( M_BCh_d );
413  }
414 
415  M_epetraWorldComm->Barrier();
416  chronoSolid.stop();
417  this->displayer().leaderPrintMax (" Solid solution total time: ", chronoSolid.diff() );
418 
419  chronoInterface.start();
420 
421  if (this->isSolid() )
422  {
423  this->transferSolidOnInterface (this->M_solid->displacement(), lambdaSolidUnique);
424  this->transferSolidOnInterface ( this->M_solidTimeAdvance->firstDerivative ( this->M_solid->displacement() ), lambdaDotSolidUnique );
425  this->transferSolidOnInterface (this->M_solid->residual(), sigmaSolidUnique);
426  }
427 
428  this->setLambdaSolid ( lambdaSolidUnique);
429  this->setLambdaDotSolid ( lambdaDotSolidUnique);
430  this->setSigmaSolid ( sigmaSolidUnique);
431 
432  chronoInterface.stop();
433  this->displayer().leaderPrintMax (" Interface transfer total time: ", chronoInterface.diffCumul() );
434 
435 
436  // possibly unsafe when using more cpus, since both has repeated maps
437 
438  this->displayer().leaderPrint (" Norm(disp ) = ", _disp.normInf(), "\n");
439  this->displayer().leaderPrint (" Norm(dispNew ) = " , this->lambdaSolid().normInf(), "\n" );
440  this->displayer().leaderPrint (" Norm(velo ) = " , this->lambdaDotSolid().normInf(), "\n" );
441  this->displayer().leaderPrint (" Max Residual Fluid = " , this->sigmaFluid().normInf(), "\n" );
442  this->displayer().leaderPrint (" Max Residual Solid = " , this->sigmaSolid().normInf(), "\n" );
443 
444  if ( this->isFluid() )
445  {
446  this->displayer().leaderPrint (" Max ResidualF = " , M_fluid->residual().normInf(), "\n" );
447  }
448  if ( this->isSolid() )
449  {
450  this->displayer().leaderPrint (" NL2 Diplacement S. = " , M_solid->displacement().norm2(), "\n" );
451  this->displayer().leaderPrint (" Max Residual Solid = " , M_solid->residual().normInf(), "\n" );
452  }
453 }
454 
455 
456 
457 
458 
459 
460 // ===================================================
461 // Epetra_ExactJacobian
462 // ===================================================
463 
464 // ===================================================
465 // Constructors & Destructorxs
466 // ===================================================
467 
469  M_ej(),
472  M_comm()
473 {
474 }
475 
476 // ===================================================
477 // Methods
478 // ===================================================
479 
481 {
482  ASSERT (ej != 0, "passing NULL pointer to se operator");
483  M_ej = ej;
484  M_operatorDomainMap = M_ej->solidInterfaceMap()->map (Repeated);
485  M_operatorRangeMap = M_ej->solidInterfaceMap()->map (Repeated);
486  M_comm = M_ej->worldComm();
487 }
488 
489 int FSIExactJacobian::Epetra_ExactJacobian::Apply (const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
490 {
491 
492  LifeChrono chronoFluid, chronoSolid, chronoInterface;
493 
494  M_comm->Barrier();
495 
496  double xnorm = 0.;
497  X.NormInf (&xnorm);
498 
499  Epetra_FEVector dz (Y.Map() );
500 
501  if (M_ej->isSolid() )
502  {
503  std::cout << "\n ***** norm (z)= " << xnorm << std::endl << std::endl;
504  }
505 
506 
507  if ( xnorm == 0.0 )
508  {
509  Y.Scale (0.);
510  dz.Scale (0.);
511  }
512  else
513  {
514  vector_Type const z (X, M_ej->solidInterfaceMap(), Unique);
515 
516  M_ej->displayer().leaderPrint ( "NormInf res " , z.normInf(), "\n" );
517 
518  //M_ej->solid().residual() *= 0.;
519  //M_ej->transferInterfaceOnSolid(z, M_ej->solid().residual());
520 
521  //std::cout << "NormInf res_d " << M_ej->solid().residual().NormInf() << std::endl;
522 
523  //if (M_ej->isSolid())
524  // M_ej->solid().postProcess();
525 
526  M_ej->setLambdaFluid (z);
527 
528  //M_ej->transferInterfaceOnSolid(z, M_ej->solid().disp());
529 
530  chronoInterface.start();
531  vector_Type sigmaFluidUnique (M_ej->sigmaFluid(), Unique);
532  chronoInterface.stop();
533 
534  M_comm->Barrier();
535  chronoFluid.start();
536 
537  if (M_ej->isFluid() )
538  {
539 
540  //to be used when we correct the other lines
541  if (true || ( !this->M_ej->dataFluid()->isSemiImplicit() /*|| this->M_ej->dataFluid().semiImplicit()==-1*/) )
542  {
543  M_ej->meshMotion().iterate (*M_ej->BCh_harmonicExtension() );
544  //std::cout<<" mesh motion iterated!!!"<<std::endl;
545  }
546 
547  M_ej->displayer().leaderPrint ( " norm inf dx = " , M_ej->meshMotion().disp().normInf(), "\n" );
548 
550 
551  M_ej->transferFluidOnInterface (M_ej->fluid().residual(), sigmaFluidUnique);
552 
553  //M_ej->fluidPostProcess();
554  }
555 
556  M_comm->Barrier();
557  chronoFluid.stop();
558  M_ej->displayer().leaderPrintMax ( "Fluid linear solution: total time : ", chronoFluid.diff() );
559 
560 
561  chronoInterface.start();
562  // M_ej->setSigmaFluid(sigmaFluidUnique);
563  M_ej->setSigmaSolid (sigmaFluidUnique);
564 
565 
566  vector_Type lambdaSolidUnique (M_ej->lambdaSolid(), Unique);
567  chronoInterface.stop();
568 
569  M_comm->Barrier();
570  chronoFluid.start();
571 
572  if (M_ej->isSolid() )
573  {
575  M_ej->transferSolidOnInterface (M_ej->solid().displacement(), lambdaSolidUnique);
576  }
577 
578  M_comm->Barrier();
579  chronoSolid.stop();
580  M_ej->displayer().leaderPrintMax ( "Solid linear solution: total time : " , chronoSolid.diff() );
581 
582  chronoInterface.start();
583  M_ej->setLambdaSolid (lambdaSolidUnique);
584 
585  chronoInterface.stop();
586  M_ej->displayer().leaderPrintMax ( "Interface linear transfer: total time : " , chronoInterface.diffCumul() );
587 
588  dz = lambdaSolidUnique.epetraVector();
589  }
590 
591 
592  Y = X;
593  Y.Update (1., dz, -1.);
594 
595  double ynorm;
596  Y.NormInf (&ynorm);
597 
598  if (M_ej->isSolid() )
599  std::cout << "\n\n ***** norm (Jz)= " << ynorm
600  << std::endl << std::endl;
601 
602  return 0;
603 }
604 
605 }
void setOperator(FSIExactJacobian *ej)
sets the exactJacobian pointer and some contents thereof
void solveLinearSolid()
Solves the linear structure problem.
void assignFunction(bcBase_Type &base)
Assign the function to the base of the BCHandler.
void registerMyProducts()
register the product for the factory
void eval(const vector_Type &_res, UInt status)
#define ERROR_MSG(A)
Definition: LifeAssert.hpp:69
void solveLinearFluid()
Solves the linear fluid problem.
FSIExactJacobian()
Empty Constructor.
void setDataFile(GetPot const &data)
initializes the GetPot data file
#define ASSERT(X, A)
Definition: LifeAssert.hpp:90
Epetra_ExactJacobian This class implements an Epetra_Operator to be passed to AztecOO.
double Real
Generic real data.
Definition: LifeV.hpp:175
FSIModelExactJacobian - Implementation of an FSI (Operator) with Newton algorithm.
void setupFluidSolid()
setup of the fluid and solid solver classes
void setupFEspace()
sets the space discretization parameters
void evalResidual(vector_Type &_res, const vector_Type &_disp, const UInt _iter)
Evaluates the nonlinear residual of the FSI system.
int Apply(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const
apply the jacobian to X and returns the result in Y
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191
void solveJac(vector_Type &_muk, const vector_Type &_res, const Real _linearRelTol)
solves the Jacobian system