LifeV
LevelSetSolver.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 constaining a solver for the level set equation
30 
31  @author Samuel Quinodoz <samuel.quinodoz@epfl.ch>
32  @date 05-11-2010
33 
34  @contributor Samuel Quinodoz <samuel.quinodoz@epfl.ch>
35  @mantainer Samuel Quinodoz <samuel.quinodoz@epfl.ch>
36 
37  A more detailed description of the file (if necessary)
38  */
39 
40 #ifndef LEVELSETSOLVER_H
41 #define LEVELSETSOLVER_H 1
42 
43 
44 #include <Epetra_ConfigDefs.h>
45 #ifdef EPETRA_MPI
46 #include <mpi.h>
47 #include <Epetra_MpiComm.h>
48 #else
49 #include <Epetra_SerialComm.h>
50 #endif
51 
52 
53 
54 #include <lifev/core/algorithm/SolverAztecOO.hpp>
55 
56 #include <lifev/core/LifeV.hpp>
57 
58 #include <lifev/core/fem/TimeAdvanceBDF.hpp>
59 
60 #include <lifev/core/solver/ADRAssembler.hpp>
61 #include <lifev/core/solver/ADRAssemblerIP.hpp>
62 
63 #include <lifev/level_set/solver/LevelSetData.hpp>
64 
65 #include <vector>
66 #include <limits>
67 
68 #include <boost/shared_ptr.hpp>
69 
70 namespace LifeV
71 {
72 
73 // LevelSetSolver - This class contains a solver for the level set problem usually created when dealing with free surface problems.
74 /*!
75 
76  <b> Scope </b>
77 
78  For solving free surface problems (free surface flows for example), there exists many methods to
79  track or capture the moving interface. The level set method, popularized by Osher and Sethian, is
80  one of them.
81 
82  One has to deal with a scalar function \f$ \phi \f$ such that the interface is described by the
83  zero level set of \f$ \phi \f$, i.e. the interface is \f$ \{\mathbf{x} | \phi(\mathbf{x})=0 \} \f$.
84 
85  Two key elements are then needed to make the interface evolve. The first one is the PDE for \f$ \phi \f$:
86 
87  \f[ \frac{\partial \phi}{\partial t} + \beta \cdot \nabla \phi = 0 \f]
88 
89  The second one is the reinitialization, essential to keep the distance property of $\f \phi \f$ and
90  so the accuracy on the zero level set location.
91 
92  The scope of this class is to provide both the time and space discretization of the level set PDE
93  (and the stabilization needed by this pure transport equation), as well as some tools inherants to the
94  level set method, including reinitialization procedures.
95 
96  <b> PDE discretization </b>
97 
98  For the time discretization, a BDF scheme is used. Space discretization
99  is handled in the ADR framework (see ADRAssembler) with finite elements.
100  As the standard approximation leads to instabilities, this solver gives
101  the possibility to use stabilized schemes.
102 
103  Right now, only IP stabilization is enabled (see ADRAssemblerIP).
104 
105  The LevelSetData structure provides the convenient way to set all the
106  parameters for both discretizations.
107 
108  <b> Reinitialization </b>
109 
110  In the moment, only direct reinitialization using geometric computations
111  of all the distances is available. This makes the choice of the element
112  used for the space discretization to be restricted to the P1.
113 
114  <b> Usage </b>
115 
116  The best usage consists in, first of all, build a LevelSetData stucture
117 
118  \code
119  std::shared_ptr<DataLevelSet> data_level_set(new DataLevelSet);
120  data_level_set->setup(...);
121  \endcode
122 
123  Then, the level set solver can be defined and setup:
124 
125  \code
126  LevelSetSolver<mesh_type> level_set(...);
127  level_set.setup(data_level_set);
128  \endcode
129 
130  Do not forget to initialize the solver with the initial data!
131 
132  \code
133  level_set.initialize(...);
134  \endcode
135 
136  Finally, before starting the time loop, you have to setup the solver
137 
138  \code
139  level_set.setupLinearSolver(...);
140  \endcode
141 
142  In the time loop, the most important things are:
143 
144  \code
145  data_level_set->dataTime()->updateTime(); // Update the time in the data
146  level_set.updateSystem(...); // Update the linear system
147  level_set.iterate(); // Solve the system
148  level_set.reinitializationDirect(); // Reinitialize if needed
149  \endcode
150 
151 
152  <b> Futur improvements </b>
153 
154  The current reinitialization is quite primitive: it is
155  not very accurate, volume is not very well conserved
156  and the computational cost is far too high (it consists
157  more or less to a broadcast of the mesh...). Better
158  reinitialization procedures should be added.
159 
160  @author Samuel Quinodoz
161  @version 1.0
162 */
163 
164 template< typename mesh_type, typename solver_type = LifeV::SolverAztecOO>
165 class LevelSetSolver
166 {
167 public:
168 
169  //! @name Public Types
170  //@{
171 
172  typedef MapEpetra map_Type;
173 
174  typedef FESpace<mesh_type, map_Type> fespace_type;
175  typedef std::shared_ptr<fespace_type> fespace_ptrType;
176 
177  typedef typename solver_type::vector_type vector_type;
178 
179  typedef typename solver_type::matrix_type matrix_type;
180  typedef std::shared_ptr<matrix_type> matrix_ptrType;
181 
182  typedef DataLevelSet data_type;
183  typedef std::shared_ptr<data_type> data_ptrType;
184 
185  typedef TimeAdvanceBDF<vector_type> bdf_type;
186  typedef std::shared_ptr<bdf_type> bdf_ptrType;
187 
188  //@}
189 
190 
191  //! @name Constructor & Destructor
192  //@{
193 
194  //! Empty constructor
195  LevelSetSolver ( fespace_ptrType fespace, fespace_ptrType betaFESpace );
196 
197  //! Destructor
198  ~LevelSetSolver() {};
199 
200  //@}
201 
202  //! @name Methods
203  //@{
204 
205  //! Set the internal data with this data
206  void setup (const data_ptrType& data);
207 
208  //! Set the initial solution
209  /*!
210  @Warning: the setup method has to be called before
211  */
212  void initialize (const vector_type& init);
213 
214  //! Rebuild the system
215  /*!
216  @Warning: the initialize method has to be called before
217  */
218  void updateSystem (const vector_type& beta, BCHandler& bch, const Real& time);
219 
220  //! Setup the linear solver
221  void setupLinearSolver (const GetPot& dataFile, const std::string& section = "level-set");
222 
223  //! Solve the problem with the built system
224  void iterate();
225 
226  //! Reinitialization via direct geometrical computations
227  void reinitializationDirect();
228 
229  //@}
230 
231  //! @name Set Methods
232  //@{
233 
234  //@}
235 
236 
237  //! @name Get Methods
238  //@{
239 
240  //! Return the map of the unknown FE space
241  inline map_Type map() const
242  {
243  return M_fespace->map();
244  }
245 
246  //! Return the solution
247  inline vector_type solution() const
248  {
249  return M_solution;
250  }
251 
252  //! Return the data
253  inline data_ptrType data() const
254  {
255  return M_data;
256  }
257 
258  //@}
259 
260 private:
261 
262  // Private typedefs
263 
264  // Assemblers
265  typedef ADRAssembler<mesh_type, matrix_type, vector_type> adrAssembler_type;
266  typedef ADRAssemblerIP<mesh_type, matrix_type, vector_type> ipAssembler_type;
267 
268  // Geometry
269  typedef std::vector<Real> point_type;
270  typedef std::vector<point_type> face_type;
271 
272 
273  //! @name Private Methods
274  //@{
275 
276  void updateFacesNormalsRadius();
277  Real computeUnsignedDistance (const std::vector< Real >& point);
278  void cleanFacesData();
279  inline Real distanceBetweenPoints (const point_type& P1, const point_type& P2) const
280  {
281  return std::sqrt ( (P1[0] - P2[0]) * (P1[0] - P2[0]) + (P1[1] - P2[1]) * (P1[1] - P2[1]) + (P1[2] - P2[2]) * (P1[2] - P2[2]) );
282  };
283  inline point_type crossProd (const point_type& P1, const point_type& P2) const
284  {
285  point_type n (3, 0);
286 
287  n[0] = P1[1] * P2[2] - P1[2] * P2[1];
288  n[1] = P1[2] * P2[0] - P1[0] * P2[2];
289  n[2] = P1[0] * P2[1] - P1[1] * P2[0];
290 
291  return n;
292  };
293  inline Real scalProd (const point_type& P1, const point_type& P2) const
294  {
295  return P1[0] * P2[0] + P1[1] * P2[1] + P1[2] * P2[2];
296  };
297  inline Real norm (const point_type& V) const
298  {
299  return std::sqrt (V[0] * V[0] + V[1] * V[1] + V[2] * V[2]);
300  };
301 
302  //@}
303 
304 
305  // Private members
306  fespace_ptrType M_fespace;
307  fespace_ptrType M_betaFESpace;
308 
309  vector_type M_solution;
310 
311  adrAssembler_type M_adrAssembler;
312  ipAssembler_type M_ipAssembler;
313 
314  matrix_ptrType M_systemMatrix;
315  matrix_ptrType M_massMatrix;
316  matrix_ptrType M_rhsMatrix;
317 
318  vector_type M_rhs;
319 
320  data_ptrType M_data;
321 
322  bdf_ptrType M_bdf;
323 
324  solver_type M_linearSolver;
325 
326  std::vector<face_type> M_faces;
327  std::vector<point_type> M_normals;
328  std::vector<Real> M_radius;
329 
330 };
331 
332 // ===================================================
333 // Constructors & Destructor
334 // ===================================================
335 
336 template< typename mesh_type, typename solver_type>
337 LevelSetSolver<mesh_type, solver_type>::
338 LevelSetSolver ( fespace_ptrType fespace, fespace_ptrType betaFESpace )
339  :
340  M_fespace (fespace),
341  M_betaFESpace (betaFESpace),
342 
343  M_solution (fespace->map() ),
344 
345  M_adrAssembler(),
346  M_ipAssembler(),
347 
348  M_systemMatrix(),
349  M_massMatrix(),
350  M_rhsMatrix(),
351 
352  M_rhs (fespace->map() ),
353 
354  M_data(),
355 
356  M_bdf(),
357 
358  M_linearSolver()
359 {
360  M_adrAssembler.setup (fespace, betaFESpace);
361  M_ipAssembler.setup (fespace, betaFESpace);
362  M_linearSolver.setCommunicator (fespace->map().commPtr() );
363 }
364 
365 // ===================================================
366 // Methods
367 // ===================================================
368 
369 template< typename mesh_type, typename solver_type>
370 void
371 LevelSetSolver<mesh_type, solver_type>::
372 setup (const data_ptrType& data)
373 {
374  M_data = data;
375  M_bdf.reset (new bdf_type() );
376  M_bdf->setup (data->dataTimeAdvance()->orderBDF() );
377 }
378 
379 
380 template< typename mesh_type, typename solver_type>
381 void
382 LevelSetSolver<mesh_type, solver_type>::
383 initialize (const vector_type& init)
384 {
385  ASSERT (M_bdf != 0, "Bdf structure not initialized. Use the setup method before initialize.");
386  M_solution = init;
387  M_bdf->setInitialCondition (init);
388 }
389 
390 template< typename mesh_type, typename solver_type>
391 void
392 LevelSetSolver<mesh_type, solver_type>::
393 updateSystem (const vector_type& beta, BCHandler& bcHandler, const Real& time)
394 {
395  ASSERT (M_bdf != 0, "Bdf structure not initialized. Use the setup method before updateSystem.");
396  ASSERT (M_data != 0, "No data available. Use the setup method before updateSystem.");
397 
398  // Check the existence of the matrices
399  if (M_massMatrix == 0)
400  {
401  M_massMatrix.reset (new matrix_type (M_fespace->map() ) );
402  M_adrAssembler.addMass (M_massMatrix, 1.0);
403  M_massMatrix->globalAssemble();
404  }
405 
406  M_systemMatrix.reset (new matrix_type (M_fespace->map() ) );
407  M_rhsMatrix.reset (new matrix_type (M_fespace->map() ) );
408 
409  // Erase the old matrices
410  *M_systemMatrix *= 0.0;
411  *M_rhsMatrix *= 0.0;
412 
413 
414  // Mass matrix
415  *M_systemMatrix += (*M_massMatrix) * ( M_bdf->coefficientFirstDerivative (0) / M_data->dataTime()->timeStep() );
416 
417  // advection matrix
418  M_adrAssembler.addAdvection (M_systemMatrix, beta);
419 
420  // ip stabilization
421  if (M_data->stabilization() == DataLevelSet::IP)
422  {
423  if (M_data->IPTreatment() == DataLevelSet::IMPLICIT)
424  {
425  M_ipAssembler.addIPStabilization (M_systemMatrix, beta, M_data->IPCoef() );
426  }
427  else if (M_data->IPTreatment() == DataLevelSet::SEMI_IMPLICIT)
428  {
429  M_ipAssembler.addIPStabilizationStencil (M_systemMatrix, M_rhsMatrix, beta, M_data->IPCoef() );
430  }
431  else if (M_data->IPTreatment() == DataLevelSet::EXPLICIT)
432  {
433  M_ipAssembler.addIPStabilization (M_rhsMatrix, beta, M_data->IPCoef() );
434  }
435  }
436 
437  // Global Assembly
438 
439  M_systemMatrix->globalAssemble();
440  M_rhsMatrix->globalAssemble();
441 
442 
443  // Erase old rhs
444  M_rhs *= 0.0;
445 
446  // Rhs time
447  M_bdf->updateRHSContribution (M_data->dataTime()->timeStep() );
448  M_rhs += *M_massMatrix * M_bdf->rhsContributionFirstDerivative();
449 
450  // Rhs stab
451  M_rhs += *M_rhsMatrix * M_solution;
452 
453 
454  // Manage the BCs
455  bcHandler.bcUpdate (*M_fespace->mesh(), M_fespace->feBd(), M_fespace->dof() );
456  bcManage (*M_systemMatrix, M_rhs, *M_fespace->mesh(), M_fespace->dof(), bcHandler, M_fespace->feBd(), 1.0, time);
457 }
458 
459 
460 template< typename mesh_type, typename solver_type>
461 void
462 LevelSetSolver<mesh_type, solver_type>::
463 setupLinearSolver (const GetPot& dataFile, const std::string& section)
464 {
465  M_linearSolver.setDataFromGetPot ( dataFile, (section + "/solver").data() );
466  M_linearSolver.setupPreconditioner ( dataFile, (section + "/prec").data() );
467 }
468 
469 template< typename mesh_type, typename solver_type>
470 void
471 LevelSetSolver<mesh_type, solver_type>::
472 iterate()
473 {
474  ASSERT (M_systemMatrix != 0, "No system matrix for the linear system! Build it before.");
475  ASSERT (M_bdf != 0, "No bdf structure. Use the setup method before the iterate.");
476 
477  M_linearSolver.setMatrix (*M_systemMatrix);
478 
479  M_linearSolver.solveSystem (M_rhs, M_solution, M_systemMatrix);
480 
481  M_bdf->shiftRight (M_solution);
482 }
483 
484 
485 
486 template<typename mesh_type, typename solver_type>
487 void
488 LevelSetSolver<mesh_type, solver_type>::
489 reinitializationDirect()
490 {
491  updateFacesNormalsRadius();
492 
493 
494  // Initialization of the MPI things
495  int nb_proc (0);
496  int my_rank (0);
497 
498  const Epetra_MpiComm* my_comm = dynamic_cast<Epetra_MpiComm const*> (& (M_fespace->map().comm() ) );
499 
500  unsigned int dim (3);
501  int nPt (M_fespace->mesh()->storedPoints() );
502 
503  nb_proc = my_comm->NumProc();
504  my_rank = my_comm->MyPID();
505  MPI_Status status;
506 
507  std::vector< std::vector< Real > > my_points (nPt, std::vector<Real> (dim) );
508  for (int iter_pt (0); iter_pt < nPt; ++iter_pt)
509  {
510  my_points[iter_pt][0] = M_fespace->mesh()->point (iter_pt).x();
511  my_points[iter_pt][1] = M_fespace->mesh()->point (iter_pt).y();
512  my_points[iter_pt][2] = M_fespace->mesh()->point (iter_pt).z();
513  };
514 
515 
516 
517  // Storage for the distance
518  std::vector < std::vector < Real > > temp_distances (nb_proc, std::vector< Real> (nPt, 0.0) );
519 
520  // Communications
521 
522  my_comm->Barrier();
523 
524  // Start the communications
525 
526  for (int i (0); i < nb_proc; ++i)
527  {
528  // Sender
529  if (my_rank == i)
530  {
531  //std::cout << " Reinitialize part " << my_rank << std::endl;
532 
533  for (int j (0); j < nb_proc; ++j)
534  {
535  if (j != i)
536  {
537  MPI_Send (&nPt, 1, MPI_INT, j, 1, my_comm->Comm() );
538  }
539  };
540 
541  //std::cout << " Send points " << std::endl;
542  for (int d (0); d < nPt; ++d)
543  {
544  for (int j (0); j < nb_proc; ++j)
545  {
546  if (j != i)
547  {
548  //MPI_Request req;
549  //MPI_Isend(&my_points[d][0],dim,MPI_DOUBLE,j,1,my_comm->Comm(),&req);
550  //MPI_Wait(&req,&status);
551  MPI_Ssend (&my_points[d][0], dim, MPI_DOUBLE, j, 1, my_comm->Comm() );
552  };
553  };
554  };
555 
556  //std::cout << " Compute " << std::endl;
557  for (int iter_pt (0); iter_pt < nPt; ++iter_pt)
558  {
559  std::vector<Real> dof_coord;
560  dof_coord.push_back (my_points[iter_pt][0]);
561  dof_coord.push_back (my_points[iter_pt][1]);
562  dof_coord.push_back (my_points[iter_pt][2]);
563  temp_distances[i][iter_pt] = computeUnsignedDistance (dof_coord);
564  };
565 
566  //std::cout << " Get the distances " << std::endl;
567  for (int distToRecieve (0); distToRecieve < nPt; ++distToRecieve)
568  {
569  for (int j (0); j < nb_proc; ++j)
570  {
571  if (j != i)
572  {
573  //MPI_Request req;
574  //MPI_Irecv(&(temp_distances[j][distToRecieve]),1,MPI_DOUBLE,j,1,my_comm->Comm(),&req);
575  //MPI_Wait(&req,&status);
576  MPI_Recv (& (temp_distances[j][distToRecieve]), 1, MPI_DOUBLE, j, 1, my_comm->Comm(), &status);
577  }
578  };
579  };
580 
581 
582  }
583  else
584  {
585  // Reciever
586 
587  int n_pt_to_recieve (0);
588  MPI_Recv (&n_pt_to_recieve, 1, MPI_INT, i, 1, my_comm->Comm(), &status);
589  //std::cout << " Points (R) : " << n_pt_to_recieve << std::endl;
590 
591  std::vector< std::vector< Real > > current_points (n_pt_to_recieve, std::vector< Real> (dim, 0) );
592  std::vector< Real> current_distances (n_pt_to_recieve, 0);
593 
594  for (int d (0); d < n_pt_to_recieve; ++d)
595  {
596  //MPI_Request req;
597  //MPI_Irecv(&current_points[d][0],dim,MPI_DOUBLE,i,1,my_comm->Comm(),&req);
598  //MPI_Wait(&req,&status);
599  MPI_Recv (&current_points[d][0], dim, MPI_DOUBLE, i, 1, my_comm->Comm(), &status);
600  };
601 
602  for (int iter_pt (0); iter_pt < n_pt_to_recieve; ++iter_pt)
603  {
604  std::vector< Real > current_pt (dim, 0);
605  current_pt[0] = current_points[iter_pt][0];
606  current_pt[1] = current_points[iter_pt][1];
607  current_pt[2] = current_points[iter_pt][2];
608 
609  current_distances[iter_pt] = computeUnsignedDistance (current_pt);
610  };
611 
612  for (int iter_pt (0); iter_pt < n_pt_to_recieve; ++iter_pt)
613  {
614  //MPI_Request req;
615  //MPI_Isend(&current_distances[iter_pt],1,MPI_DOUBLE,i,1,my_comm->Comm(),&req);
616  //MPI_Wait(&req,&status);
617  MPI_Ssend (&current_distances[iter_pt], 1, MPI_DOUBLE, i, 1, my_comm->Comm() );
618  };
619 
620  }; // end if
621 
622  my_comm->Barrier();
623 
624  }; // end for i
625 
626 
627  // Post processing
628  // Also give the sign!
629 
630  vector_type repSol (M_solution, Repeated);
631 
632  for (int iter_pt (0); iter_pt < nPt; ++iter_pt)
633  {
634  // Compute the minimum over the points
635  Real abs_dist (temp_distances[0][iter_pt]);
636 
637  for (int j (1); j < nb_proc; ++j)
638  {
639  if (temp_distances[j][iter_pt] < abs_dist)
640  {
641  abs_dist = temp_distances[j][iter_pt];
642  };
643  };
644 
645  ID my_id (M_fespace->mesh()->point (iter_pt).id() );
646  int sign (1);
647  if (repSol (my_id) < 0)
648  {
649  sign = -1;
650  };
651  repSol (my_id) = abs_dist * sign;
652  };
653 
654  my_comm->Barrier();
655 
656  M_solution = vector_type (repSol, Unique, Zero);
657 
658 }
659 
660 // ===================================================
661 // Private Methods
662 // ===================================================
663 
664 template<typename mesh_type, typename solver_type>
665 void
666 LevelSetSolver<mesh_type, solver_type>::
667 updateFacesNormalsRadius()
668 {
669  // Use a repeated vector, as we need the boundary
670  // values on both processor domains
671  vector_type rep_solution (M_solution, Repeated);
672 
673  cleanFacesData();
674 
675  UInt n_el (M_fespace->mesh()->numElements() );
676  UInt n_dof (M_fespace->dof().numLocalDof() );
677  for (ID iter_el (0); iter_el < n_el; ++iter_el)
678  {
679 
680  // Storage for the points on the face
681  std::vector< point_type> intersection_points;
682 
683 
684  // Find the edges that are crossed by the interface
685  for (UInt iter_dof_1 (0); iter_dof_1 < n_dof; ++iter_dof_1)
686  {
687  ID id_dof_1 ( M_fespace->dof().localToGlobalMap (iter_el, iter_dof_1) );
688  Real val1 (rep_solution (id_dof_1) );
689 
690  for (UInt iter_dof_2 (iter_dof_1 + 1); iter_dof_2 < n_dof ; ++iter_dof_2)
691  {
692  ID id_dof_2 ( M_fespace->dof().localToGlobalMap (iter_el, iter_dof_2) );
693  Real val2 (rep_solution (id_dof_2) );
694 
695  // Check if there is a change in the sign
696  // DO NOT TAKE INTO ACCOUNT THE DEGENERATED EDGES
697  if ( (val1 * val2 <= 0) && ( (val1 != 0) || (val2 != 0) ) )
698  {
699  Real lambda (-val1 / (val2 - val1) );
700 
701  point_type inter (3, 0);
702 
703  inter[0] = (1 - lambda) * M_fespace->mesh()->element (iter_el).point (iter_dof_1).x()
704  + lambda * M_fespace->mesh()->element (iter_el).point (iter_dof_2).x() ;
705  inter[1] = (1 - lambda) * M_fespace->mesh()->element (iter_el).point (iter_dof_1).y()
706  + lambda * M_fespace->mesh()->element (iter_el).point (iter_dof_2).y() ;
707  inter[2] = (1 - lambda) * M_fespace->mesh()->element (iter_el).point (iter_dof_1).z()
708  + lambda * M_fespace->mesh()->element (iter_el).point (iter_dof_2).z() ;
709 
710  intersection_points.push_back (inter);
711 
712  };
713  };
714  };
715 
716  // Now we know the points on the faces
717  // We want to store them and compute
718  // the radius for each of them
719 
720  if (intersection_points.size() == 3)
721  {
722  // Store the face
723 
724  face_type my_face;
725  my_face.push_back (intersection_points[0]);
726  my_face.push_back (intersection_points[1]);
727  my_face.push_back (intersection_points[2]);
728 
729  M_faces.push_back (my_face);
730 
731  // Compute the radius
732 
733  Real radius (0);
734  Real current_dist (0);
735  current_dist = distanceBetweenPoints (intersection_points[0], intersection_points[1]);
736  if (current_dist > radius)
737  {
738  radius = current_dist;
739  }
740  current_dist = distanceBetweenPoints (intersection_points[0], intersection_points[2]);
741  if (current_dist > radius)
742  {
743  radius = current_dist;
744  }
745  current_dist = distanceBetweenPoints (intersection_points[1], intersection_points[2]);
746  if (current_dist > radius)
747  {
748  radius = current_dist;
749  }
750 
751  M_radius.push_back (radius);
752 
753  // Compute the normal
754 
755  point_type v1 (3, 0);
756  v1[0] = intersection_points[1][0] - intersection_points[0][0];
757  v1[1] = intersection_points[1][1] - intersection_points[0][1];
758  v1[2] = intersection_points[1][2] - intersection_points[0][2];
759 
760  point_type v2 (3, 0);
761  v2[0] = intersection_points[2][0] - intersection_points[0][0];
762  v2[1] = intersection_points[2][1] - intersection_points[0][1];
763  v2[2] = intersection_points[2][2] - intersection_points[0][2];
764 
765  point_type normal_face (crossProd (v1, v2) );
766  Real my_norm (norm (normal_face) );
767  normal_face[0] = normal_face[0] / my_norm;
768  normal_face[1] = normal_face[1] / my_norm;
769  normal_face[2] = normal_face[2] / my_norm;
770 
771  M_normals.push_back (normal_face);
772 
773 
774  }
775  else if (intersection_points.size() == 4)
776  {
777  // Here we have to beware to choose the right one!
778  // Store the face
779 
780  face_type my_face;
781  my_face.push_back (intersection_points[0]);
782  my_face.push_back (intersection_points[1]);
783  my_face.push_back (intersection_points[2]);
784 
785  M_faces.push_back (my_face);
786 
787  // Compute the radius
788 
789  Real radius (0);
790  Real current_dist (0);
791  current_dist = distanceBetweenPoints (intersection_points[0], intersection_points[1]);
792  if (current_dist > radius)
793  {
794  radius = current_dist;
795  }
796  current_dist = distanceBetweenPoints (intersection_points[0], intersection_points[2]);
797  if (current_dist > radius)
798  {
799  radius = current_dist;
800  }
801  current_dist = distanceBetweenPoints (intersection_points[1], intersection_points[2]);
802  if (current_dist > radius)
803  {
804  radius = current_dist;
805  }
806 
807  M_radius.push_back (radius);
808 
809  point_type v1 (3, 0);
810  v1[0] = intersection_points[1][0] - intersection_points[0][0];
811  v1[1] = intersection_points[1][1] - intersection_points[0][1];
812  v1[2] = intersection_points[1][2] - intersection_points[0][2];
813 
814  point_type v2 (3, 0);
815  v2[0] = intersection_points[2][0] - intersection_points[0][0];
816  v2[1] = intersection_points[2][1] - intersection_points[0][1];
817  v2[2] = intersection_points[2][2] - intersection_points[0][2];
818 
819  point_type normal_face (crossProd (v1, v2) );
820  Real my_norm (norm (normal_face) );
821  normal_face[0] = normal_face[0] / my_norm;
822  normal_face[1] = normal_face[1] / my_norm;
823  normal_face[2] = normal_face[2] / my_norm;
824 
825  M_normals.push_back (normal_face);
826 
827 
828  // Find the second face
829  face_type my_second_face;
830 
831  my_second_face.push_back (intersection_points[3]);
832 
833  for (int i (0); i < 3; ++i)
834  {
835  int other_1 ( (i + 1) % 3);
836  int other_2 ( (i + 2) % 3);
837 
838  point_type v (3, 0);
839  v[0] = intersection_points[other_2][0] - intersection_points[other_1][0];
840  v[1] = intersection_points[other_2][1] - intersection_points[other_1][1];
841  v[2] = intersection_points[other_2][2] - intersection_points[other_1][2];
842 
843  point_type normal_v (crossProd (v, normal_face) );
844 
845  point_type o1_to_i (3, 0);
846  o1_to_i[0] = intersection_points[i][0] - intersection_points[other_1][0];
847  o1_to_i[1] = intersection_points[i][1] - intersection_points[other_1][1];
848  o1_to_i[2] = intersection_points[i][2] - intersection_points[other_1][2];
849 
850  point_type o1_to_inter3 (3, 0);
851  o1_to_inter3[0] = intersection_points[3][0] - intersection_points[other_1][0];
852  o1_to_inter3[1] = intersection_points[3][1] - intersection_points[other_1][1];
853  o1_to_inter3[2] = intersection_points[3][2] - intersection_points[other_1][2];
854 
855  if ( scalProd (normal_v, o1_to_i) * scalProd (normal_v, o1_to_inter3) > 0)
856  {
857  my_second_face.push_back (intersection_points[i]);
858  }
859 
860  };
861 
862  ASSERT (my_second_face.size() == 3, "Internal error while computing the faces");
863  M_faces.push_back (my_second_face);
864 
865  // Compute its radius
866 
867  current_dist = 0;
868  current_dist = distanceBetweenPoints (my_second_face[0], my_second_face[1]);
869  if (current_dist > radius)
870  {
871  radius = current_dist;
872  }
873  current_dist = distanceBetweenPoints (my_second_face[0], my_second_face[2]);
874  if (current_dist > radius)
875  {
876  radius = current_dist;
877  }
878  current_dist = distanceBetweenPoints (my_second_face[1], my_second_face[2]);
879  if (current_dist > radius)
880  {
881  radius = current_dist;
882  }
883 
884  M_radius.push_back (radius);
885 
886  // Normal is the same
887  // (already supposed in the computations)
888  M_normals.push_back (normal_face);
889 
890 
891 
892  }
893  else if (intersection_points.size() > 0)
894  {
895  std::cout << intersection_points.size() << std::endl;
896  ERROR_MSG ("Internal error in the localization of the interface");
897  };
898  }; // end for iter_el
899 
900  ASSERT (M_faces.size() == M_radius.size(), "Internal non coerance");
901  ASSERT (M_faces.size() == M_normals.size(), "Internal non coerance");
902 
903 }
904 
905 template<typename mesh_type, typename solver_type>
906 Real
907 LevelSetSolver<mesh_type, solver_type>::
908 computeUnsignedDistance (const std::vector< Real >& point)
909 {
910  // We use here a 2 steps algorithm.
911  // The first step is used to erase quickly all the
912  // the faces that are not good candidates
913  // The second step then compute the exact distance
914  // for the remaining faces.
915 
916  // Initialisation
917  Real absdist (std::numeric_limits<double>::max() );
918 
919  // Informations
920  int nbFaces (this->M_faces.size() );
921 
922  // Storage of the distances with the center of gravity
923  std::vector<Real> dist_lower_bound (nbFaces);
924 
925 
926  // ==> STEP 1
927  // A first run to get a rough estimations and lower bounds
928  // We just test the first point as this is fast and already
929  // eliminates lot of faces
930 
931  for (int iter_face (0); iter_face < nbFaces; ++iter_face)
932  {
933  Real current_dist (distanceBetweenPoints (point, M_faces[iter_face][0]) );
934  dist_lower_bound[iter_face] = current_dist - M_radius[iter_face];
935 
936  if (current_dist < absdist)
937  {
938  absdist = current_dist;
939  }
940  };
941 
942 
943  // ==> STEP 2
944  // Compute the distance using only the candidates
945  // selected by the lower bound
946  //
947  for (int iter_face (0); iter_face < nbFaces; ++iter_face)
948  {
949  // Exclude cells that are too far
950  if (dist_lower_bound[iter_face] <= absdist)
951  {
952 
953  Real current_abs_dist (std::numeric_limits<double>::max() );
954 
955 
956  // First of all, project the point on the plan
957  // of the face
958 
959  point_type point_to_face (3, 0);
960  point_to_face[0] = point[0] - M_faces[iter_face][0][0];
961  point_to_face[1] = point[1] - M_faces[iter_face][0][1];
962  point_to_face[2] = point[2] - M_faces[iter_face][0][2];
963 
964  Real lambda = scalProd (point_to_face, M_normals[iter_face]);
965  point_type projected_point (3, 0);
966  projected_point[0] = point[0] - lambda * M_normals[iter_face][0];
967  projected_point[1] = point[1] - lambda * M_normals[iter_face][1];
968  projected_point[2] = point[2] - lambda * M_normals[iter_face][2];
969 
970  // Compute the distance
971  // For debugging purpose, this should be equal to std::abs(lambda)
972  current_abs_dist = distanceBetweenPoints (point, projected_point);
973 
974  // This is the distance only if the projected point
975  // belongs to the present facel. We test this.
976 
977  for (int iter_edge (0); iter_edge < 3 ; ++iter_edge)
978  {
979  int vertex1 (iter_edge), vertex2 ( (iter_edge + 1) % 3), vertex_out ( (iter_edge + 2) % 3);
980 
981  // Check if the projected point is on the right side of the edge
982  point_type edge_vector (3, 0);
983  edge_vector[0] = M_faces[iter_face][vertex2][0] - M_faces[iter_face][vertex1][0];
984  edge_vector[1] = M_faces[iter_face][vertex2][1] - M_faces[iter_face][vertex1][1];
985  edge_vector[2] = M_faces[iter_face][vertex2][2] - M_faces[iter_face][vertex1][2];
986 
987  // Compute the "normal to the edge", the vector that is orthogonal to
988  // the edge and to the normal of the face
989  point_type edge_normal (crossProd (M_normals[iter_face], edge_vector) );
990 
991  Real edge_normal_norm (norm (edge_normal) );
992  edge_normal[0] = edge_normal[0] / edge_normal_norm;
993  edge_normal[1] = edge_normal[1] / edge_normal_norm;
994  edge_normal[2] = edge_normal[2] / edge_normal_norm;
995 
996 
997  // Compute the vectors that link point and vertex_out to the edge
998  point_type projpoint_to_edge (3, 0);
999  projpoint_to_edge[0] = projected_point[0] - M_faces[iter_face][vertex1][0];
1000  projpoint_to_edge[1] = projected_point[1] - M_faces[iter_face][vertex1][1];
1001  projpoint_to_edge[2] = projected_point[2] - M_faces[iter_face][vertex1][2];
1002 
1003  point_type vertex_out_to_edge (3, 0);
1004  vertex_out_to_edge[0] = M_faces[iter_face][vertex_out][0] - M_faces[iter_face][vertex1][0];
1005  vertex_out_to_edge[1] = M_faces[iter_face][vertex_out][1] - M_faces[iter_face][vertex1][1];
1006  vertex_out_to_edge[2] = M_faces[iter_face][vertex_out][2] - M_faces[iter_face][vertex1][2];
1007 
1008  // Check whether the point and the vertex_out are on the same side
1009  // of the edge
1010  if (scalProd (edge_normal, projpoint_to_edge) * scalProd (edge_normal, vertex_out_to_edge) < 0)
1011  {
1012  // The projected point is on the wrong side of the edge, so we project it
1013  // again, but this time on the edge (inside the face plan)
1014  // The plan of the projection is determined by the vector of the edge
1015  // and the normal of the face, what means that the normal of the edge
1016  // is already the projection direction.
1017 
1018  Real lambda_2 (scalProd (edge_normal, projpoint_to_edge) );
1019  point_type projproj_point (3, 0);
1020  projproj_point[0] = projected_point[0] - lambda_2 * edge_normal[0];
1021  projproj_point[1] = projected_point[1] - lambda_2 * edge_normal[1];
1022  projproj_point[2] = projected_point[2] - lambda_2 * edge_normal[2];
1023 
1024  point_type projprojpoint_to_edge (3, 0);
1025  projprojpoint_to_edge[0] = projproj_point[0] - M_faces[iter_face][vertex1][0];
1026  projprojpoint_to_edge[1] = projproj_point[1] - M_faces[iter_face][vertex1][1];
1027  projprojpoint_to_edge[2] = projproj_point[2] - M_faces[iter_face][vertex1][2];
1028 
1029  Real report (scalProd (projprojpoint_to_edge, edge_vector) / scalProd (edge_vector, edge_vector) );
1030 
1031  if (report < 0)
1032  {
1033  current_abs_dist = distanceBetweenPoints (point, M_faces[iter_face][vertex1]);
1034  }
1035  else if (report <= 1)
1036  {
1037  current_abs_dist = distanceBetweenPoints (point, projproj_point);
1038  }
1039  else
1040  {
1041  current_abs_dist = distanceBetweenPoints (point, M_faces[iter_face][vertex2]);
1042  };
1043 
1044  // To avoid useless computations, we
1045  // break the "for iter_edge" loop
1046  break;
1047  };
1048 
1049  };
1050 
1051  // Update if needed
1052 
1053  if (current_abs_dist <= absdist)
1054  {
1055  absdist = current_abs_dist;
1056  };
1057  };
1058  };
1059 
1060  return absdist;
1061 }
1062 
1063 template<typename mesh_type, typename solver_type>
1064 void
1065 LevelSetSolver<mesh_type, solver_type>::
1066 cleanFacesData()
1067 {
1068  M_faces.clear();
1069  M_normals.clear();
1070  M_radius.clear();
1071 }
1072 
1073 } // Namespace LifeV
1074 
1075 #endif /* LEVELSETSOLVER_H */
BCHandler - class for handling boundary conditions.
Definition: BCHandler.hpp:100
#define ERROR_MSG(A)
Definition: LifeAssert.hpp:69
Epetra_Import const & importer()
Getter for the Epetra_Import.
Definition: MapEpetra.cpp:394
#define ASSERT(X, A)
Definition: LifeAssert.hpp:90
uint32_type ID
IDs.
Definition: LifeV.hpp:194
class TimeAdvanceBDF - Backward differencing formula time discretization for the first and the second...
double Real
Generic real data.
Definition: LifeV.hpp:175
ADRAssembler - This class add into given matrices terms corresponding to the space discretization of ...
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191