LifeV
MultiscaleModelFSI3D.hpp
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  * @file
29  * @brief File containing the Multiscale Model FSI3D
30  *
31  * @date 19-04-2010
32  * @author Paolo Crosetto <paolo.crosetto@epfl.ch>
33  * @author Cristiano Malossi <cristiano.malossi@epfl.ch>
34  *
35  * @maintainer Cristiano Malossi <cristiano.malossi@epfl.ch>
36  */
37 
38 #ifndef MultiscaleModelFSI3D_H
39 #define MultiscaleModelFSI3D_H 1
40 
41 // If the following macro is defined, the pressure inside the 3-D FSI model
42 // is initialized to the external pressure. Otherwise, the external pressure
43 // is applied just as an offset at the interfaces.
44 //#define FSI_WITH_EXTERNALPRESSURE
45 
46 // If the following macro is defined, any flow rate BC is prescribed in the
47 // classical way, i.e., weakly through a Lagrange multiplier. Otherwise, the user
48 // can chose to prescribe it through an essential BC (a given velocity profile).
49 //#define FSI_WITHOUT_VELOCITYPROFILE
50 
51 // This macro now serves just to easily identify the part of the code where the
52 // methods needed for coupling the area are called. Apart from that, it is useless,
53 // and in the future can be removed.
54 #define FSI_WITH_BOUNDARYAREA
55 
56 // This macro enable/disable the stress computation in the structural solver.
57 #define FSI_WITH_STRESSOUTPUT
58 
59 #include <lifev/core/filter/ExporterEnsight.hpp>
60 #ifdef HAVE_HDF5
61 #include <lifev/core/filter/ExporterHDF5.hpp>
62 #endif
63 
64 #include <lifev/core/algorithm/NonLinearRichardson.hpp>
65 
66 #include <lifev/bc_interface/3D/function/fsi/BCInterfaceFunctionParserFSI3D.hpp>
67 #include <lifev/bc_interface/3D/function/fsi/BCInterfaceFunctionParserSolverFSI3D.hpp>
68 #include <lifev/bc_interface/3D/function/fsi/BCInterfaceFunctionSolverDefinedFSI3D.hpp>
69 #include <lifev/bc_interface/3D/function/fsi/BCInterfaceFunctionUserDefinedFSI3D.hpp>
70 #include <lifev/bc_interface/3D/bc/BCInterface3D.hpp>
71 
72 #include <lifev/fsi/solver/FSIMonolithic.hpp>
73 #include <lifev/fsi/solver/FSIMonolithicGE.hpp>
74 #include <lifev/fsi/solver/FSIMonolithicGI.hpp>
75 
76 #include <lifev/fsi/solver/MonolithicBlockMatrix.hpp>
77 #include <lifev/fsi/solver/MonolithicBlockMatrixRN.hpp>
78 #include <lifev/fsi/solver/MonolithicBlockComposedDN.hpp>
79 #include <lifev/fsi/solver/MonolithicBlockComposedNN.hpp>
80 #include <lifev/fsi/solver/MonolithicBlockComposedDNND.hpp>
81 
83 #include <lifev/structure/solver/WallTensionEstimator.hpp>
84 #include <lifev/structure/solver/WallTensionEstimatorData.hpp>
85 #endif
86 
87 #include <lifev/multiscale/models/MultiscaleModel.hpp>
88 #include <lifev/multiscale/framework/MultiscaleInterface.hpp>
89 
90 namespace LifeV
91 {
92 namespace Multiscale
93 {
94 
95 #ifndef FSI_WITH_EXTERNALPRESSURE
96 // Forward declaration
97 class FSI3DBoundaryStressFunction;
98 #endif
99 
100 #ifndef FSI_WITHOUT_VELOCITYPROFILE
101 // Forward declaration
102 class FSI3DBoundaryFlowRateFunction;
103 #endif
104 
106 // Forward declaration
107 class FSI3DBoundaryAreaFunction;
108 #endif
109 
110 //! MultiscaleModelFSI3D - Multiscale model for 3D FSI simulations
111 /*!
112  * @author Paolo Crosetto
113  * @author Cristiano Malossi <cristiano.malossi@epfl.ch>
114  *
115  * @see Full description of the Geometrical Multiscale Framework: \cite Malossi-Thesis
116  * @see Methodology: \cite Malossi2011Algorithms \cite Malossi2011Algorithms1D \cite Malossi2011Algorithms3D1DFSI \cite BlancoMalossi2012
117  * @see Applications: \cite Malossi2011Algorithms3D1DFSIAortaIliac \cite LassilaMalossi2012IdealLeftVentricle \cite BonnemainMalossi2012LVAD
118  */
119 class MultiscaleModelFSI3D: public virtual multiscaleModel_Type,
120  public virtual MultiscaleInterface
121 {
122 public:
123 
124  //! @name Public Types
125  //@{
126 
127  typedef FSIMonolithic FSIOperator_Type;
128  typedef std::shared_ptr< FSIOperator_Type> FSIOperatorPtr_Type;
129 
130  typedef FSIOperator::data_Type data_Type;
131  typedef FSIOperator::dataPtr_Type dataPtr_Type;
132 
133  typedef FSIOperator::mesh_Type mesh_Type;
134 
135  typedef FSIOperator::fluid_Type fluid_Type;
136  typedef FSIOperator::solid_Type solid_Type;
137 
138  typedef FSIOperator::vector_Type vector_Type;
139  typedef FSIOperator::vectorPtr_Type vectorPtr_Type;
140 
141  typedef Exporter< mesh_Type > IOFile_Type;
142  typedef std::shared_ptr< IOFile_Type > IOFilePtr_Type;
143  typedef ExporterData< mesh_Type > IOData_Type;
144 
145  typedef ExporterEnsight< mesh_Type > ensightIOFile_Type;
146 #ifdef HAVE_HDF5
147  typedef ExporterHDF5< mesh_Type > hdf5IOFile_Type;
148 #endif
149 
150  typedef BCHandler bc_Type;
151  typedef std::shared_ptr< bc_Type > bcPtr_Type;
152  typedef BCInterface3D< bc_Type, FSIOperator > bcInterface_Type;
153  typedef std::shared_ptr< bcInterface_Type > bcInterfacePtr_Type;
154 
155 #ifndef FSI_WITH_EXTERNALPRESSURE
156  typedef FSI3DBoundaryStressFunction boundaryStressFunction_Type;
157  typedef std::shared_ptr< boundaryStressFunction_Type > boundaryStressFunctionPtr_Type;
158  typedef std::vector< boundaryStressFunctionPtr_Type > boundaryStressFunctionContainer_Type;
159 #endif
160 
161 #ifndef FSI_WITHOUT_VELOCITYPROFILE
162 
163  /*! @enum FSI3DBoundaryFlowRate_Type
164  */
165  enum FSI3DBoundaryFlowRate_Type
166  {
167  Weak, /*!< always impose flow rate weakly (DEFAULT) */
168  Semiweak, /*!< impose essential when flow rate = 0, otherwise impose flow rate weakly */
169  Strong /*!< always impose essential with user prescribed velocity profile */
170  };
171 
172  typedef std::vector< FSI3DBoundaryFlowRate_Type > boundaryFlowRateTypeContainer_Type;
173 
174  typedef std::map< multiscaleID_Type, FSI3DBoundaryFlowRate_Type > boundaryFlowRateMap_Type;
175 
176  typedef FSI3DBoundaryFlowRateFunction boundaryFlowRateFunction_Type;
177  typedef std::shared_ptr< boundaryFlowRateFunction_Type > boundaryFlowRateFunctionPtr_Type;
178  typedef std::vector< boundaryFlowRateFunctionPtr_Type > boundaryFlowRateFunctionsContainer_Type;
179  typedef boundaryFlowRateFunctionsContainer_Type::iterator boundaryFlowRateFunctionsContainerIterator_Type;
180 #endif
181 
183  typedef FSI3DBoundaryAreaFunction boundaryAreaFunction_Type;
184  typedef std::shared_ptr< boundaryAreaFunction_Type > boundaryAreaFunctionPtr_Type;
185  typedef std::vector< boundaryAreaFunctionPtr_Type > boundaryAreaFunctionsContainer_Type;
186  typedef boundaryAreaFunctionsContainer_Type::iterator boundaryAreaFunctionsContainerIterator_Type;
187 #endif
188 
190  typedef WallTensionEstimator< mesh_Type > wallTensionEstimator_Type;
191  typedef std::shared_ptr< wallTensionEstimator_Type > wallTensionEstimatorPtr_Type;
192 #endif
193 
194  //@}
195 
196 
197  //! @name Constructor & Destructor
198  //@{
199 
200  //! Constructor
201  explicit MultiscaleModelFSI3D();
202 
203  //! Destructor
204  virtual ~MultiscaleModelFSI3D() {}
205 
206  //@}
207 
208 
209  //! @name MultiscaleModel Methods
210  //@{
211 
212  //! Setup the data of the model.
213  /*!
214  * @param fileName Name of data file.
215  */
216  void setupData ( const std::string& fileName );
217 
218  //! Setup the model.
219  void setupModel();
220 
221  //! Build the initial model.
222  void buildModel();
223 
224  //! Update the model.
225  void updateModel();
226 
227  //! Solve the model.
228  void solveModel();
229 
230  //! Update the solution.
231  void updateSolution();
232 
233  //! Save the solution
234  void saveSolution();
235 
236  //! Display some information about the model.
237  void showMe();
238 
239  //! Return a specific scalar quantity to be used for a comparison with a reference value.
240  /*!
241  * This method is meant to be used for night checks.
242  * @return reference quantity.
243  */
244  Real checkSolution() const;
245 
246  //@}
247 
248 
249  //! @name MultiscaleInterface Methods
250  //@{
251 
252  //! Impose the flow rate on a specific interface of the model
253  /*!
254  * @param boundaryID ID of the boundary interface
255  * @param function boundary condition function
256  */
257  void imposeBoundaryFlowRate ( const multiscaleID_Type& boundaryID, const function_Type& function );
258 
259  //! Impose the integral of the mean normal stress on a specific boundary interface of the model
260  /*!
261  * @param boundaryID ID of the boundary interface
262  * @param function boundary condition function
263  */
264  void imposeBoundaryMeanNormalStress ( const multiscaleID_Type& boundaryID, const function_Type& function );
265 
266  //! Impose the integral of the mean total normal stress on a specific boundary interface of the model
267  /*!
268  * Note: mean total normal stress cannot be imposed at the interfaces of this model.
269  *
270  * @param boundaryID ID of the boundary interface
271  * @param function boundary condition function
272  */
273  void imposeBoundaryMeanTotalNormalStress ( const multiscaleID_Type& /*boundaryID*/, const function_Type& /*function*/ )
274  {
275  multiscaleErrorCheck ( ModelInterface, "Invalid interface [MeanTotalNormalStress] for model type [" + enum2String ( M_type, multiscaleModelsMap ) + "]", M_comm->MyPID() == 0 );
276  }
277 
278  //! Impose the area on a specific boundary interface of the model
279  /*!
280  * Note: area cannot be imposed at the interfaces of this model.
281  *
282  * @param boundaryID ID of the boundary interface
283  * @param function boundary condition function
284  */
285  void imposeBoundaryArea ( const multiscaleID_Type& boundaryID, const function_Type& function );
286 
287  //! Get the flow rate on a specific boundary interface of the model
288  /*!
289  * @param boundaryID ID of the boundary interface
290  * @return flow rate value
291  */
292  Real boundaryFlowRate ( const multiscaleID_Type& boundaryID ) const
293  {
294  return M_FSIoperator->fluid().flux ( boundaryFlag ( boundaryID ), *M_stateVariable );
295  }
296 
297  //! Get the integral of the mean normal stress on a specific boundary interface of the model
298  /*!
299  * @param boundaryID ID of the boundary interface
300  * @return mean normal stress value
301  */
302  Real boundaryMeanNormalStress ( const multiscaleID_Type& boundaryID ) const;
303 
304  //! Get the integral of the mean total normal stress on a specific boundary interface of the model
305  /*!
306  * @param boundaryID ID of the boundary interface
307  * @return mean total normal stress value
308  */
309  Real boundaryMeanTotalNormalStress ( const multiscaleID_Type& boundaryID ) const;
310 
311  //! Get the area on a specific boundary interface of the model
312  /*!
313  * @param boundaryID ID of the boundary interface
314  * @return area value
315  */
316  Real boundaryArea ( const multiscaleID_Type& boundaryID ) const
317  {
318  return M_FSIoperator->fluid().area ( boundaryFlag ( boundaryID ) );
319  }
320 
321  //! Get the variation of the flow rate (on a specific boundary interface) using the linear model
322  /*!
323  * @param boundaryID ID of the boundary interface
324  * @param solveLinearSystem a flag to which determine if the linear system has to be solved
325  * @return variation of the flow rate
326  */
327  Real boundaryDeltaFlowRate ( const multiscaleID_Type& boundaryID, bool& solveLinearSystem );
328 
329  //! Get the variation of the integral of the mean normal stress (on a specific boundary interface) using the linear model
330  /*!
331  * @param boundaryID ID of the boundary interface
332  * @param solveLinearSystem a flag to which determine if the linear system has to be solved
333  * @return variation of the mean normal stress
334  */
335  Real boundaryDeltaMeanNormalStress ( const multiscaleID_Type& boundaryID, bool& solveLinearSystem );
336 
337  //! Get the variation of the integral of the mean total normal stress (on a specific boundary interface) using the linear model
338  /*!
339  * TODO The integral terms of the derivative of the area have not been coded yet. They are used only by the GI formulation.
340  * @param boundaryID ID of the boundary interface
341  * @param solveLinearSystem a flag to which determine if the linear system has to be solved
342  * @return variation of the mean total normal stress
343  */
344  Real boundaryDeltaMeanTotalNormalStress ( const multiscaleID_Type& boundaryID, bool& solveLinearSystem );
345 
346  //! Get the variation of the integral of the area (on a specific boundary interface) using the linear model
347  /*!
348  * Note: returns always a NaN since this specific method is never used in the current interface equations.
349  *
350  * @param boundaryID ID of the boundary interface
351  * @param solveLinearSystem a flag to which determine if the linear system has to be solved
352  * @return variation of the area
353  */
354  Real boundaryDeltaArea ( const multiscaleID_Type& /*boundaryID*/, bool& /*solveLinearSystem*/ )
355  {
356  return NaN;
357  }
358 
359  //@}
360 
361 
362  //! @name Get Methods
363  //@{
364 
365  //! Get the FSI3D fluid bcHandler
366  /*!
367  * @return FSI3D fluid bcHandler
368  */
369  bc_Type& bcHandlerFluid()
370  {
371  return *M_fluidBC->handler();
372  }
373 
374  //! Get the FSI3D solid bcHandler
375  /*!
376  * @return FSI3D solid bcHandler
377  */
378  bc_Type& bcHandlerSolid()
379  {
380  return *M_solidBC->handler();
381  }
382 
383  //! Get the BCInterface container of the boundary conditions of the model
384  /*!
385  * @return BCInterface container
386  */
387  bcInterface_Type& bcInterface()
388  {
389  return *M_fluidBC;
390  }
391 
392  //! Get the density on a specific boundary face of the model
393  /*!
394  * @return density value
395  */
396  Real boundaryDensity() const
397  {
398  return M_FSIoperator->dataFluid()->density();
399  }
400 
401  //! Get the viscosity on a specific boundary face of the model
402  /*!
403  * @return viscosity value
404  */
405  Real boundaryViscosity() const
406  {
407  return M_FSIoperator->dataFluid()->viscosity();
408  }
409 
410  //! Get the integral of the pressure (on a specific boundary face)
411  /*!
412  * @param boundaryID ID of the boundary interface
413  * @return pressure value
414  */
415  Real boundaryPressure ( const multiscaleID_Type& boundaryID ) const;
416 
417  //! Get the integral of the total pressure (on a specific boundary face)
418  /*!
419  * @param boundaryID ID of the boundary interface
420  * @return total pressure value
421  */
422  Real boundaryTotalPressure ( const multiscaleID_Type& boundaryID ) const;
423 
424  //! Get the external wall pressure
425  /*!
426  * @return external pressure value
427  */
428  Real externalPressure() const;
429 
430  //! Get the FSI3D data container
431  /*!
432  * @return FSI3D data container
433  */
434  const dataPtr_Type& data() const
435  {
436  return M_data;
437  }
438 
439  //! Get the FSI3D operator
440  /*!
441  * @return FSI3D operator
442  */
443  const FSIOperatorPtr_Type& solver() const
444  {
445  return M_FSIoperator;
446  }
447 
448  //@}
449 
450 private:
451 
452  //! @name Unimplemented Methods
453  //@{
454 
455  MultiscaleModelFSI3D ( const MultiscaleModelFSI3D& model );
456 
457  MultiscaleModelFSI3D& operator= ( const MultiscaleModelFSI3D& model );
458 
459  //@}
460 
461 
462  //! @name Private Methods
463  //@{
464 
465  //! Setup the global data of the model.
466  /*!
467  * In particular, it replaces the default local values with the ones in the global container.
468  * If a value is already specified in the data file, do not perform the replacement.
469  *
470  * @param fileName File name of the specific model.
471  */
472  void setupGlobalData ( const std::string& fileName );
473 
474  //! Initialize the FSI solution.
475  void initializeSolution();
476 
477  void setupCommunicator();
478 
479  void setupBC ( const std::string& fileName );
480  void updateBC();
481 
482  void setupExporter ( IOFilePtr_Type& exporter, const GetPot& dataFile, const std::string& label = "" );
483  void setupImporter ( IOFilePtr_Type& exporter, const GetPot& dataFile, const std::string& label = "" );
484 
485  void setExporterFluid ( const IOFilePtr_Type& exporter );
486  void setExporterSolid ( const IOFilePtr_Type& exporter );
487 
488  void exportFluidSolution();
489  void exportSolidSolution();
490 
491  //! Setup the linear model
492  void setupLinearModel();
493 
494  //! Update the linear system matrix and vectors
495  void updateLinearModel();
496 
497  //! Solve the linear problem
498  void solveLinearModel ( bool& solveLinearSystem );
499 
500  //! Impose the coupling perturbation on the correct BC inside the BCHandler
501  void imposePerturbation();
502 
503  //! Reset all the coupling perturbations imposed on the BCHandler
504  void resetPerturbation();
505 
506  Real bcFunctionDeltaZero ( const Real& /*t*/, const Real& /*x*/, const Real& /*y*/, const Real& /*z*/, const UInt& /*id*/ )
507  {
508  return 0.;
509  }
510  Real bcFunctionDeltaOne ( const Real& /*t*/, const Real& /*x*/, const Real& /*y*/, const Real& /*z*/, const UInt& /*id*/ )
511  {
512  return 1.;
513  }
514 
515  //@}
516 
517  // Operator
518  FSIOperatorPtr_Type M_FSIoperator;
519 
520  // Data
521  dataPtr_Type M_data;
522 
523  // Exporters
524  IOFilePtr_Type M_exporterFluid;
525  IOFilePtr_Type M_exporterSolid;
526 
527  // Importers
528  IOFilePtr_Type M_importerFluid;
529  IOFilePtr_Type M_importerSolid;
530 
531 #ifndef FSI_WITH_EXTERNALPRESSURE
532  // Stress coupling function container
533  boundaryStressFunctionContainer_Type M_boundaryStressFunctions;
534 
535  // Scalar external pressure
536  Real M_externalPressureScalar;
537 #endif
538 
539 #ifndef FSI_WITHOUT_VELOCITYPROFILE
540  // Flow rate coupling function container
541  boundaryFlowRateFunctionsContainer_Type M_boundaryFlowRateFunctions;
542 
543  // Flow rate type container
544  boundaryFlowRateTypeContainer_Type M_boundaryFlowRateType;
545 #endif
546 
548  // Boundary area coupling function container
549  boundaryAreaFunctionsContainer_Type M_boundaryAreaFunctions;
550 
551  // Free flags, available for the couplings
552  multiscaleIDContainer_Type M_boundaryFlagsArea;
553  std::vector< bool > M_boundaryFlagsAreaPerturbed;
554 #endif
555 
557  wallTensionEstimatorPtr_Type M_wallTensionEstimator;
558 #endif
559 
560  // Post processing members
561  vectorPtr_Type M_fluidVelocity;
562  vectorPtr_Type M_fluidPressure;
563  vectorPtr_Type M_fluidDisplacement;
564  vectorPtr_Type M_solidVelocity;
565  vectorPtr_Type M_solidDisplacement;
566 
568  vectorPtr_Type M_solidStressXX;
569  vectorPtr_Type M_solidStressXY;
570  vectorPtr_Type M_solidStressXZ;
571  vectorPtr_Type M_solidStressYY;
572  vectorPtr_Type M_solidStressYZ;
573  vectorPtr_Type M_solidStressZZ;
574  vectorPtr_Type M_solidStressVonMises;
575 #endif
576 
577  vectorPtr_Type M_stateVariable;
578 
579  UInt M_nonLinearRichardsonIteration;
580 
581  // Boundary Conditions
582  bcInterfacePtr_Type M_fluidBC;
583  bcInterfacePtr_Type M_solidBC;
584  bcInterfacePtr_Type M_harmonicExtensionBC;
585 
586  // Linear problem
587  bcPtr_Type M_linearFluidBC;
588  bcPtr_Type M_linearSolidBC;
589  vectorPtr_Type M_linearRHS;
590  vectorPtr_Type M_linearSolution;
591 };
592 
593 
594 
595 #ifndef FSI_WITH_EXTERNALPRESSURE
596 
597 //! FSI3DBoundaryStressFunction - The FSI3D coupling function
598 /*!
599  * @author Cristiano Malossi
600  *
601  * This simple class provides the implementation for the BC function used by the FSI3D model
602  * in order to apply an offset to the coupling quantity (e.g.: to remove the wall pressure).
603  */
604 class FSI3DBoundaryStressFunction
605 {
606 public:
607 
608  //! @name Type definitions
609  //@{
610 
611  typedef MultiscaleInterface::function_Type function_Type;
612 
613  //@}
614 
615 
616  //! @name Constructors & Destructor
617  //@{
618 
619  //! Constructor
620  explicit FSI3DBoundaryStressFunction() : M_function(), M_delta() {}
621 
622  //! Destructor
623  virtual ~FSI3DBoundaryStressFunction() {}
624 
625  //@}
626 
627 
628  //! @name Methods
629  //@{
630 
631  //! Evaluate the coupling quantity
632  /*!
633  * @return evaluation of the function
634  */
635  Real function ( const Real& t, const Real& x, const Real& y, const Real& z, const UInt& id )
636  {
637  return M_function ( t, x, y, z, id ) + M_delta;
638  }
639 
640  //@}
641 
642 
643  //! @name Set methods
644  //@{
645 
646  //! Set the offset to be applied to the boundary condition
647  /*!
648  * @param delta offset to be applied to the boundary condition
649  */
650  void setDelta ( const Real& delta )
651  {
652  M_delta = delta;
653  }
654 
655  //! Set the area function
656  /*!
657  * @param function area function
658  */
659  void setFunction ( const function_Type& function )
660  {
661  M_function = function;
662  }
663 
664  //@}
665 
666 private:
667 
668  //! @name Unimplemented Methods
669  //@{
670 
671  FSI3DBoundaryStressFunction ( const FSI3DBoundaryStressFunction& boundaryFunction );
672 
673  FSI3DBoundaryStressFunction& operator= ( const FSI3DBoundaryStressFunction& boundaryFunction );
674 
675  //@}
676 
677  function_Type M_function;
678  Real M_delta;
679 };
680 
681 #endif
682 
683 
684 
685 #ifndef FSI_WITHOUT_VELOCITYPROFILE
686 
687 //! FSI3DBoundaryFlowRateFunction - The FSI3D coupling function
688 /*!
689  * @author Cristiano Malossi
690  * @author Toni Lassila
691  *
692  * This simple class provides the implementation for the BC function used by the FSI3D model
693  * in order to convert the given flow rate to a velocity profile.
694  */
695 class FSI3DBoundaryFlowRateFunction
696 {
697 public:
698 
699  //! @name Type definitions
700  //@{
701 
702  typedef MultiscaleInterface::function_Type function_Type;
703 
704  typedef MultiscaleModelFSI3D::FSI3DBoundaryFlowRate_Type FSI3DBoundaryFlowRate_Type;
705 
706  //@}
707 
708 
709  //! @name Constructors & Destructor
710  //@{
711 
712  //! Constructor
713  explicit FSI3DBoundaryFlowRateFunction() :
714  M_FSI3D (),
715  M_function (),
716  M_fluidFlag (),
717  M_boundaryFlowRateType (),
718  M_n (),
719  M_area (),
720  M_flowRateIsZero ()
721  {}
722 
723  //! Destructor
724  virtual ~FSI3DBoundaryFlowRateFunction()
725  {
726  /* M_FSI3D is deleted outside */
727  }
728 
729  //@}
730 
731 
732  //! @name Methods
733  //@{
734 
735  //! Update function parameters
736  /*!
737  * Instead of evaluating all the parameters at each call, we update them once at each time step.
738  */
739  void updateParameters()
740  {
741  // Updating the area
742  M_area = M_FSI3D->solver()->fluid().area ( M_fluidFlag );
743 
744  // Updating the BC
745  switch ( M_boundaryFlowRateType )
746  {
747  case MultiscaleModelFSI3D::Strong:
748  {
749  // Update the approximate surface normal direction for this b.c.
750  useNormalDirectionFlow ( M_FSI3D->bcHandlerFluid().findBCWithFlag ( M_fluidFlag ) );
751 
752  break;
753  }
754  case MultiscaleModelFSI3D::Semiweak:
755  {
756  // Check if the flow rate is (almost) zero and impose b.c. accordingly:
757  // we use a cutoff to determine when the coupled flow rate is sufficiently small
758  M_flowRateIsZero = ( std::abs ( M_function ( M_FSI3D->data()->dataFluid()->dataTime()->time(), 0.0, 0.0, 0.0, 0 ) ) < 1e-8 );
759 
760  BCFunctionBase base;
761  if ( M_flowRateIsZero )
762  {
763  // Impose essential Dirichlet
764  M_FSI3D->bcHandlerFluid().modifyBC ( M_fluidFlag, Essential );
765 
766  /* In case of essential b.c. we must take care of the Lagrange multiplier, otherwise the global
767  system will be singular. For now we circumvent the problem by setting the corresponding diagonal
768  element to zero, i.e., the Lagrange multiplier is retained but becomes trivial. */
769  }
770  else
771  {
772  // Impose weakly the flow rate
773  M_FSI3D->bcHandlerFluid().modifyBC ( M_fluidFlag, Flux );
774  }
775 
776  break;
777  }
778  case MultiscaleModelFSI3D::Weak:
779 
780  std::cerr << "!!! ERROR: in case Weak option has been selected, this class should not be instantiated at all !!!" << std::endl;
781  break;
782 
783  default:
784 
785  break;
786  }
787  }
788 
789  //! Evaluate the coupling quantity
790  /*!
791  * For now, we impose a flat profile in the normal direction.
792  * TODO: In the future, this method can be extended in order to prescribe some "predefined" velocity profile
793  * such as Poiseuille, Womersley, etc...
794  *
795  * @return evaluation of the function
796  */
797  Real function ( const Real& t, const Real& x, const Real& y, const Real& z, const UInt& id )
798  {
799  /* CAUTION: Here lies a possible bug. The flat profile is assumed to extend to the boundary of the
800  * surface patch, but if the user specific explicitly a no-slip condition on the ring then an error
801  * of order h will be made in the flow rate coupling equations. The proper implementation is to
802  * make no assumptions but to integrate the effective flow profile across the surface patch and use
803  * that value for the scaling. That way it is always mesh-independent. */
804 
805  if ( M_boundaryFlowRateType == MultiscaleModelFSI3D::Semiweak && M_flowRateIsZero )
806  {
807  return 0;
808  }
809 
810  Real flowRate = M_function ( t, x, y, z, id );
811  Real meanVelocity = flowRate / M_area;
812 
813  return meanVelocity * M_n[id];
814  }
815 
816  //@}
817 
818 
819  //! @name Set Methods
820  //@{
821 
822  //! Set the FSI3D model
823  /*!
824  * @param modelFSI3D a pointer to the FSI3D model
825  */
826  void setModel ( MultiscaleModelFSI3D* modelFSI3D )
827  {
828  M_FSI3D = modelFSI3D;
829  }
830 
831  //! Set the fluid flag of the boundary
832  /*!
833  * @param flag flag of the fluid boundary
834  */
835  void setFluidFlag ( const multiscaleID_Type& flag )
836  {
837  M_fluidFlag = flag;
838  }
839 
840  //! Set the outgoing normal of the fluid boundary
841  /*!
842  * @param normal outgoing normal of the fluid boundary
843  */
844  void setNormal ( const std::array< Real, 3 >& normal )
845  {
846  M_n = normal;
847  }
848 
849  //! Set the area function
850  /*!
851  * @param function area function
852  */
853  void setFunction ( const function_Type& function )
854  {
855  M_function = function;
856  }
857 
858  //! Set the boundary flow rate type
859  /*!
860  * @param boundaryFlowRateType boundary flow rate type
861  */
862  void setBoundaryFlowRateType ( const FSI3DBoundaryFlowRate_Type& boundaryFlowRateType )
863  {
864  M_boundaryFlowRateType = boundaryFlowRateType;
865  }
866 
867  //@}
868 
869 
870  //! @name Get methods
871  //@{
872 
873  //! Get the fluid flag of the boundary
874  /*!
875  * @return flag of the fluid boundary
876  */
877  const multiscaleID_Type& fluidFlag() const
878  {
879  return M_fluidFlag;
880  }
881 
882  //! Get the boundary flow rate type
883  /*!
884  * @return boundary flow rate type
885  */
886  const FSI3DBoundaryFlowRate_Type& boundaryFlowRateType() const
887  {
888  return M_boundaryFlowRateType;
889  }
890 
891  //@}
892 
893 
894 private:
895 
896  //! @name Unimplemented Methods
897  //@{
898 
899  FSI3DBoundaryFlowRateFunction ( const FSI3DBoundaryFlowRateFunction& boundaryFunction );
900 
901  FSI3DBoundaryFlowRateFunction& operator= ( const FSI3DBoundaryFlowRateFunction& boundaryFunction );
902 
903  //@}
904 
905  //! @name Private Methods
906  //@{
907 
908  //! Impose a flow in the outgoing normal direction.
909  void useNormalDirectionFlow ( const BCBase& boundaryID )
910  {
911  // Use the PostProcessingBoundary utility class to extract the surface normals
912  PostProcessingBoundary<MultiscaleModelFSI3D::mesh_Type> normalExtraction ( M_FSI3D->solver()->uFESpacePtr()->mesh(),
913  & (M_FSI3D->solver()->uFESpacePtr()->feBd() ),
914  & (M_FSI3D->solver()->uFESpacePtr()->dof() ),
915  M_FSI3D->solver()->uFESpacePtr()->map() );
916 
917  Vector approxNormal = normalExtraction.normal ( boundaryID.flag() );
918 
919  // Take the first surface normal direction
920  M_n[0] = approxNormal[0];
921  M_n[1] = approxNormal[1];
922  M_n[2] = approxNormal[2];
923  }
924 
925  //@}
926 
927  MultiscaleModelFSI3D* M_FSI3D;
928  function_Type M_function;
929  multiscaleID_Type M_fluidFlag;
930  FSI3DBoundaryFlowRate_Type M_boundaryFlowRateType;
931  std::array< Real, 3 > M_n;
932  Real M_area;
933  bool M_flowRateIsZero;
934 };
935 
936 #endif
937 
938 
939 
941 
942 //! FSI3DBoundaryAreaFunction - The FSI3D area function
943 /*!
944  * @author Cristiano Malossi
945  *
946  * This simple class provides the implementation for the BC function used by the FSI3D model
947  * in order to apply the area of the fluid vessel at the boundaries.
948  */
949 class FSI3DBoundaryAreaFunction
950 {
951 public:
952 
953  //! @name Type definitions
954  //@{
955 
956  typedef MultiscaleInterface::function_Type function_Type;
957 
958  //@}
959 
960 
961  //! @name Constructors & Destructor
962  //@{
963 
964  //! Constructor
965  explicit FSI3DBoundaryAreaFunction() :
966  M_FSI3D (),
967  M_fluidFlag (),
968  M_referenceArea (),
969  M_geometricCenter (),
970  M_n (),
971  M_t1 (),
972  M_t2 (),
973  M_function ()
974  {}
975 
976  //! Destructor
977  virtual ~FSI3DBoundaryAreaFunction()
978  {
979  /* M_FSI3D is deleted outside */
980  }
981 
982  //@}
983 
984 
985  //! @name Methods
986  //@{
987 
988  //! Evaluate the displacement of a point
989  /*!
990  * @return displacement of a point
991  */
992  Real function ( const Real& t, const Real& x, const Real& y, const Real& z, const UInt& id )
993  {
994  return displacement ( std::sqrt ( M_function ( t, x, y, z, id ) / M_referenceArea ) - 1, x , y, z, id );
995  }
996 
997  //! Evaluate the displacement of a point when solving the tangent problem
998  /*!
999  * @return displacement of a point
1000  */
1001  Real functionLinear ( const Real& /*t*/, const Real& x, const Real& y, const Real& z, const UInt& id )
1002  {
1003  return displacement ( std::sqrt ( 1. / M_referenceArea ) - 1, x , y, z, id );
1004  }
1005 
1006  //! Setup main quantities
1007  void setup()
1008  {
1009  // Compute reference area
1010  M_referenceArea = M_FSI3D->solver()->fluid().area ( M_fluidFlag );
1011 
1012  // Compute normal
1013  Vector normal = M_FSI3D->solver()->fluid().normal ( M_fluidFlag );
1014 
1015  M_n[0] = normal[0];
1016  M_n[1] = normal[1];
1017  M_n[2] = normal[2];
1018 
1019  // Compute tangent
1020  setupTangent();
1021 
1022  // Compute geometric center
1023  Vector geometricCenter = M_FSI3D->solver()->fluid().geometricCenter ( M_fluidFlag );
1024 
1025  M_geometricCenter[0] = geometricCenter[0];
1026  M_geometricCenter[1] = geometricCenter[1];
1027  M_geometricCenter[2] = geometricCenter[2];
1028 
1029  // ShowMe
1030  showMe();
1031  }
1032 
1033  //! ShowMe
1034  void showMe() const
1035  {
1036  if ( M_FSI3D->communicator()->MyPID() == 0 )
1037  {
1038  std::cout << "Fluid flag = " << M_fluidFlag << std::endl
1039  << "Reference area = " << M_referenceArea << std::endl
1040  << "Geometric center = " << M_geometricCenter[0] << " " << M_geometricCenter[1] << " " << M_geometricCenter[2] << std::endl
1041  << "Normal = " << M_n[0] << " " << M_n[1] << " " << M_n[2] << std::endl
1042  << "Tangent 1 = " << M_t1[0] << " " << M_t1[1] << " " << M_t1[2] << std::endl
1043  << "Tangent 2 = " << M_t2[0] << " " << M_t2[1] << " " << M_t2[2] << std::endl << std::endl;
1044  }
1045  }
1046 
1047  //@}
1048 
1049 
1050  //! @name Set methods
1051  //@{
1052 
1053  //! Set the FSI3D model
1054  /*!
1055  * @param modelFSI3D a pointer to the FSI3D model
1056  */
1057  void setModel ( const MultiscaleModelFSI3D* modelFSI3D )
1058  {
1059  M_FSI3D = modelFSI3D;
1060  }
1061 
1062  //! Set the fluid flag of the boundary
1063  /*!
1064  * @param flag flag of the fluid boundary
1065  */
1066  void setFluidFlag ( const multiscaleID_Type& flag )
1067  {
1068  M_fluidFlag = flag;
1069  }
1070 
1071  //! Set the reference area the fluid boundary
1072  /*!
1073  * @param referenceArea reference area of the fluid boundary
1074  */
1075  void setReferenceArea ( const Real& referenceArea )
1076  {
1077  M_referenceArea = referenceArea;
1078  }
1079 
1080  //! Set the geometric center of the fluid boundary
1081  /*!
1082  * @param geometricCenter the x-y-z coordinate of the geometric center of the fluid boundary
1083  */
1084  void setGeometricCenter ( const std::array< Real, 3 >& geometricCenter )
1085  {
1086  M_geometricCenter = geometricCenter;
1087  }
1088 
1089  //! Set the outgoing normal of the fluid boundary
1090  /*!
1091  * @param normal outgoing normal of the fluid boundary
1092  */
1093  void setNormal ( const std::array< Real, 3 >& normal )
1094  {
1095  M_n = normal;
1096  setupTangent();
1097  }
1098 
1099  //! Set the area function
1100  /*!
1101  * @param function area function
1102  */
1103  void setFunction ( const function_Type& function )
1104  {
1105  M_function = function;
1106  }
1107 
1108  //@}
1109 
1110  //! @name Get methods
1111  //@{
1112 
1113  //! Get the fluid flag of the boundary
1114  /*!
1115  * @return flag of the fluid boundary
1116  */
1117  const multiscaleID_Type& fluidFlag() const
1118  {
1119  return M_fluidFlag;
1120  }
1121 
1122  //@}
1123 
1124 private:
1125 
1126  //! @name Unimplemented Methods
1127  //@{
1128 
1129  FSI3DBoundaryAreaFunction ( const FSI3DBoundaryAreaFunction& boundaryFunction );
1130 
1131  FSI3DBoundaryAreaFunction& operator= ( const FSI3DBoundaryAreaFunction& boundaryFunction );
1132 
1133  //@}
1134 
1135 
1136  //! @name Private Methods
1137  //@{
1138 
1139  //! Setup tangent vectors
1140  void setupTangent()
1141  {
1142  // Normalization
1143  Real module = std::sqrt ( M_n[0] * M_n[0] + M_n[1] * M_n[1] + M_n[2] * M_n[2] );
1144  M_n[0] = M_n[0] / module;
1145  M_n[1] = M_n[1] / module;
1146  M_n[2] = M_n[2] / module;
1147 
1148  // Compute t1
1149  M_t1[0] = M_n[1] * M_n[1] - M_n[0] * M_n[2];
1150  M_t1[1] = M_n[2] * M_n[2] - M_n[0] * M_n[1];
1151  M_t1[2] = M_n[0] * M_n[0] - M_n[1] * M_n[2];
1152 
1153  // Compute t2
1154  M_t2[0] = M_n[1] * M_t1[2] - M_n[2] * M_t1[1];
1155  M_t2[1] = M_n[2] * M_t1[0] - M_n[0] * M_t1[2];
1156  M_t2[2] = M_n[0] * M_t1[1] - M_n[1] * M_t1[0];
1157  }
1158 
1159  //! Evaluate the displacement of a point given the scale factor
1160  /*!
1161  * @param scale factor
1162  * @param x x-coordinate of the point
1163  * @param y y-coordinate of the point
1164  * @param z z-coordinate of the point
1165  * @param id id of the component
1166  * @return displacement of a point
1167  */
1168  Real displacement ( const Real& scaleFactor, const Real& x, const Real& y, const Real& z, const UInt& id )
1169  {
1170  // Compute the RHS
1171  std::array< Real, 3 > rhs;
1172  rhs[0] = 0;
1173  rhs[1] = scaleFactor * ( ( x - M_geometricCenter[0] ) * M_t1[0] + ( y - M_geometricCenter[1] ) * M_t1[1] + ( z - M_geometricCenter[2] ) * M_t1[2] );
1174  rhs[2] = scaleFactor * ( ( x - M_geometricCenter[0] ) * M_t2[0] + ( y - M_geometricCenter[1] ) * M_t2[1] + ( z - M_geometricCenter[2] ) * M_t2[2] );
1175 
1176  // Compute the displacement
1177  Real determinant = M_n[0] * ( M_t1[1] * M_t2[2] - M_t1[2] * M_t2[1] )
1178  + M_n[1] * ( M_t1[2] * M_t2[0] - M_t1[0] * M_t2[2] )
1179  + M_n[2] * ( M_t1[0] * M_t2[1] - M_t1[1] * M_t2[0] );
1180  switch ( id )
1181  {
1182  case 0:
1183  return - ( rhs[0] * ( M_t1[2] * M_t2[1] - M_t1[1] * M_t2[2] )
1184  + rhs[1] * ( M_n[1] * M_t2[2] - M_n[2] * M_t2[1] )
1185  + rhs[2] * ( M_n[2] * M_t1[1] - M_n[1] * M_t1[2] ) ) / determinant;
1186 
1187  case 1:
1188  return ( rhs[0] * ( M_t1[2] * M_t2[0] - M_t1[0] * M_t2[2] )
1189  + rhs[1] * ( M_n[0] * M_t2[2] - M_n[2] * M_t2[0] )
1190  + rhs[2] * ( M_n[2] * M_t1[0] - M_n[0] * M_t1[2] ) ) / determinant;
1191 
1192  case 2:
1193  return - ( rhs[0] * ( M_t1[1] * M_t2[0] - M_t1[0] * M_t2[1] )
1194  + rhs[1] * ( M_n[0] * M_t2[1] - M_n[1] * M_t2[0] )
1195  + rhs[2] * ( M_n[1] * M_t1[0] - M_n[0] * M_t1[1] ) ) / determinant;
1196 
1197  default:
1198 
1199  return 0.;
1200  }
1201  }
1202 
1203  //@}
1204 
1205 
1206  const MultiscaleModelFSI3D* M_FSI3D; // A pointer to the model class
1207  multiscaleID_Type M_fluidFlag; // Boundary flag
1208  Real M_referenceArea; // Reference area
1209  std::array< Real, 3 > M_geometricCenter; // Geometric center
1210  std::array< Real, 3 > M_n; // Normal direction
1211  std::array< Real, 3 > M_t1; // Tangential direction 1
1212  std::array< Real, 3 > M_t2; // Tangential direction 2
1213  function_Type M_function; // Function scale factor
1214 };
1215 
1216 #endif
1217 
1218 
1219 
1220 //! Factory create function
1221 inline multiscaleModel_Type* createMultiscaleModelFSI3D()
1222 {
1223  return new MultiscaleModelFSI3D();
1224 }
1225 
1226 } // Namespace multiscale
1227 } // Namespace LifeV
1228 
1229 #endif /* MultiscaleModelFSI3D_H */
#define FSI_WITH_BOUNDARYAREA
#define FSI_WITH_STRESSOUTPUT