LifeV
FSIMonolithic.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 
28 #include <EpetraExt_Reindex_MultiVector.h>
29 
30 
31 #include <lifev/core/LifeV.hpp>
32 #include <lifev/fsi/solver/FSIMonolithic.hpp>
33 
34 namespace LifeV
35 {
36 
37 // ===================================================
38 // Constructors, Destructor
39 // ===================================================
40 FSIMonolithic::FSIMonolithic() :
41  super_Type(),
42  M_monolithicMap(),
43  M_interfaceMap(),
44  M_beta(),
45  M_monolithicMatrix(),
46  M_precPtr(),
47  M_rhsFull(),
48  M_BCh_flux(),
49  M_BChWS(),
50  M_offset (0),
51  M_solidAndFluidDim (0),
52  M_fluidBlock(),
53  M_solidBlockPrec(),
54  M_linearSolver(),
55  M_numerationInterface(),
56  M_BChs(),
57  M_FESpaces(),
58  M_diagonalScale (false),
59  M_reusePrec (true),
60  M_resetPrec (true),
61  M_maxIterSolver (-1),
62  M_restarts (false),
63  //end of protected attributes
64  M_preconditionedSymmetrizedMatrix(),
65  M_stress(),
66  M_fluxes (0)
67 {}
68 
69 FSIMonolithic::~FSIMonolithic()
70 {
71 }
72 
73 // ===================================================
74 // Setup Methods
75 // ===================================================
76 void
77 FSIMonolithic::setupFEspace()
78 {
79  super_Type::setupFEspace();
80 
81  // Monolitic: In the beginning I need a non-partitioned mesh. later we will do the partitioning
82  M_dFESpace.reset ( new FESpace<mesh_Type, MapEpetra> ( M_solidMesh,
83  M_data->dataSolid()->order(),
84  nDimensions,
85  M_epetraComm) );
86 
87 }
88 
89 void
90 FSIMonolithic::setupDOF ( void )
91 {
92  M_dofStructureToHarmonicExtension .reset ( new DOFInterface3Dto3D );
93  M_dofStructureToFluid .reset ( new DOFInterface3Dto3D );
94 
95  M_dofStructureToHarmonicExtension->setup ( M_mmFESpace->refFE(), M_mmFESpace->dof(),
96  M_dFESpace->refFE(), M_dFESpace->dof() );
97  M_dofStructureToHarmonicExtension->update ( *M_mmFESpace->mesh(), M_data->fluidInterfaceFlag(),
98  *M_dFESpace->mesh(), M_data->structureInterfaceFlag(),
99  M_data->interfaceTolerance(),
100  M_data->fluidInterfaceVertexFlag() );
101 
102  M_dofStructureToFluid->setup ( M_uFESpace->refFE(), M_uFESpace->dof(),
103  M_dFESpace->refFE(), M_dFESpace->dof() );
104  M_dofStructureToFluid->update ( *M_uFESpace->mesh(), M_data->fluidInterfaceFlag(),
105  *M_dFESpace->mesh(), M_data->structureInterfaceFlag(),
106  M_data->interfaceTolerance(),
107  M_data->fluidInterfaceVertexFlag() );
108 
109  createInterfaceMaps (M_dofStructureToFluid/*HarmonicExtension*/->localDofMap() );
110 
111  M_fluidMesh.reset();
112  M_solidMesh.reset();
113 }
114 
115 #ifdef HAVE_HDF5
116 void
117 FSIMonolithic::setupDOF ( meshFilter_Type& filterMesh )
118 {
119  createInterfaceMaps (*filterMesh.getStoredInterface (0) );
120 }
121 #endif
122 
123 void
124 FSIMonolithic::setupSystem( )
125 {
126  M_fluid->setUp ( M_dataFile );
127  setup ( M_dataFile );
128 }
129 
130 void
131 FSIMonolithic::setup ( const GetPot& dataFile )
132 {
133 
134  M_linearSolver.reset (new solver_Type (M_epetraComm) );
135 
136  M_linearSolver->setDataFromGetPot ( dataFile, "linear_system/solver" );
137  std::string prectype = dataFile ("problem/DDBlockPrec", "PRECTYPE_UNDEFINED");
138  std::string opertype = dataFile ("problem/blockOper", "PRECTYPE_UNDEFINED");
139 
140  M_precPtr.reset (BlockPrecFactory::instance().createObject ( prectype ) );
141 
142  M_precPtr->setupSolver (*M_linearSolver, dataFile);
143  std::string section ("linear_system/prec");
144  M_precPtr->setComm (M_epetraComm);
145  M_precPtr->setDataFromGetPot (dataFile, section); //to avoid if we build the prec from a matrix.
146  M_monolithicMatrix->setComm (M_epetraComm);
147  M_monolithicMatrix->setDataFromGetPot (dataFile, section); //to avoid if we build the prec from a matrix.
148  M_reusePrec = dataFile ( "linear_system/prec/reuse", true);
149  M_maxIterSolver = dataFile ( "linear_system/solver/max_iter", -1);
150  M_diagonalScale = dataFile ( "linear_system/prec/diagonalScaling", false );
151  M_restarts = dataFile ( "exporter/start" , 0 );
152 }
153 
154 void
155 FSIMonolithic::setupFluidSolid( )
156 {
157  M_BCh_flux = M_BCh_u; // For the moment M_BCh_u contains only the fluxes.
158  M_fluxes = M_BCh_u->size( );
159 
160  setupFluidSolid ( M_fluxes );
161 
162  M_BCh_flux->setOffset (M_offset - M_fluxes);
163  std::vector<BCBase>::iterator fluxIt = M_BCh_flux->begin( );
164  for ( UInt i = 0; i < M_fluxes; ++i, ++fluxIt )
165  {
166  fluxIt->setOffset ( i );
167  }
168 
169 }
170 
171 void
172 FSIMonolithic::setupFluidSolid ( UInt const fluxes )
173 {
174 
175  // Note: up to now it works only with matching grids (and poly order) on the interface
176  assert (M_fluidInterfaceMap->map (Unique)->NumGlobalElements() == M_solidInterfaceMap->map (Unique)->NumGlobalElements() );
177 
178  M_interfaceMap = M_solidInterfaceMap;
179 
180  //std::map<ID, ID> const& localDofMap = M_dofStructureToHarmonicExtension->localDofMap();
181  std::map<ID, ID>::const_iterator ITrow;
182 
183  M_monolithicMap.reset (new MapEpetra (M_uFESpace->map() ) );
184 
185  std::string opertype = M_dataFile ("problem/blockOper", "AdditiveSchwarz");
186 
187  createOperator ( opertype );
188 
189  *M_monolithicMap += M_pFESpace->map();
190  *M_monolithicMap += fluxes;
191  *M_monolithicMap += M_dFESpace->map();
192 
193  M_monolithicMatrix->createInterfaceMap ( *M_interfaceMap, M_dofStructureToFluid->localDofMap(), M_dFESpace->map().map (Unique)->NumGlobalElements() / nDimensions, M_epetraWorldComm );
194  *M_monolithicMap += *M_monolithicMatrix->interfaceMap();
195 
196  //the map for the interface coupling matrices should be done with respect to the coarser mesh.
197  M_monolithicMatrix->numerationInterface (M_numerationInterface);
198  M_beta.reset (new vector_Type (M_uFESpace->map() ) );
199 
200  M_offset = M_uFESpace->dof().numTotalDof() * nDimensions + fluxes + M_pFESpace->dof().numTotalDof();
201  M_solidAndFluidDim = M_offset + M_dFESpace->dof().numTotalDof() * nDimensions;
202  M_BCh_d->setOffset (M_offset);
203 
204  M_fluxes = fluxes;
205 }
206 
207 // ===================================================
208 // Public Methods
209 // ===================================================
210 void
211 FSIMonolithic::monolithicToInterface (vector_Type& lambdaSolid, const vector_Type& disp)
212 {
213  if (disp.mapType() == Repeated)
214  {
215  vector_Type const dispUnique (disp, Unique);
216  monolithicToInterface (lambdaSolid, dispUnique);
217  return;
218  }
219  if (lambdaSolid.mapType() == Repeated)
220  {
221  vector_Type lambdaSolidUn (lambdaSolid.map(), Unique);
222  monolithicToInterface ( lambdaSolidUn, disp);
223  lambdaSolid = lambdaSolidUn;
224  return;
225  }
226 
227  MapEpetra subMap (*disp.map().map (Unique), M_offset, disp.map().map (Unique)->NumGlobalElements() );
228  vector_Type subDisp (subMap, Unique);
229  subDisp.subset (disp, M_offset);
230  lambdaSolid = subDisp;
231 }
232 
233 void
234 FSIMonolithic::monolithicToX (const vector_Type& disp, vector_Type& dispFluid, MapEpetra& map, UInt offset)
235 {
236  if (disp.mapType() == Repeated)
237  {
238  vector_Type dispUnique (disp, Unique);
239  monolithicToX (dispUnique, dispFluid, map, offset);
240  dispFluid = dispUnique;
241  return;
242  }
243  dispFluid.subset (disp, map, offset, offset);
244 }
245 
246 
247 void
248 FSIMonolithic::buildSystem()
249 {
250  M_solid->buildSystem ( M_solidTimeAdvance->coefficientSecondDerivative ( 0 ) / (M_data->dataSolid()->dataTime()->timeStep() *M_data->dataSolid()->dataTime()->timeStep() ) );
251 }
252 
253 #ifdef HAVE_TRILINOS_ANASAZI
254 Real&
255 FSIMonolithic::computeMaxSingularValue( )
256 {
257  typedef Epetra_Operator operatorPtr_Type;
258 
259  M_preconditionedSymmetrizedMatrix.reset (new ComposedOperator<Epetra_Operator> (M_epetraComm) );
260 
261  std::shared_ptr<operatorPtr_Type> ComposedPrecPtr (M_linearSolver->preconditioner()->preconditioner() );
262 
263  //M_monolithicMatrix->getMatrixPtr()->OptimizeStorage();
264  std::shared_ptr<Epetra_FECrsMatrix> matrCrsPtr (new Epetra_FECrsMatrix (*M_monolithicMatrix->matrix()->matrixPtr() ) );
265  M_preconditionedSymmetrizedMatrix->push_back (std::static_pointer_cast<operatorPtr_Type> (/*ComposedPrecPtr*/matrCrsPtr) );
266  M_preconditionedSymmetrizedMatrix->push_back ( (ComposedPrecPtr/*matrCrsPtr*/), true);
267  M_preconditionedSymmetrizedMatrix->push_back ( (ComposedPrecPtr/*matrCrsPtr*/), true, true);
268  M_preconditionedSymmetrizedMatrix->push_back (std::static_pointer_cast<operatorPtr_Type> (/*ComposedPrecPtr*/matrCrsPtr), false, true);
269 
270  std::vector<LifeV::Real> real;
271  std::vector<LifeV::Real> imaginary;
272 
273  std::shared_ptr<EigenSolver> eig;
274 
275  UInt nev = M_dataFile ("eigensolver/nevec", 10); //number of eigenvectors
276  if (nev)
277  {
278  eig.reset (new EigenSolver (M_preconditionedSymmetrizedMatrix, M_preconditionedSymmetrizedMatrix->OperatorDomainMap(), nev) );
279  eig->setDataFromGetPot (M_dataFile, "eigensolver/");
280  eig->solve();
281  eig->eigenvalues (real, imaginary);
282  }
283  else
284  {
285  throw UNDEF_EIGENSOLVER_EXCEPTION();
286  }
287  for (UInt i = 0; i < real.size(); ++i)
288  {
289  displayer().leaderPrint ("\n real part ", real[i]);
290  displayer().leaderPrint ("\n imaginary part ", imaginary[i]);
291  }
292  return real[0];
293 }
294 #endif
295 
296 void
297 FSIMonolithic::computeFluidNormals ( vector_Type& normals)
298 {
299  BCManageNormal<matrix_Type> normalManager;
300  if ( !M_BChWS->bcUpdateDone() ) //possibly to avoid
301  {
302  M_BChWS->bcUpdate (*M_uFESpace->mesh(), M_uFESpace->feBd(), M_uFESpace->dof() );
303  }
304  normalManager.init ( (*M_BChWS) [0], 0.);
305  normalManager.computeIntegratedNormals (M_uFESpace->dof(), M_uFESpace->feBd(), normals, *M_uFESpace->mesh() );
306 }
307 
308 void
309 FSIMonolithic::solveJac ( vector_Type& step, const vector_Type& res, const Real /*linearRelTol*/ )
310 {
311  setupBlockPrec( );
312 
313  checkIfChangedFluxBC ( M_precPtr );
314 
315  M_precPtr->blockAssembling();
316  M_precPtr->applyBoundaryConditions ( dataFluid()->dataTime()->time() );
317  M_precPtr->GlobalAssemble();
318 
319 #ifdef HAVE_LIFEV_DEBUG
320  M_solid->displayer().leaderPrint (" M- Residual NormInf: ", res.normInf(), "\n");
321 #endif
322  iterateMonolithic (res, step);
323 #ifdef HAVE_LIFEV_DEBUG
324  M_solid->displayer().leaderPrint (" M- Solution NormInf: ", step.normInf(), "\n");
325 #endif
326 }
327 
328 void
329 FSIMonolithic::updateSystem()
330 {
331  *M_rhs *= 0;
332  *M_rhsFull *= 0;
333  this->M_fluid->resetStabilization();
334 }
335 
336 
337 // ===================================================
338 // Protected Methods
339 // ===================================================
340 void
341 FSIMonolithic::iterateMonolithic (const vector_Type& rhs, vector_Type& step)
342 {
343  LifeChrono chrono;
344 
345  displayer().leaderPrint (" M- Solving the system ... \n" );
346 
347  //M_monolithicMatrix->GlobalAssemble();
348  //necessary if we did not imposed Dirichlet b.c.
349 
350  M_linearSolver->setOperator (*M_monolithicMatrix->matrix()->matrixPtr() );
351 
352  M_linearSolver->setReusePreconditioner ( (M_reusePrec) && (!M_resetPrec) );
353 
354  int numIter = M_precPtr->solveSystem ( rhs, step, M_linearSolver );
355 
356  if (numIter < 0)
357  {
358  chrono.start();
359 
360  M_solid->displayer().leaderPrint (" Iterative solver failed, numiter = ", -numIter );
361 
362  if (numIter <= -M_maxIterSolver)
363  {
364  M_solid->displayer().leaderPrint (" ERROR: Iterative solver failed.\n");
365  }
366  }
367 
368  //M_solid->getDisplayer().leaderPrint(" M- System solved.\n" );
369 }
370 
371 void
372 FSIMonolithic::couplingRhs (vectorPtr_Type rhs) // not working with non-matching grids
373 {
374  std::map<ID, ID> const& localDofMap = M_dofStructureToFluid->localDofMap();
375  std::map<ID, ID>::const_iterator ITrow;
376 
377  vector_Type rhsStructureVelocity (M_solidTimeAdvance->rhsContributionFirstDerivative() *M_solid->rescaleFactor(), Unique, Add);
378  vector_Type lambda (*M_interfaceMap, Unique);
379 
380  this->monolithicToInterface (lambda, rhsStructureVelocity);
381 
382  UInt interface (M_monolithicMatrix->interface() );
383  UInt totalDofs (M_dFESpace->dof().numTotalDof() );
384 
385 
386  for (UInt dim = 0; dim < nDimensions; ++dim)
387  {
388  for ( ITrow = localDofMap.begin(); ITrow != localDofMap.end() ; ++ITrow)
389  {
390  if (M_interfaceMap->map (Unique)->LID ( static_cast<EpetraInt_Type> (ITrow->second /*+ dim*solidDim*/) ) >= 0 ) //to avoid repeated stuff
391  {
392  if (rhs.get() )
393  {
394  (*rhs) [ (int) (*M_numerationInterface) [ITrow->second ] + dim * interface + M_solidAndFluidDim ] = -lambda ( ITrow->second + dim * totalDofs );
395  }
396  }
397  }
398  }
399 }
400 
401 void
402 FSIMonolithic::
403 evalResidual ( const vector_Type& sol, const vectorPtr_Type& rhs, vector_Type& res, bool diagonalScaling)
404 {
405  if ( diagonalScaling )
406  {
407  diagonalScale (*rhs, M_monolithicMatrix->matrix() );
408  }
409 
410  // case of nonlinear laws
411  if ( ! ( M_data->dataSolid()->lawType().compare ("nonlinear") ) )
412  {
413  // need to set correctly the vectors to remove offset
414  // Extract the right proportion
415  vectorPtr_Type solidPart ( new vector_Type ( M_dFESpace->map() ) );
416  solidPart->subset (sol, M_offset );
417 
418  vectorPtr_Type resSolidPart ( new vector_Type ( M_dFESpace->map() ) );
419  resSolidPart->subset (res, M_offset );
420 
421  // Multiplying it by the rescale factor
422  *solidPart *= M_solid->rescaleFactor();
423 
424  // Computing residual
425  M_solid->apply (*solidPart, *resSolidPart);
426 
427  resSolidPart->globalAssemble();
428 
429  // reassembling them in the right places
430  // Only the residual is needed since the sol is not touched inside the solid part
431  // sol.subset( *solidPart, solidPart->map(), UInt(0), M_offset);
432  res.subset ( *resSolidPart, resSolidPart->map(), UInt (0), M_offset);
433 
434  res.globalAssemble();
435 
436  M_fluidBlock->globalAssemble();
437 
438  res += ( (*M_fluidBlock) * sol);
439 
440  M_monolithicMatrix->coupling()->globalAssemble();
441 
442  res += *M_monolithicMatrix->coupling() * sol;
443  }
444  else
445  {
446  // this works for the linear elastic case where the matrix is not touched
447  res = * (M_monolithicMatrix->matrix() ) * sol;
448 
449  res -= *rhs; // Ax-b
450  }
451 }
452 
453 void
454 FSIMonolithic::
455 updateSolidSystem ( vectorPtr_Type& rhsFluidCoupling )
456 {
457  Real coefficient ( M_data->dataSolid()->dataTime()->timeStep() * M_data->dataSolid()->dataTime()->timeStep() * M_solid->rescaleFactor() / M_solidTimeAdvance->coefficientSecondDerivative ( 0 ) );
458 
459  M_solidTimeAdvance->updateRHSContribution ( M_data->dataSolid()->dataTime()->timeStep() );
460 
461  // Extract the right portion from th right hand side contribution
462  vectorPtr_Type solidPortionRHSSecondDerivative ( new vector_Type ( M_dFESpace->map() ) );
463  solidPortionRHSSecondDerivative->subset (M_solidTimeAdvance->rhsContributionSecondDerivative(), M_offset );
464 
465  // Create a matrix of the size of the structure
466  std::shared_ptr<MatrixEpetra<Real> > solidMassMatrix (new MatrixEpetra<Real> ( M_solid->map(), 1 ) );
467  *solidMassMatrix *= 0.0;
468  *solidMassMatrix += *M_solid->massMatrix();
469  solidMassMatrix->globalAssemble();
470 
471  vectorPtr_Type solidPortionRHSFluidCoupling ( new vector_Type ( M_dFESpace->map() ) );
472  *solidPortionRHSFluidCoupling *= 0.0;
473 
474  // Computing the vector
475  *solidPortionRHSFluidCoupling = *solidMassMatrix * ( *solidPortionRHSSecondDerivative * coefficient );
476 
477  // Putting it in the right place
478  rhsFluidCoupling->subset ( *solidPortionRHSFluidCoupling, solidPortionRHSFluidCoupling->map(), UInt (0), M_offset);
479 }
480 
481 
482 void FSIMonolithic::setVectorInStencils ( const vectorPtr_Type& vel,
483  const vectorPtr_Type& pressure,
484  const vectorPtr_Type& solidDisp,
485  //const vectorPtr_Type& fluidDisp,
486  const UInt iter)
487 {
488  setFluidVectorInStencil (vel, pressure, iter);
489  setSolidVectorInStencil (solidDisp, iter);
490  // setALEVectorInStencil(fluidDisp, iter);
491 
492 }
493 
494 void FSIMonolithic::setFluidVectorInStencil ( const vectorPtr_Type& vel,
495  const vectorPtr_Type& pressure,
496  const UInt /*iter*/ )
497 {
498 
499  //The fluid and solid TimeAdvance classes have a stencil of dimension
500  //as big as the coupled problem.
501 
502  //Fluid Problem
503  vectorPtr_Type vectorMonolithicFluidVelocity (new vector_Type (*M_monolithicMap, Unique, Zero) );
504  vectorPtr_Type vectorMonolithicFluidPressure (new vector_Type (*M_monolithicMap, Unique, Zero) );
505 
506  *vectorMonolithicFluidVelocity *= 0.0;
507  *vectorMonolithicFluidPressure *= 0.0;
508 
509  vectorMonolithicFluidVelocity->subset (*vel, vel->map(), UInt (0), UInt (0) ) ;
510  vectorMonolithicFluidPressure->subset ( *pressure, pressure->map(), UInt (0), (UInt) 3 * M_uFESpace->dof().numTotalDof() );
511 
512  *vectorMonolithicFluidVelocity += *vectorMonolithicFluidPressure;
513 
514  vector_Type* normalPointerToFluidVector ( new vector_Type (*vectorMonolithicFluidVelocity) );
515  (M_fluidTimeAdvance->stencil() ).push_back ( normalPointerToFluidVector );
516 }
517 
518 
519 void FSIMonolithic::setSolidVectorInStencil ( const vectorPtr_Type& solidDisp,
520  const UInt iter)
521 {
522  //Solid problem
523  vectorPtr_Type vectorMonolithicSolidDisplacement (new vector_Type (*M_monolithicMap, Unique, Zero) );
524  *vectorMonolithicSolidDisplacement *= 0.0;
525  vectorMonolithicSolidDisplacement->subset ( *solidDisp, solidDisp->map(), (UInt) 0, M_offset);
526  *vectorMonolithicSolidDisplacement *= 1.0 / M_solid->rescaleFactor();
527 
528  //The fluid timeAdvance has size = orderBDF because it is seen as an equation frist order in time.
529  //We need to add the solidVector to the fluidVector in the fluid TimeAdvance because we have the
530  //extrapolation on it.
531  if ( iter <= M_fluidTimeAdvance->size() - 1 )
532  {
533  * ( M_fluidTimeAdvance->stencil() [ iter ] ) += *vectorMonolithicSolidDisplacement;
534  }
535 
536  vector_Type* normalPointerToSolidVector ( new vector_Type (*vectorMonolithicSolidDisplacement) );
537  (M_solidTimeAdvance->stencil() ).push_back ( normalPointerToSolidVector );
538 
539 }
540 
541 void FSIMonolithic::finalizeRestart( )
542 {
543  //Set the initialRHS for the TimeAdvance classes
544  vector_Type zeroFluidSolid (*M_monolithicMap, Unique, Zero);
545  vector_Type zeroALE (M_mmFESpace->map(), Unique, Zero);
546 
547  zeroFluidSolid *= 0.0;
548  zeroALE *= 0.0;
549 
550  M_fluidTimeAdvance->setInitialRHS (zeroFluidSolid);
551  M_solidTimeAdvance->setInitialRHS (zeroFluidSolid);
552  M_ALETimeAdvance->setInitialRHS (zeroALE);
553 
554  //This updates at the current value (the one when the simulation was stopped) the RHScontribution
555  //of the first derivative which is use to compute the velocity in TimeAdvance::velocity().
556  //Please note that, even if it is ugly, at this stage, the fluidTimeAdvance is leading the Time Discretization
557  //and this is why there is the dataFluid class to get the dt.
558  M_ALETimeAdvance->updateRHSFirstDerivative ( M_data->dataFluid()->dataTime()->timeStep() );
559 }
560 
561 void FSIMonolithic::initializeMonolithicOperator ( std::vector< vectorPtr_Type> u0,
562  std::vector< vectorPtr_Type> ds0,
563  std::vector< vectorPtr_Type> df0)
564 {
565  UInt i;
566  if (!u0.size() || !ds0.size() || !df0.size() )
567  {
568  if ( this->isFluid() )
569  {
570  for (i = 0; i < M_fluidTimeAdvance->size(); ++i)
571  {
572  vectorPtr_Type vec (new vector_Type ( *M_monolithicMap ) );
573  u0.push_back (vec); // couplingVariableMap()
574  }
575  for (i = 0; i < M_ALETimeAdvance->size(); ++i)
576  {
577  vectorPtr_Type vec (new vector_Type ( M_mmFESpace->map() ) );
578  df0.push_back (vec); // couplingVariableMap()
579  }
580  }
581  if ( this->isSolid() )
582  {
583  for (i = 0; i < M_solidTimeAdvance->size(); ++i)
584  {
585  vectorPtr_Type vec (new vector_Type ( *M_monolithicMap ) );
586  ds0.push_back (vec); // couplingVariableMap()
587  }
588  }
589  initializeTimeAdvance (u0, ds0, df0);
590  // M_oper->initializeBDF(*u0);
591  }
592  else
593  {
594  initializeTimeAdvance (u0, ds0, df0); // couplingVariableMap()//copy
595  }
596 
597 }
598 
599 void
600 FSIMonolithic::
601 diagonalScale (vector_Type& rhs, matrixPtr_Type matrFull)
602 {
603  Epetra_Vector diagonal (*rhs.map().map (Unique) );
604  //M_matrFull->matrixPtr()->InvRowSums(diagonal);
605  //M_matrFull->matrixPtr()->InvRowMaxs(diagonal);
606  //M_matrFull->matrixPtr()->InvColSums(diagonal);
607  matrFull->matrixPtr()->InvColMaxs (diagonal);
608  matrFull->matrixPtr()->LeftScale (diagonal);
609  rhs.epetraVector().Multiply (1, rhs.epetraVector(), diagonal, 0);
610 }
611 
612 void
613 FSIMonolithic::variablesInit (const std::string& dOrder)
614 {
615  M_dFESpace.reset (new FESpace<mesh_Type, MapEpetra> (M_solidLocalMesh,
616  dOrder,
617  3,
618  M_epetraComm) );
619 
620  M_dETFESpace.reset (new ETFESpace<mesh_Type, MapEpetra, 3, 3> (M_solidLocalMesh,
621  & (M_dFESpace->refFE() ),
622  & (M_dFESpace->fe().geoMap() ),
623  M_epetraComm) );
624 
625 
626  // INITIALIZATION OF THE VARIABLES
627  M_lambdaFluid.reset (new vector_Type (*M_fluidInterfaceMap, Unique) );
628  M_lambdaFluidRepeated.reset (new vector_Type (*M_fluidInterfaceMap, Repeated) );
629 }
630 
631 void FSIMonolithic::setupBlockPrec( )
632 {
633  if (! (M_precPtr->set() ) )
634  {
635  M_precPtr->push_back_matrix (M_solidBlockPrec, M_structureNonLinear);
636  M_precPtr->push_back_matrix (M_fluidBlock, true);
637  M_precPtr->setConditions (M_BChs);
638  M_precPtr->setSpaces (M_FESpaces);
639  M_precPtr->setOffsets (2, M_offset, 0);
640  M_precPtr->coupler (M_monolithicMap, M_dofStructureToFluid->localDofMap(), M_numerationInterface, M_data->dataFluid()->dataTime()->timeStep(), M_solidTimeAdvance->coefficientFirstDerivative ( 0 ), M_solid->rescaleFactor() );
641  }
642  else
643  {
644  M_precPtr->replace_matrix (M_fluidBlock, 1);
645  M_precPtr->replace_matrix (M_solidBlockPrec, 0);
646  }
647 
648 #ifdef HAVE_NS_PREC
649  /* This shall be enabled once the branch about NS_PREC is going to be merged to master*/
650  std::shared_ptr<MonolithicBlockComposed> blockPrecPointer ( std::dynamic_pointer_cast<MonolithicBlockComposed> M_precPtr);
651 
652  if (blockPrecPointer.get() != 0)
653  {
654  UInt fluidPosition = blockPrecPointer->whereIsBlock (MonolithicBlockComposed::fluid);
655  ASSERT (blockPrecPointer->blockPrecs().size() < fluidPosition, "The preconditioner corresponding to the fluid block is probably not PCD. Check in the data file");
656  std::shared_ptr<PreconditionerPCD> prec_PCD ( std::dynamic_pointer_cast<PreconditionerPCD> blockPrecPointer->blockPrecs() [fluidPosition] );
657 
658 
659  if (prec_PCD.get() != 0)
660  {
661  prec_PCD->setFESpace (M_uFESpace, M_pFESpace);
662  prec_PCD->setBCHandler (M_BCh_u);
663  prec_PCD->setTimestep (M_data->dataFluid()->dataTime()->timeStep() );
664  prec_PCD->setViscosity (M_data->dataFluid()->viscosity() );
665  prec_PCD->setDensity (M_data->dataFluid()->density() );
666  prec_PCD->setCouplingMatrixView (M_precPtr->couplingVector() [MonolithicBlockComposed::fluid]);
667  prec_PCD->setMapStructure (&M_dFESpace->map() );
668  prec_PCD->updateBeta (M_fluidTimeAdvance->singleElement (0) );
669  }
670  }
671 #endif
672 }
673 
674 void
675 FSIMonolithic::assembleSolidBlock ( UInt iter, const vector_Type& solution )
676 {
677  if (iter == 0)
678  {
679  updateSolidSystem (this->M_rhs);
680  }
681 
682  // Resetting the solidBlockPrec term
683  M_solidBlockPrec.reset (new matrix_Type (*M_monolithicMap, 1) );
684  *M_solidBlockPrec *= 0.0;
685 
686  // When ET for structures is used, there is not offset parameter. This is why
687  // we need to extract portions of vector and mount them in the proper parts.
688  // Extractig the right portion from the total solution of the solid part
689  vectorPtr_Type solidPortion ( new vector_Type ( M_dFESpace->map() ) );
690  solidPortion->subset (solution, M_offset );
691 
692  //Multiplying it by the rescale factor
693  *solidPortion *= M_solid->rescaleFactor();
694 
695  // Start building a block matrix to handle easily the assembled part
696  // in the structure module.
697  //1. Create the correct global map for fluxes
698  MapEpetra mapEpetraFluxes ( M_fluxes, M_epetraComm );
699 
700  //2. Construct a global MapVector with all the maps
701  // The globalMatrix will be adjusted according to the monolithic solver
702  // that is used.
703  matrixBlockPtr_Type globalMatrixWithOnlyStructure;
704 
705  //The map is composed of ( u , p , fluxes, solid, interface, d_f )
706  if ( !M_data->method().compare ("monolithicGI") )
707  {
708  globalMatrixWithOnlyStructure.reset (new matrixBlock_Type ( M_uFESpace->map() | M_pFESpace->map() | mapEpetraFluxes | M_dFESpace->map()
709  | * (M_monolithicMatrix->interfaceMap() ) | M_mmFESpace->map() ) );
710  }
711  //The map is composed of ( u , p , fluxes, solid, interface )
712  else
713  {
714  globalMatrixWithOnlyStructure.reset (new matrixBlock_Type ( M_uFESpace->map() | M_pFESpace->map() | mapEpetraFluxes | M_dFESpace->map()
715  | * (M_monolithicMatrix->interfaceMap() ) ) );
716  }
717 
718  // In the case of LE it does not do anything.
719  M_solid->material()->updateJacobianMatrix ( *solidPortion, dataSolid(), M_solid->mapMarkersVolumes(), M_solid->mapMarkersIndexes(), M_solid->displayerPtr() ); // computing the derivatives if nonlinear (comment this for inexact Newton);
720 
721  //Need to inglobe it into a boost::shared to avoid memeory leak
722  std::shared_ptr<MatrixEpetra<Real> > solidMatrix (new MatrixEpetra<Real> ( M_solid->map(), 1 ) );
723  *solidMatrix *= 0.0;
724 
725  *solidMatrix += *M_solid->massMatrix();
726  *solidMatrix += * (M_solid->material()->jacobian() );
727 
728  solidMatrix->globalAssemble();
729 
730  MatrixEpetra<Real>* rawPointerToMatrix = new MatrixEpetra<Real> ( *solidMatrix );
731 
732  matrixBlockView_Type structurePart (* (globalMatrixWithOnlyStructure->block (3, 3) ) );
733 
734  structurePart.setup (UInt (0), UInt (0), UInt (3 * M_dFESpace->dof().numTotalDof() ), UInt (3 * M_dFESpace->dof().numTotalDof() ), rawPointerToMatrix);
735 
736  using namespace MatrixEpetraStructuredUtility;
737 
738  //3. Put the matrix assembled in the solid in the proper vector
739  copyBlock ( structurePart, * (globalMatrixWithOnlyStructure->block (3, 3) ) );
740 
741  globalMatrixWithOnlyStructure->globalAssemble();
742 
743  //Summing the local matrix into the global
744  *M_solidBlockPrec += *globalMatrixWithOnlyStructure;
745 
746  M_solidBlockPrec->globalAssemble();
747 
748  *M_solidBlockPrec *= M_solid->rescaleFactor();
749 
750  delete rawPointerToMatrix;
751 }
752 
753 void
754 FSIMonolithic::assembleFluidBlock (UInt iter, const vector_Type& solution)
755 {
756  M_fluidBlock.reset (new FSIOperator::fluid_Type::matrix_Type (*M_monolithicMap) );
757 
758  Real alpha = M_fluidTimeAdvance->coefficientFirstDerivative ( 0 ) / M_data->dataFluid()->dataTime()->timeStep(); //mesh velocity w
759 
760  //This line is based on the hypothesis that the conservativeFormulation flag is set on FALSE
761  M_fluid->updateSystem (alpha, *this->M_beta, *this->M_rhs, M_fluidBlock, solution );
762 
763  //This in the case of conservativeFormulation == true
764  // else
765  // if (! M_fluid->matrixMassPtr().get() )
766  // M_fluid->buildSystem( );
767 
768  if (iter == 0)
769  {
770  M_resetPrec = true;
771  M_fluidTimeAdvance->updateRHSContribution ( M_data->dataFluid()->dataTime()->timeStep() );
772  if (!M_data->dataFluid()->conservativeFormulation() )
773  {
774  *M_rhs += M_fluid->matrixMass() * (M_fluidTimeAdvance->rhsContributionFirstDerivative() );
775  }
776  else
777  {
778  *M_rhs += (M_fluidMassTimeAdvance->rhsContributionFirstDerivative() );
779  }
780  couplingRhs (M_rhs/*, M_fluidTimeAdvance->stencil()[0]*/);
781  }
782  //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.
783  //At the moment, the flag conservativeFormulation should be always kept on FALSE
784  if (M_data->dataFluid()->conservativeFormulation() )
785  {
786  M_fluid->updateSystem (alpha, *this->M_beta, *this->M_rhs, M_fluidBlock, solution );
787  }
788  this->M_fluid->updateStabilization (*M_fluidBlock);
789 }
790 
791 void FSIMonolithic::updateRHS()
792 {
793  // Update fluid (iter == 0)
794  M_fluidTimeAdvance->updateRHSContribution ( M_data->dataFluid()->dataTime()->timeStep() );
795  *M_rhs += M_fluid->matrixMass() * (M_fluidTimeAdvance->rhsContributionFirstDerivative() );
796  couplingRhs (M_rhs);
797 
798  // Update solid (iter == 0)
799  updateSolidSystem (M_rhs);
800 
801  // Update RHS
802  *M_rhsFull = *M_rhs;
803 }
804 
805 namespace
806 {
807 static Real fZero (const Real& /*t*/, const Real& /*x*/, const Real& /*y*/, const Real& /*z*/, const ID& /*i*/)
808 {
809  return 0.;
810 }
811 static Real fOne (const Real& /*t*/, const Real& /*x*/, const Real& /*y*/, const Real& /*z*/, const ID& /*i*/)
812 {
813  return 1.;
814 }
815 }
816 
817 void FSIMonolithic::enableStressComputation (UInt flag)
818 {
819  M_BChWS.reset (new solidBchandler_Type() );
820  BCFunctionBase bcfZero (fZero);
821  BCFunctionBase bcfOne (fOne);
822  M_bcfWs.setFunctions_Robin (bcfOne, bcfOne);
823 
824  M_BChWS->addBC ("WS", (UInt) flag, Robin, Full, M_bcfWs, 3);
825 }
826 
827 FSIMonolithic::vectorPtr_Type FSIMonolithic::computeStress()
828 {
829  vector_Type lambda (M_monolithicMatrix->interfaceMap() );
830  lambda.subset (M_fluidTimeAdvance->singleElement (0), M_solidAndFluidDim);
831 
832  M_boundaryMass.reset (new matrix_Type (*M_interfaceMap) );
833  if ( !M_BChWS->bcUpdateDone() )
834  {
835  M_BChWS->bcUpdate (*M_dFESpace->mesh(), M_dFESpace->feBd(), M_dFESpace->dof() );
836  }
837  bcManageMatrix (*M_boundaryMass, *M_dFESpace->mesh(), M_dFESpace->dof(), *M_BChWS, M_dFESpace->feBd(), 1., dataSolid()->dataTime()->time() );
838  M_boundaryMass->globalAssemble();
839 
840  solver_Type solverMass (M_epetraComm);
841  solverMass.setDataFromGetPot ( M_dataFile, "solid/solver" );
842  solverMass.setupPreconditioner (M_dataFile, "solid/prec"); //to avoid if we have already a prec.
843 
844  std::shared_ptr<PreconditionerIfpack> P (new PreconditionerIfpack() );
845 
846  vectorPtr_Type sol (new vector_Type (M_monolithicMatrix->interfaceMap() ) );
847  solverMass.setMatrix (*M_boundaryMass);
848  solverMass.setReusePreconditioner (false);
849  solverMass.solveSystem ( lambda, *sol, M_boundaryMass);
850 
851  EpetraExt::MultiVector_Reindex reindexMV (*M_interfaceMap->map (Unique) );
852  std::shared_ptr<MapEpetra> newMap (new MapEpetra ( *M_interfaceMap ) );
853  M_stress.reset (new vector_Type (reindexMV (lambda.epetraVector() ), newMap, Unique) );
854  return M_stress;
855 }
856 
857 void
858 FSIMonolithic::checkIfChangedFluxBC ( precPtr_Type oper )
859 {
860  UInt nfluxes (M_BChs[1]->numberOfBCWithType (Flux) );
861  if (M_fluxes != nfluxes)
862  {
863  for (UInt i = 0; i < M_fluxes; ++i)
864  {
865  const BCBase* bc (M_BChs[1]->findBCWithName (M_BCFluxNames[i]) );
866  if (bc->type() != Flux)
867  {
868  oper->addToCoupling (1., M_fluxOffset[i], M_fluxOffset[i], 1 );
869  }
870  }
871  }
872 }
873 
874 
875 }