LifeV
lifev/electrophysiology/testsuite/test_fibers/main.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  @file
29  @brief Generation muscular fibers and sheets
30 
31  @author Simone Rossi <simone.rossi@epfl.ch>
32  @maintainer Simone Palamara <palamara.simone@gmail.com>
33  @date 31-01-2014
34 
35 
36  Generation of the muscular fibers and sheets on a generic
37  geometry representing the left or right ventricle, generated
38  according to geometrical rules based on anatomical knowledge.
39  For more details about the method see [S.Rossi et al,European Journal of
40  Mechanics A/Solids (2013), http://dx.doi.org/10.1016/j.euromechsol.2013.10.009]
41 
42  */
43 
44 //#include <Epetra_ConfigDefs.h>
45 
46 // ------------------------------------------------------------------------------
47 // Include MPI for parallel simulations
48 // ------------------------------------------------------------------------------
49 #ifdef EPETRA_MPI
50 #include <mpi.h>
51 #include <Epetra_MpiComm.h>
52 #else
53 #include <Epetra_SerialComm.h>
54 #endif
55 
56 // ------------------------------------------------------------------------------
57 // To set up the linear solver we need a Teuchos parameter list
58 // ------------------------------------------------------------------------------
59 #include <Teuchos_ParameterList.hpp>
60 
61 // ------------------------------------------------------------------------------
62 // Needed to generate the ouput folder
63 // ------------------------------------------------------------------------------
64 #include <sys/stat.h>
65 
66 // ------------------------------------------------------------------------------
67 // BCInterface is the interface that between the datafile and the
68 // boundary conditions. We will create a ummy physical solver in order to use it.
69 // ------------------------------------------------------------------------------
70 #include <lifev/bc_interface/3D/bc/BCInterface3D.hpp>
71 #include <lifev/bc_interface/core/solver/EmptyPhysicalSolver.hpp>
72 
73 // ------------------------------------------------------------------------------
74 // Usefule utility to load the mesh in one line.
75 // Not working with partitioned meshes
76 // ------------------------------------------------------------------------------
77 #include <lifev/core/mesh/MeshLoadingUtility.hpp>
78 
79 // ------------------------------------------------------------------------------
80 // The sheets are defined as the gradient of a scalar potential, we therefore
81 // need to be able to compute the gradient in the nodes.
82 // ------------------------------------------------------------------------------
83 #include <lifev/core/fem/GradientRecovery.hpp>
84 #include <lifev/core/fem/BCManage.hpp>
85 
86 // ------------------------------------------------------------------------------
87 // To solve the laplacian, use the linear solver (AztecOO or Belos) with ML
88 // ------------------------------------------------------------------------------
89 #include <lifev/core/algorithm/LinearSolver.hpp>
90 #include <lifev/core/algorithm/PreconditionerML.hpp>
91 
92 // ------------------------------------------------------------------------------
93 // The laplacian is assembled using Expression Template Assembly
94 // ------------------------------------------------------------------------------
95 #include <lifev/eta/fem/ETFESpace.hpp>
96 #include <lifev/eta/expression/Integrate.hpp>
97 
98 // ------------------------------------------------------------------------------
99 // Cannot save without HDF5 !!! Please make sure you have it
100 // ------------------------------------------------------------------------------
101 #ifdef HAVE_HDF5
102 #include <lifev/core/filter/ExporterHDF5.hpp>
103 #endif
104 
105 // ------------------------------------------------------------------------------
106 // In this file there are a bunch of useful functions.
107 // Here we use it only to normalize a vector.
108 // ------------------------------------------------------------------------------
109 #include <lifev/electrophysiology/util/HeartUtility.hpp>
110 
111 // ---------------------------------------------------------------
112 // As usual, we work in the LifeV namespace. Moreover,
113 // to make the code more readable, we also make typedefs for the mesh type,
114 // matrix type, vector type, boundary condition
115 // ---------------------------------------------------------------
116 
117 using namespace LifeV;
118 
119 // ---------------------------------------------------------------
120 // We typedef some common type we will frequently
121 // ---------------------------------------------------------------
122 
125 
128 
131 
132 
133 
134 typedef FESpace< mesh_Type, MapEpetra > fespace_Type;
136 
137 
138 // ---------------------------------------------------------------
139 // In order to keep the code more readble I created a couple
140 // of auxiliary functions.
141 // In this test we only have the datafile that will be
142 // a GetPot object. To set up the linear solver we need a Teuchos::ParameterList
143 // that typically reads xml files. Therefore,
144 // the createListFromGetPot function create the requested Teuchos list
145 // from the datafile we have.
146 // In the end we will export three vector field in three different
147 // files. To avoid code repetition, I created this function
148 // that exports the requested vecotr fields.
149 // ---------------------------------------------------------------
150 void createListFromGetPot (Teuchos::ParameterList& solverList, const GetPot& dataFile);
151 void exportVectorField (std::shared_ptr<Epetra_Comm> comm,
152  meshPtr_Type mesh,
153  fespacePtr_Type fespace,
154  vectorPtr_Type vector,
155  std::string postDir,
156  std::string outputName,
157  std::string hdf5name);
158 
159 
160 // ------------------------------------------------------------------------------
161 // Dummy class for to be used with the BCInterfac3D.
162 // We could have used the ElectroETAMonodomainSolver as physical solver,
163 // but in this way, this test is totally independent.
164 // ------------------------------------------------------------------------------
165 
166 Real fzero (const Real& /*t*/, const Real& /*x*/, const Real& /*y*/, const Real& /*z*/, const ID& /*i*/)
167 {
168  return 0.0;
169 }
170 // Starting ...
171 int main ( int argc, char** argv )
172 {
173 
174  // ---------------------------------------------------------------
175  // In parallel? Yes, we dare!!!
176  // ---------------------------------------------------------------
177 
178 #ifdef HAVE_MPI
179  MPI_Init (&argc, &argv);
180  std::shared_ptr<Epetra_Comm> Comm (new Epetra_MpiComm (MPI_COMM_WORLD) );
181 #else
182  std::shared_ptr<Epetra_Comm> Comm (new Epetra_SerialComm);
183 #endif
184 
185  typedef BCHandler bc_Type;
186  typedef std::shared_ptr< bc_Type > bcPtr_Type;
187 
188  typedef EmptyPhysicalSolver<VectorEpetra> physicalSolver_Type;
189  typedef BCInterface3D< bc_Type, physicalSolver_Type > bcInterface_Type;
190 
191  typedef std::shared_ptr< bcInterface_Type > bcInterfacePtr_Type;
192  typedef MeshUtility::MeshTransformer<mesh_Type> meshTransformer_Type;
193 
194  //*************************************************************//
195  // We create, as usual, the output folder where
196  // we are going to save the solutions of
197  // the simulation.
198  // It requires to append "-o OutputFolderName" flag
199  // when you laucnh the executable, e.g.
200  // mpirun -n 2 Electrophysiology_thisTestName -o SolutionFolder
201  // By default the name of the folder will be "Output"
202  //*************************************************************//
203  GetPot commandLine ( argc, argv );
204  std::string problemFolder = commandLine.follow ( "Output", 2, "-o", "--output" );
205  // Create the problem folder
206  if ( problemFolder.compare ("./") )
207  {
208  problemFolder += "/";
209 
210  if ( Comm->MyPID() == 0 )
211  {
212  mkdir ( problemFolder.c_str(), 0777 );
213  }
214  }
215 
216  //*************************************************************//
217  // We create the datafile. The datafile is passed through the flag
218  // "-f datafileName" when launching the executable.
219  // By default the name of the datafiler is "data".
220  // Usually you should not bother about this flag, as the
221  // datafile has already the default filename.
222  // Remember about this, though, if you are going to change the filename
223  // or if you want to add another datafile and run your simulation
224  // with that one.
225  //*************************************************************//
226  GetPot command_line (argc, argv);
227  const std::string data_file_name = command_line.follow ("data", 2, "-f", "--file");
228  GetPot dataFile (data_file_name);
229 
230  //*************************************************************//
231  // We specified in the datafile the name and the path of the
232  // mesh we are going to create the fibers on.
233  //*************************************************************//
234 
235  std::string meshName = dataFile ( "problem/space_discretization/mesh_file", "" );
236  std::string meshPath = dataFile ( "problem/space_discretization/mesh_dir", "./" );
237 
238  //*************************************************************//
239  // Here we create a pointer to the mesh and then we load it.
240  // Notice how cool is to load the mesh in just one line!!!
241  // Note that the pointer will point to the partitioned mesh
242  // If you would like to keep informations about the full mesh
243  // create another meshPtr_Type and call for example
244  // MeshUtility::loadMesh (meshPart, meshFull, meshName, meshPath);
245  //*************************************************************//
246  meshPtr_Type meshPart (new mesh_Type ( Comm ) );
247  MeshUtility::loadMesh (meshPart, meshName, meshPath);
248 
249  //*************************************************************//
250  // Here we define the finite element spaces. In particular
251  // - uSpace is the finite element space for Expression Template Assembly
252  // - uFESpace is the usual finite element space required for
253  // boundary conditions and for the exporter
254  // - vectorESpace is the space for the vectorial fields (sheets and fibers)
255  // we will define. Even if we don't need to do finite element
256  // operation on them, this fespace will be required to export
257  // the solution.
258  //*************************************************************//
259 
260  std::shared_ptr<ETFESpace< mesh_Type, MapEpetra, 3, 1 > > uSpace
261  ( new ETFESpace< mesh_Type, MapEpetra, 3, 1 > (meshPart, &feTetraP1, Comm) );
262 
263  fespacePtr_Type uFESpace ( new FESpace< mesh_Type, MapEpetra > (meshPart, "P1", 1, Comm) );
264 
265  fespacePtr_Type vectorFESpace ( new FESpace< mesh_Type, MapEpetra > (meshPart, "P1", 3, Comm) );
266 
267  //*************************************************************//
268  // We asseble the stiffness matrix using expression template.
269  // For more details, look at the ETA tutorial.
270  //*************************************************************//
271 
272  std::shared_ptr<matrix_Type> systemMatrix (new matrix_Type ( uSpace->map() ) );
273 
274  *systemMatrix *= 0.0;
275  {
276  using namespace ExpressionAssembly;
277 
278 
279  integrate ( elements (uSpace->mesh() ),
280  quadRuleTetra4pt,
281  uSpace,
282  uSpace,
283  dot ( grad (phi_i) , grad (phi_j) )
284  )
285  >> systemMatrix;
286  }
287 
288  systemMatrix->globalAssemble();
289 
290  //*************************************************************//
291  // Setting up the boundary conditions is always an issue.
292  // Fortunately Cristiano Malossi implemented a way to read
293  // the boundary condition from the datafile. This is achieved
294  // by using the BCInterface class.
295  // The BC is template on a physicalSolver_Type.
296  // We have not created a specific BCInterface for the
297  // monodomain model (as usually one imposes homogeneous Neumann
298  // conditions). Therefore here I created a default physical solver
299  // in the bc interface module which will be used to solve this
300  // simple laplacian problem. Check the typedef.
301  // Then to set up the boundary conditions, we need to
302  // 1 - create the BCHandler
303  // 2 - fill the handler with the boundary conditions specified
304  // in the datafile
305  // 3 - update the boundary condtions
306  // For more information on how to use the BCInterface refer
307  // to that module.
308  //*************************************************************//
309  bcInterfacePtr_Type BC ( new bcInterface_Type() );
310  BC->createHandler();
311  BC->fillHandler ( data_file_name, "problem" );
312  BC->handler()->bcUpdate ( *uFESpace->mesh(), uFESpace->feBd(), uFESpace->dof() );
313 
314  //**********************************************************//
315  // We are going to solve the laplace equation with an
316  // iterative solver. We precondition the system with Ifpack.
317  // The parameters of the preconditioner are in the datafile.
318  // If you want to use ML, change the precType to
319  // LifeV::PreconditionerML
320  //**********************************************************//
321 
322  typedef LifeV::Preconditioner basePrec_Type;
323  typedef std::shared_ptr<basePrec_Type> basePrecPtr_Type;
324  typedef LifeV::PreconditionerIfpack prec_Type;
325  typedef std::shared_ptr<prec_Type> precPtr_Type;
326 
327  prec_Type* precRawPtr;
328  basePrecPtr_Type precPtr;
329  precRawPtr = new prec_Type;
330  precRawPtr->setDataFromGetPot ( dataFile, "prec" );
331  precPtr.reset ( precRawPtr );
332 
333  //**********************************************************//
334  // As detailed above to setup the linear system we need a
335  // Teuchos::ParmeterList list. Usually this is read from
336  // an xml file. Since the xml is not available in this test
337  // the createListFromGetPot reads the required parameters
338  // from the datafile and put the in the Teuchos list.
339  // You can see the actual implementation at the end of the
340  // test.
341  //**********************************************************//
342  Teuchos::ParameterList solverList;
343  createListFromGetPot (solverList, dataFile);
344 
345  LinearSolver linearSolver;
346  linearSolver.setCommunicator (Comm);
347  linearSolver.setParameters ( solverList );
348  linearSolver.setPreconditioner ( precPtr );
349 
350  //*************************************************************//
351  // We are going to solve the laplace equation. The right hand
352  // is zero!
353  //*************************************************************//
354  vectorPtr_Type rhs (new vector_Type ( uSpace -> map() ) );
355  *rhs *= 0.0;
356  rhs -> globalAssemble();
357 
358  //*************************************************************//
359  // We impose the boundary conditions, on our system.
360  //*************************************************************//
361 
362  bcManage ( *systemMatrix, *rhs, *uSpace->mesh(), uSpace->dof(), *BC -> handler(), uFESpace->feBd(), 1.0, 0.0 );
363 
364  //*************************************************************//
365  // We declare the vector where we want to put the solution.
366  // Here we want to solve the linear system Ax=b;
367  // we tell the linear solver which A to use (systemMatrix)
368  // and which right hand side to use (rhs).
369  // Then we solve telling the solver to put the solution in the
370  // vector x (solution).
371  //*************************************************************//
372  vectorPtr_Type solution ( new vector_Type ( uFESpace -> map() ) );
373 
374 
375  linearSolver.setOperator (systemMatrix);
376  linearSolver.setRightHandSide (rhs);
377  linearSolver.solve (solution);
378 
379  //*************************************************************//
380  // We save the potential field just computed on a file
381  // using HDF5.
382  //*************************************************************//
383  ExporterHDF5< mesh_Type > exporter;
384  exporter.setMeshProcId ( meshPart, Comm -> MyPID() );
385  exporter.setPostDir (problemFolder);
386  exporter.setPrefix ("Potential");
387  exporter.addVariable ( ExporterData<mesh_Type>::ScalarField, "potential", uFESpace, solution, UInt (0) );
388  exporter.postProcess (0);
389  exporter.closeFile();
390 
391  //*************************************************************//
392  // The sheets are defined as the gradient of the scalar
393  // potential just computed. We create three vector where we
394  // store the components of the sheets direction.
395  // We computed the gradient using the superconvergent
396  // gradient recovery patch of ZZ (check that file for more infos)
397  //*************************************************************//
398  vectorPtr_Type sx (new vector_Type ( uSpace -> map() ) );
399  vectorPtr_Type sy (new vector_Type ( uSpace -> map() ) );
400  vectorPtr_Type sz (new vector_Type ( uSpace -> map() ) );
401 
402  *sx = GradientRecovery::ZZGradient (uSpace, *solution, 0);
403  *sy = GradientRecovery::ZZGradient (uSpace, *solution, 1);
404  *sz = GradientRecovery::ZZGradient (uSpace, *solution, 2);
405 
406  //*************************************************************//
407  // We declare the rule-based sheets, fibers, and the projection
408  // vectors. All these vectors have three components. Therefore
409  // we use the vectorFESpace to create them.
410  //*************************************************************//
411 
412  vectorPtr_Type rbSheet ( new vector_Type ( vectorFESpace -> map() ) );
413  vectorPtr_Type rbFiber ( new vector_Type ( vectorFESpace -> map() ) );
414  vectorPtr_Type projection ( new vector_Type ( vectorFESpace -> map() ) );
415 
416  //*************************************************************//
417  // From now on all the operations (except for the export)
418  // will not require communication between the processors.
419  // Using more processor will surely speed up the computations.
420  // Therefore the first step is to understand what is the length
421  // of each of the above vectors on each processor.
422  // Since we used the same map to declare the vectors, they
423  // are distributed on the processors in the same way.
424  // We check only the lenght one of them calling the
425  // MyLength() method (this method is defined in Trilinos).
426  // The length n is an integer, and since we have 3 components
427  // each component will hav n/3 entries.
428  //*************************************************************//
429 
430 
431  int n = (*rbSheet).epetraVector().MyLength();
432  int d = n / 3;
433 
434  //*************************************************************//
435  // We loop over the number of entries for each component and
436  // we fill the rule-based sheet vector field.
437  // To access the components of the vector we use the global IDs.
438  // Therefore, we first compute the GIDs and the we assign to
439  // rbSheet the components of the sheets sx, sy and sz.
440  // After that we normalize this vector field.
441  // In this way we have computed the sheet field.
442  //*************************************************************//
443  for ( int l (0); l < d; l++)
444  {
445  int i = (*rbSheet).blockMap().GID (l);
446  int j = (*rbSheet).blockMap().GID (l + d);
447  int k = (*rbSheet).blockMap().GID (l + 2 * d);
448 
449  (*rbSheet) [i] = (*sx) [i];
450  (*rbSheet) [j] = (*sy) [i];
451  (*rbSheet) [k] = (*sz) [i];
452  }
453 
454  ElectrophysiologyUtility::normalize (*rbSheet);
455 
456  //*************************************************************//
457  // The algorithm requires to give as input the centerline of
458  // the left ventricle. This can be read from datafile
459  // so that if you want to change the mesh/geoemtry you don't have
460  // to recompile
461  //*************************************************************//
462  Real cx = dataFile ("problem/centerline_x", 0.0);
463  Real cy = dataFile ("problem/centerline_y", 0.0);
464  Real cz = dataFile ("problem/centerline_z", 1.0);
465 
466 
467  //*************************************************************//
468  // What I call the projection field is the projection of the
469  // centerline to the plane orthogonal to the sheets.
470  // Given the vector of the centerline c and the sheets s.
471  // then this projection vector p is given by
472  // p = c - (c,s) s,
473  // where (c,s) is the scalar product of c with s.
474  // After we normalize the projection vector.
475  //*************************************************************//
476 
477  for ( int l (0); l < d; l++)
478  {
479  int i = (*rbSheet).blockMap().GID (l);
480  int j = (*rbSheet).blockMap().GID (l + d);
481  int k = (*rbSheet).blockMap().GID (l + 2 * d);
482 
483  Real cdot = cx * (*rbSheet) [i] + cy * (*rbSheet) [j] + cz * (*rbSheet) [k];
484 
485  (*projection) [i] = cx - cdot * (*rbSheet) [i];
486  (*projection) [j] = cy - cdot * (*rbSheet) [j];
487  (*projection) [k] = cz - cdot * (*rbSheet) [k];
488  }
489 
490  ElectrophysiologyUtility::normalize (*projection);
491 
492  //*************************************************************//
493  // In each point we have defined to orthogonal direction s and p
494  // We finish computing the local coordinate system computing the
495  // third orthonormal component. This is a prototype of the fiber
496  // field. I usually call it flat fiber field in the sense that
497  // is a vector field which has zero component in the direction
498  // of the left ventricle centerline and it can be rotated in
499  // order to define the seeked fiber field.
500  // This flat fiber vector f is the vector product of s and p:
501  // f = s x p;
502  // Although f should already be normalized, since the vector
503  // product of two unit vector is a unit vector, we call again
504  // the normalize function.
505  //*************************************************************//
506 
507  for ( int l (0); l < d; l++)
508  {
509  int i = (*rbSheet).blockMap().GID (l);
510  int j = (*rbSheet).blockMap().GID (l + d);
511  int k = (*rbSheet).blockMap().GID (l + 2 * d);
512 
513  (*rbFiber) [i] = (*rbSheet) [j] * (*projection) [k] - (*rbSheet) [k] * (*projection) [j];
514  (*rbFiber) [j] = (*rbSheet) [k] * (*projection) [i] - (*rbSheet) [i] * (*projection) [k];
515  (*rbFiber) [k] = (*rbSheet) [i] * (*projection) [j] - (*rbSheet) [j] * (*projection) [i];
516  }
517 
518  ElectrophysiologyUtility::normalize (*rbFiber);
519 
520  //*************************************************************//
521  // The last step is to rotate the flat fiber field just computed
522  // We rotate the fibers with respect to the sheet field in order
523  // to keep the orthogonal.
524  // We make use of Rodrigues formula (you can check wikipedia :) )
525  // The angle of rotation changes through the wall thickness.
526  // The hypothesis is that the angle of rotation can be written
527  // as a function of the scalar potential we computed at the
528  // beginning.
529  // We first read from the data file the angle of rotation we
530  // want to impose on the endocardium and on the epicardium.
531  //*************************************************************//
532  Real epi_angle = dataFile ("problem/epi_angle", -60.0);
533  Real endo_angle = dataFile ("problem/endo_angle", 60.0);
534 
535  for ( int l (0); l < d; l++)
536  {
537  int i = (*rbSheet).blockMap().GID (l);
538  int j = (*rbSheet).blockMap().GID (l + d);
539  int k = (*rbSheet).blockMap().GID (l + 2 * d);
540 
541  //*************************************************************//
542  // We define a linear relation between the scalar potential u
543  // (the vector solution) and the angle teta, such that
544  // teta = m * u + q;
545  // We need to compute m and q!
546  // First: transform the angles in radiants.
547  // Second: define m as the difference betwee the epi and the endo
548  // angles.
549  // Third: define q as the endo angle.
550  // Fourth: compute m * u + q
551  //*************************************************************//
552  Real p = 3.14159265358979;
553  Real teta1 = p * epi_angle / 180;
554  Real teta2 = p * endo_angle / 180;
555  Real m = (teta1 - teta2 );
556  Real q = teta2;
557  Real teta;
558 
559  teta = m * (*solution) [i] + q;
560 
561  //*************************************************************//
562  // For easiness of implementation and to be more readable
563  // we define the local components of the sheets and of the fibers.
564  // Note that the component of the fibers are the one of the
565  // flat fiber field.
566  //*************************************************************//
567 
568  Real s01 = (*rbSheet) [i];
569  Real s02 = (*rbSheet) [j];
570  Real s03 = (*rbSheet) [k];
571  Real f01 = (*rbFiber) [i];
572  Real f02 = (*rbFiber) [j];
573  Real f03 = (*rbFiber) [k];
574 
575  //*************************************************************//
576  // The fiber field F is a rotation of the flat fiber field f
577  // F = R f
578  // where R is the rotation matrix.
579  // To compute R we need the sin(teta) and
580  // the sin(teta)^2 and the cross-product matrix W (check
581  // rodrigues formula on wikipedia :) )
582  //*************************************************************//
583  Real sa = std::sin (teta);
584  Real sa2 = 2.0 * std::sin (0.5 * teta) * std::sin (0.5 * teta);
585 
586  Real W11 = 0.0;
587  Real W12 = -s03;
588  Real W13 = s02;
589  Real W21 = s03;
590  Real W22 = 0.0;
591  Real W23 = -s01;
592  Real W31 = -s02;
593  Real W32 = s01;
594  Real W33 = 0.0;
595  //
596  Real R11 = 1.0 + sa * W11 + sa2 * ( s01 * s01 - 1.0 );
597  Real R12 = 0.0 + sa * W12 + sa2 * ( s01 * s02 );
598  Real R13 = 0.0 + sa * W13 + sa2 * ( s01 * s03 );
599  Real R21 = 0.0 + sa * W21 + sa2 * ( s02 * s01 );
600  Real R22 = 1.0 + sa * W22 + sa2 * ( s02 * s02 - 1.0 );
601  Real R23 = 0.0 + sa * W23 + sa2 * ( s02 * s03 );
602  Real R31 = 0.0 + sa * W31 + sa2 * ( s03 * s01 );
603  Real R32 = 0.0 + sa * W32 + sa2 * ( s03 * s02 );
604  Real R33 = 1.0 + sa * W33 + sa2 * ( s03 * s03 - 1.0 );
605 
606  //*************************************************************//
607  // Finally we perform the rotation of the flat fiber field
608  //*************************************************************//
609 
610  (*rbFiber) [i] = R11 * f01 + R12 * f02 + R13 * f03;
611  (*rbFiber) [j] = R21 * f01 + R22 * f02 + R23 * f03;
612  (*rbFiber) [k] = R31 * f01 + R32 * f02 + R33 * f03;
613  }
614 
615 
616  //*************************************************************//
617  // Now that we have computed all the desired vector fields
618  // we export them using HDF5 format.
619  // From datafile we can choose the name of the files of the
620  // fiber and sheet vectors.
621  // Also the field are saved on the h5 file with a identification
622  // name (that is the one you can select on paraview). I called
623  // this fiberHDF5Name and sheetHDF5Name. This name is important
624  // to know if we want to import the computed fields in other
625  // simulations
626  //*************************************************************//
627  std::string outputFiberFileName = dataFile ("problem/output_fiber_filename", "FiberDirection");
628  std::string fiberHDF5Name = dataFile ("problem/hdf5_fiber_name", "fibers");
629 
630  std::string outputSheetsFileName = dataFile ("problem/output_sheets_filename", "SheetsDirection");
631  std::string sheetsHDF5Name = dataFile ("problem/hdf5_sheets_name", "sheets");
632 
633  exportVectorField (Comm, meshPart, vectorFESpace, rbFiber, problemFolder, outputFiberFileName, fiberHDF5Name );
634  exportVectorField (Comm, meshPart, vectorFESpace, rbSheet, problemFolder, outputSheetsFileName, sheetsHDF5Name );
635  exportVectorField (Comm, meshPart, vectorFESpace, projection, problemFolder, "Projection", "projection" );
636 
637 
638  //*************************************************************//
639  // We test if the norm of the fuber field and the norm of the
640  // sheet field are the same
641  //*************************************************************//
642 
643  Real normS = rbSheet-> norm2();
644  Real normF = rbFiber-> norm2();
645 
646 #ifdef HAVE_MPI
647  MPI_Finalize();
648 #endif
649 
650  Real err = std::abs (normF - normS) / std::abs (normS);
651  std::cout << std::setprecision (20) << "\nError: " << err << "\nFiber Norm: " << normF << "\n";
652  std::cout << std::setprecision (20) << "Sheet Norm: " << normS << "\n";
653  if ( err > 1e-13 )
654  {
655  return EXIT_FAILURE; // Norm of solution did not match
656  }
657  else
658  {
659  return EXIT_SUCCESS;
660  }
661 }
662 
663 //Implementation of the predeclared functions:
664 //
665 //Read the parameters from a datafile and
666 // put them in a Teuchos:ParameterList
667 void createListFromGetPot (Teuchos::ParameterList& solverList, const GetPot& dataFile)
668 {
669  std::string solverName = dataFile ( "problem/solver/solver_name", "AztecOO");
670  std::string solver = dataFile ( "problem/solver/solver", "gmres");
671  std::string conv = dataFile ( "problem/solver/conv", "rhs");
672  std::string scaling = dataFile ( "problem/solver/scaling", "none");
673  std::string output = dataFile ( "problem/solver/output", "all");
674  Int maxIter = dataFile ( "problem/solver/max_iter", 200);
675  Int maxIterForReuse = dataFile ( "problem/solver/max_iter_reuse", 250);
676  Int kspace = dataFile ( "problem/solver/kspace", 100);
677  Int orthog = dataFile ( "problem/solver/orthog", 0);
678  Int auxvec = dataFile ( "problem/solver/aux_vec", 0);
679  double tol = dataFile ( "problem/solver/tol", 1e-10);
680  bool reusePreconditioner = dataFile ( "problem/solver/reuse", true);
681  bool quitOnFailure = dataFile ( "problem/solver/quit", false);
682  bool silent = dataFile ( "problem/solver/silent", false);
683 
684  solverList.set ("Solver Type", solverName);
685  solverList.set ("Maximum Iterations", maxIter);
686  solverList.set ("Max Iterations For Reuse", maxIterForReuse);
687  solverList.set ("Reuse Preconditioner", reusePreconditioner);
688  solverList.set ("Quit On Failure", quitOnFailure);
689  solverList.set ("Silent", silent);
690  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("solver", solver);
691  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("conv", conv);
692  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("scaling", scaling);
693  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("output", output);
694  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("tol", tol);
695  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("max_iter", maxIter);
696  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("kspace", kspace);
697  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("orthog", orthog);
698  solverList.sublist ("Solver: Operator List").sublist ("Trilinos: AztecOO List").set ("aux_vec", auxvec);;
699 }
700 
701 //Export vector to file using HDF5 exporter
702 void exportVectorField (std::shared_ptr<Epetra_Comm> comm,
703  meshPtr_Type mesh,
704  fespacePtr_Type fespace,
705  vectorPtr_Type vector,
706  std::string postDir,
707  std::string outputName,
708  std::string hdf5name)
709 {
710  ExporterHDF5< mesh_Type > exporter;
711  exporter.setMeshProcId ( mesh, comm -> MyPID() );
712  exporter.setPostDir (postDir);
713  exporter.setPrefix (outputName);
714  exporter.addVariable ( ExporterData<mesh_Type>::VectorField, hdf5name, fespace, vector, UInt (0) );
715  exporter.postProcess (0);
716  exporter.closeFile();
717 }
VectorEpetra - The Epetra Vector format Wrapper.
int main(int argc, char **argv)
Real fzero(const Real &, const Real &, const Real &, const Real &, const ID &)
MatrixEpetra< Real > matrix_Type
void createListFromGetPot(Teuchos::ParameterList &solverList, const GetPot &dataFile)
void importFromHDF5(std::string const &fileName, std::string const &matrixName="matrix")
Read a matrix from a HDF5 (.h5) file.
std::shared_ptr< mesh_Type > meshPtr_Type
std::shared_ptr< fespace_Type > fespacePtr_Type
Epetra_Import const & importer()
Getter for the Epetra_Import.
Definition: MapEpetra.cpp:394
FESpace< mesh_Type, MapEpetra > fespace_Type
uint32_type ID
IDs.
Definition: LifeV.hpp:194
double Real
Generic real data.
Definition: LifeV.hpp:175
std::shared_ptr< matrix_Type > matrixPtr_Type
RegionMesh< LinearTetra > mesh_Type
void exportVectorField(std::shared_ptr< Epetra_Comm > comm, meshPtr_Type mesh, fespacePtr_Type fespace, vectorPtr_Type vector, std::string postDir, std::string outputName, std::string hdf5name)
std::shared_ptr< vector_Type > vectorPtr_Type