LifeV
DarcySolverLinear.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 the LifeV library
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
21  License along with this library; if not, see <http://www.gnu.org/licenses/>
22 
23 
24 *******************************************************************************
25 */
26 //@HEADER
27 
28 /*!
29  * @file
30  @brief This file contains a Darcy solver with mixed-hybrid finite elements
31 
32  @date 05/2010
33  @author A. Fumagalli <alessio.fumagalli@mail.polimi.it>
34 
35  @contributor M. Kern <michel.kern@inria.fr>
36  @maintainer M. Kern <michel.kern@inria.fr>
37 */
38 
39 #ifndef _DARCYSOLVERLINEAR_HPP_
40 #define _DARCYSOLVERLINEAR_HPP_ 1
41 
42 
43 #include <Epetra_LAPACK.h>
44 #include <Epetra_BLAS.h>
45 
46 
47 #include <lifev/core/algorithm/LinearSolver.hpp>
48 
49 #include <lifev/core/fem/Assembly.hpp>
50 #include <lifev/core/fem/AssemblyElemental.hpp>
51 
52 #include <lifev/core/util/Displayer.hpp>
53 
54 #include <lifev/core/array/MatrixElemental.hpp>
55 #include <lifev/core/array/VectorElemental.hpp>
56 
57 #include <lifev/core/fem/BCManage.hpp>
58 #include <lifev/core/fem/FEFunction.hpp>
59 #include <lifev/core/fem/TimeAdvance.hpp>
60 
61 #include <lifev/darcy/solver/DarcyData.hpp>
62 
63 // LifeV namespace.
64 namespace LifeV
65 {
66 //! @class DarcySolverLinear This class implements a mixed-hybrid FE Darcy solver.
67 /*!
68  @author A. Fumagalli <alessio.fumagalli@mail.polimi.it>
69  @see For applications related to two-phase flow see \cite Fumagalli2011a
70 
71  This class implements a Darcy solver.
72  <br>
73  <br>
74  The classical formulation of this problem is a couple of differential equations of first order with two
75  unknowns: \f$ p \in C^1 (\Omega ) \f$, being the pressure or the primal unknown,
76  and \f$ \sigma \in (C^1( \Omega ) )^n \f$, being the Darcy velocity or the total flux or the dual unknown,
77  such that
78  \f[
79  \left\{
80  \begin{array}{l l l}
81  \Lambda^{-1} \sigma + \nabla p = f_v & \mathrm{in} & \Omega\,, \vspace{0.2cm} \\
82  \nabla \cdot \sigma + \pi p - f = 0 & \mathrm{in} & \Omega\,, \vspace{0.2cm} \\
83  p = g_D & \mathrm{on} & \Gamma_D\,,\vspace{0.2cm} \\
84  \sigma \cdot n + h p = g_R & \mathrm{on} & \Gamma_R\,.
85  \end{array}
86  \right.
87  \f]
88  The first equation is the Darcy equation and the second equation is the conservation law.
89  <br>
90  The data in the system are:
91  <ul>
92  <li> \f$ \Lambda \f$ the permeability tensor; </li>
93  <li> \f$ f \f$ the scalar source term; </li>
94  <li> \f$ f_v \f$ the vector source term; </li>
95  <li> \f$ \pi \f$ the reaction coefficient; </li>
96  <li> \f$ \Gamma_D \f$ the subset of the boundary of \f$ \Omega \f$ with Dirichlet boundary conditions; </li>
97  <li> \f$ g_D \f$ Dirichlet boundary condition data; </li>
98  <li> \f$ \Gamma_R \f$ that is the part of the boundary of \f$ \Omega \f$ with Robin, or Neumann, boundary conditions; </li>
99  <li> \f$ h \f$ and \f$ g_R \f$ Robin boundary condition data; </li>
100  </ul>
101  We suppose that \f$ \partial \Omega = \Gamma_D \cup \Gamma_R \f$ and \f$ \Gamma_D \cap \Gamma_R = \emptyset \f$.
102  <br>
103  Using the hybridization procedure, and introducing a new variable, we may split the problem from
104  the entire domain to problems in each elements of the triangulation \f$ \mathcal{T}_h \f$, then we may write
105  the weak formulation for the dual problem.
106  The new variable is the hybrid unknown \f$ \lambda \f$, e.g. "the trace" of pressure of the primal unknown,
107  it is the Lagrange multipliers forcing the continuity of the flux across each faces or edges in the triangulation.
108  We introduce the following functional spaces, the first is the space of the primal variable, the third for
109  the dual variable, the fourth for the hybrid variable.
110  \f[
111  \begin{array}{l}
112  V = L^2 (\Omega ) \,,\vspace{0.2cm} \\
113  H(div, K) = \displaystyle \left\{ \tau \in ( L^2(K))^n : \nabla \cdot \tau \in L^2(K)\right\}\,, \vspace{0.2cm}\\
114  Z = \displaystyle \left\{ \tau \in L^2(\Omega) : \tau\vert_K \in H(div, K) \, \forall K \in \mathcal{T}_h \right\}\,, \vspace{0.2cm}\\
115  \Lambda = \displaystyle \left\{ \lambda \in \prod_{K \in \mathcal{T}_h} H^{1/2} (\partial K): \lambda_K = \lambda_{K'} \
116  ,\, \mathrm{on} \,\, e_{K\cap K'} \, \forall K \in \mathcal{T}_h,\, \lambda = g_D \,\, \mathrm{on} \,\, \Gamma_D \right\}\,.
117  \end{array}
118  \f]
119  Introducing the following bilinear forms and functionals
120  \f[
121  \begin{array}{l l}
122  a(\sigma, \tau) = \displaystyle \sum_{K \in \mathcal{T}_h}\int_K \Lambda^{-1} \sigma \cdot \tau \,, &
123  b(p, \tau) = \displaystyle -\sum_{K \in \mathcal{T}_h} \int_K p \nabla \cdot \tau\,, \vspace{0.2cm}\\
124  c(\lambda, \tau) = \displaystyle \sum_{K \in \mathcal{T}_h} \int_{\partial K} \lambda \tau \cdot n\,,&
125  d(p, q) = \displaystyle \sum_{K \in \mathcal{T}_h} \int_{\partial K} \pi p q \,,\vspace{0.2cm}\\
126  h(\lambda, \mu) = \displaystyle \sum_{K \in \mathcal{T}_h} \int_{\partial K \cap \Gamma_R} h \mu \lambda \,,&
127  F(q) = \displaystyle \sum_{K \in \mathcal{T}_h} \int_K f q\,,\vspace{0.2cm}\\
128  F_v(\tau) = \displaystyle \sum_{K \in \mathcal{T}_h} \int_K f_v \tau \,, \vspace{0.2cm}\,,&
129  G(\mu) = \displaystyle \sum_{K \in \mathcal{T}_h} \int_{\partial K \cap \Gamma_R} g \mu\,,
130  \end{array}
131  \f]
132  we obtain the Darcy problem in the weak form: find \f$ (\sigma, \, p, \, \lambda) \in Z \times V \times \Lambda \f$ such that
133  \f[
134  \left\{
135  \begin{array}{l l}
136  a(\sigma, \tau) + b(p, \tau) + c(\lambda, \tau) = F_v(\tau)\,, & \forall \tau \in Z \,,\vspace{0.2cm}\\
137  b(q, \sigma) - d(p,q) = - F(q)\,, & \forall q \in V \,,\vspace{0.2cm}\\
138  c(\mu, \sigma) + h(\lambda, \mu) = G(\mu) \,, & \forall \mu \in \Lambda\,.
139  \end{array}
140  \right.
141  \f]
142  At discrete level we introduce the polynomial space, of degree \f$ r \f$, that approximate the finite dimensional
143  spaces introduced above \f$ V_h \subset V \f$, \f$ Z_h \subset Z \f$ and \f$\Lambda_h \subset \Lambda \f$
144  \f[
145  \begin{array}{l}
146  V_h = \displaystyle \left\{ v_h \in V: v_h|_K \in P_r (K)\, \forall K \in \mathcal{T}_h \right\}\,, \vspace{0.2cm}\\
147  Z_h = \displaystyle \left\{ \tau_h \in Z: \tau_h|_K \in RT_r(K) \, \forall K \in \mathcal{T}_h \right\} \,, \vspace{0.2cm} \\
148  \Lambda_h = \displaystyle \left\{ \lambda_h \in \Lambda: \lambda_h|_{\partial K} \in R_r( \partial K ) \, \forall K \in \mathcal{T}_h\right\}\,,
149  \end{array}
150  \f]
151  where \f$ P_r(K) \f$ is the space of polynomial of degree \f$ r \f$ in the element \f$ K \f$, \f$ RT_r(K) \f$ is the space of
152  polynomial of Raviart-Thomas of degrees \f$ r \f$ in the element \f$ K \f$ and \f$ R_r(\partial K) \f$ is the space of polynomial of
153  degree \f$ r \f$ definite on each of the boundary of the element \f$ K \f$ and discontinuous from one edge to the other.
154  <br>
155  The finite dimensional problem is: find \f$ (\sigma_h,\, p_h, \, \lambda_h) \in Z_h \times V_h \times \Lambda_h \f$ such that
156  \f[
157  \left\{
158  \begin{array}{l l}
159  a(\sigma_h, \tau_h) + b(p_h, \tau_h) + c(\lambda_h, \tau_h) = F_v(\tau_h) \,, & \forall \tau_h \in Z_h \,,\vspace{0.2cm}\\
160  b(q_h, \sigma_h) - d(p_h, q_h)= -F(q_h)\,, & \forall q_h \in V_h \,,\vspace{0.2cm}\\
161  c(\mu_h, \sigma_h) + h(\lambda_h, \mu_h) = G(\mu_h) \,, & \forall \mu_h \in \Lambda_h\,.
162  \end{array}
163  \right.
164  \f]
165  To solve the problem we use the static condensation procedure, i.e. the unknowns in the discrete
166  weak system are not independent and \f$ p_K \f$, \f$\sigma_K \f$ may be written in function of
167  \f$ \lambda_K \f$ alone. We introduce the following local matrices
168  \f[
169  \begin{array}{l l l}
170  \left[ A \right]_{ij} = \displaystyle \int_K \Lambda^{-1} \psi_j \cdot \psi_i \,, &
171  \left[ B \right]_{ij} = \displaystyle - \int_K \phi_j \nabla \cdot \psi_i \,, &
172  \left[ C \right]_{ij} = \displaystyle \int_{\partial K} \xi_i \psi_j \cdot n \,, \vspace{0.2cm} \\
173  \left[ D \right]_{ij} = \displaystyle \int_K \pi \phi_j \phi_i\,, &
174  \left[ H \right]_{ij} = \displaystyle \int_{\partial K \cap \Gamma_R} h \xi_i \xi_j\,, &
175  \left[ F \right]_{j} = \displaystyle \int_K f \phi_j\,, \vspace{0.2cm} \\
176  \left[ F_v \right]_{j} = \displaystyle \int_K f_v \cdot \psi_j\,,&
177  \left[ G \right]_{j} = \displaystyle \int_{\partial K \cap \Gamma_R } g \xi_j\,,
178  \end{array}
179  \f]
180  where we avoid to write the dependence on the triangle \f$ K \f$ in all the matrices and vectors. <BR>
181  The local matrix formulation of the finite dimensional problem is
182  \f[
183  \left\{
184  \begin{array}{l}
185  A \sigma_K + B p_K + C \lambda_K = F_v\,, \vspace{0.2cm} \\
186  B^T \sigma_K - D p_K = -F \,, \vspace{0.2cm}\\
187  C^T \sigma_K + H \lambda_K = G\,.
188  \end{array}
189  \right.
190  \f]
191  Or alternatively
192  \f[
193  \begin{array}{l l l}
194  \left[
195  \begin{array}{c c c}
196  A & B & C \vspace{0.2cm} \\
197  B^T & -D & 0 \vspace{0.2cm} \\
198  C^T & 0 & H
199  \end{array}
200  \right] \, \cdot &
201  \left[
202  \begin{array}{c}
203  \sigma_K \vspace{0.2cm}\\
204  p_K \vspace{0.2cm}\\
205  \lambda_K
206  \end{array}
207  \right] \, &
208  =
209  \left[
210  \begin{array}{c}
211  F_v \vspace{0.2cm}\\
212  -F \vspace{0.2cm}\\
213  G
214  \end{array}
215  \right]\,.
216  \end{array}
217  \f]
218  Introducing the local hybrid matrix and local hybrid right hand side
219  \f[
220  \begin{array}{l}
221  L_K = - C^T A^{-1} C + C^T A^{-1} B \left( B^T A^{-1} B + D \right)^{-1} B^T A^{-1} C + H \,, \vspace{0.2cm} \\
222  r_K = G + C^T A^{-1} B \left( B^T A^{-1} B + D \right)^{-1} F + C^T A^{-1} B \left( B^T A^{-1} B + D \right)^{-1} B^T A^{-1} F_v - C^T A^{-1} F_v \,,
223  \end{array}
224  \f]
225  Imposing that at each edge or face the hybrid unknown is single value we obtain a linear system for the hybrid unknown
226  \f[
227  L \lambda = r \,.
228  \f]
229  We recover the primal and dual variable as a post-process from the hybrid variable at element level, so we have
230  \f[
231  \begin{array}{l}
232  p_K = \left( B^T A^{-1} B + D \right)^{-1} \left( F + B^T A^{-1} F_v - B^T A^{-1} C \lambda_K \right)\,, \vspace{0.2cm} \\
233  \sigma_K = -A^{-1} \left( B p_K - F_v + C \lambda_K \right) \,.
234  \end{array}
235  \f]
236  @note In the code we do not use the matrix \f$ H \f$ and the vector \f$ G \f$, because all the boundary
237  conditions are imposed via BCHandler class.
238  @note Example of usage can be found in darcy_nonlinear and darcy_linear.
239  Coupled with an hyperbolic solver in impes.
240  @todo Insert any scientific publications that use this solver.
241  @bug If the save flag for the exporter is setted to 0 the program fails.
242 */
243 
244 template < typename MeshType >
246 {
247 
248 public:
249 
250  //! @name Public Types
251  //@{
252 
253  //! Typedef for mesh template.
254  typedef MeshType mesh_Type;
255 
256  //! Typedef for solver template.
257  typedef LinearSolver solver_Type;
258 
259  //! Self typedef
261 
262  //! Typedef for the data type.
264 
265  //! Shared pointer for the data type.
267 
268  //! Boundary condition handler.
269  typedef BCHandler bcHandler_Type;
270 
271  //! Shared pointer to a boundary condition handler.
273 
274  //! Shared pointer to a MPI communicator.
276 
277  //! Map type.
278  typedef MapEpetra map_Type;
279 
280  //! Shared pointer to a displayer.
282 
283  //! Finite element space.
285 
286  //! Shared pointer to a finite element space.
288 
289  //! Scalar field.
291 
292  //! Shared pointer to a scalar field.
294 
295  //! Vector field.
297 
298  //! Shared pointer to a scalar field.
300 
301  //! Scalar value function.
303 
304  //! Shared pointer to a scalar value function.
306 
307  //! Vector value function.
309 
310  //! Shared pointer to a vector value function.
312 
313  //! Matrix value funcion.
315 
316  //! Shared pointer to a matrix value function.
318 
319  //! Sparse and distributed matrix.
320  typedef typename solver_Type::matrix_Type matrix_Type;
321 
322  //! Shared pointer to a sparse and distributed matrix.
323  typedef typename solver_Type::matrixPtr_Type matrixPtr_Type;
324 
325  //! Distributed vector.
326  typedef typename solver_Type::vector_Type vector_Type;
327 
328  //! Shared pointer to a distributed vector.
329  typedef typename solver_Type::vectorPtr_Type vectorPtr_Type;
330 
331  //! Shared pointer to the preconditioner.
332  typedef typename solver_Type::preconditionerPtr_Type preconditionerPtr_Type;
333 
334  //@}
335 
336  //! @name Constructors and destructor
337  //@{
338 
339  //! Constructor for the class.
341 
342  //! Virtual destructor.
343  virtual ~DarcySolverLinear () {};
344 
345  //@}
346 
347  //! @name Methods
348  //@{
349 
350  //! Build the global hybrid system, the right hand and apply the boundary conditions.
351  void buildSystem ();
352 
353  //! Set up the linear solver and the preconditioner for the linear system.
354  virtual void setup ();
355 
356  //! Solve the global hybrid system.
357  void solveLinearSystem ();
358 
359  //! Compute primal and dual variables from the hybrid variable as a post process.
360  void computePrimalAndDual ();
361 
362  //! Solve the Darcy problem grouping other public methods.
363  virtual void solve ();
364 
365  //@}
366 
367  //! @name Set Methods
368  //@{
369 
370  //! Set the data.
371  /*!
372  @param data Data for the problem.
373  */
374  void setData ( dataPtr_Type& data )
375  {
376  M_data = data;
377  }
378 
379  //! Set the boundary conditions.
380  /*!
381  @param bcHandler Boundary condition handler for the problem.
382  */
384  {
385  M_boundaryConditionHandler = bcHandler;
386  }
387 
388  //! Set scalar source term
389  /*!
390  @param scalarSourceFct Vector source term for the problem.
391  */
392  void setScalarSource ( const scalarFctPtr_Type& scalarSourceFct )
393  {
394  M_scalarSourceFct = scalarSourceFct;
395  }
396 
397  //! Set vector source term
398  /*!
399  @param vectorSourceFct Vector source term for the problem.
400  */
401  void setVectorSource ( const vectorFctPtr_Type& vectorSourceFct )
402  {
403  M_vectorSourceFct = vectorSourceFct;
404  }
405 
406  //! Set inverse diffusion tensor
407  /*!
408  Set the inverse of diffusion tensor, the default inverse of permeability is the identity matrix.
409  @param invPermFct Inverse of the permeability tensor for the problem.
410  */
411  virtual void setInversePermeability ( const matrixFctPtr_Type& invPermFct )
412  {
413  M_inversePermeabilityFct = invPermFct;
414  }
415 
416  //! Set the coefficient for the reaction term.
417  /*!
418  @param reactionTermFct Reaction term for the problem.
419  @note Useful also for time discretization term.
420  */
421  void setReactionTerm ( const scalarFctPtr_Type& reactionTermFct )
422  {
423  M_reactionTermFct = reactionTermFct;
424  }
425 
426  //! Set the hybrid field vector.
427  /*!
428  @param hybrid Constant scalarFieldPtr_Type reference of the hybrid vector.
429  */
430  void setHybridField ( const scalarFieldPtr_Type& hybridField )
431  {
432  M_hybridField = hybridField;
433  }
434 
435  //! Set the primal field vector.
436  /*!
437  @param primalField Constant scalarFieldPtr_Type reference of the primal solution.
438  */
439  void setPrimalField ( const scalarFieldPtr_Type& primalField )
440  {
441  M_primalField = primalField;
442  }
443 
444  //! Set the dual field vector.
445  /*!
446  @param dualField Constant scalarFieldPtr_Type reference of the dual solution.
447  */
448  void setDualField ( const scalarFieldPtr_Type& dualField )
449  {
450  M_dualField = dualField;
451  }
452 
453  //! Set the fields.
454  /*!
455  @param dualField Constant scalarFieldPtr_Type reference of the dual solution.
456  @param primalField Constant scalarFieldPtr_Type reference of the primal solution.
457  @param hybrid Constant scalarFieldPtr_Type reference of the hybrid vector.
458  */
459  void setFields ( const scalarFieldPtr_Type& dualField,
460  const scalarFieldPtr_Type& primalField,
461  const scalarFieldPtr_Type& hybridField )
462  {
463  // Set the dual field.
464  setDualField ( dualField );
465 
466  // Set the primal field.
467  setPrimalField ( primalField );
468 
469  // Set the hybrid field.
470  setHybridField ( hybridField );
471  }
472 
473  //! Set the displayer and, implicitly, the communicator.
474  /*!
475  @param displayer Constant displayerPtr_Type reference of the displayer.
476  */
477  void setDisplayer ( const displayerPtr_Type& displayer )
478  {
479  M_displayer = displayer;
480  }
481 
482  //! Set the communicator and, implicitly, the displayer.
483  /*!
484  @param comm Constant commPtr_Type reference of the communicator.
485  */
486  void setCommunicator ( const commPtr_Type& comm )
487  {
488  M_displayer.reset ( new displayerPtr_Type::element_type ( comm ) );
489  }
490 
491  //@}
492 
493  //! @name Get Methods
494  //@{
495 
496  //! Returns pointer to the hybrid solution field.
497  /*!
498  @return Constant scalarFieldPtr_Type reference of the hybrid field.
499  */
501  {
502  return M_hybridField;
503  }
504 
505  //! Returns pointer to the hybrid solution field.
506  /*!
507  @return scalarFieldPtr_Type reference of the hybrid solution field.
508  */
510  {
511  return M_hybridField;
512  }
513 
514  //! Returns pointer to the primal solution field.
515  /*!
516  @return Constant scalarFieldPtr_Type reference of the primal solution field.
517  */
519  {
520  return M_primalField;
521  }
522 
523  //! Returns pointer to the primal solution field.
524  /*!
525  @return scalarFieldPtr_Type reference of the primal solution field.
526  */
528  {
529  return M_primalField;
530  }
531 
532  //! Returns pointer to the dual solution field.
533  /*!
534  @return Constant scalarFieldPtr_Type reference of the dual solution field.
535  */
537  {
538  return M_dualField;
539  }
540 
541  //! Returns pointer to the dual solution field.
542  /*!
543  @return scalarFieldPtr_Type reference of the dual solution field.
544  */
546  {
547  return M_dualField;
548  }
549 
550  /*!
551  Returns the pointer of the residual vector.
552  @return Constant vectorPtr_Type reference of the residual.
553  */
554  const vectorPtr_Type& residualPtr () const
555  {
556  return M_residual;
557  }
558 
559  /*!
560  Returns the pointer of the residual vector.
561  @return vectorPtr_Type reference of the residual.
562  */
563  vectorPtr_Type& residualPtr ()
564  {
565  return M_residual;
566  }
567 
568  //! Returns boundary conditions handler.
569  /*!
570  @return Constant reference of boundary conditions handler.
571  */
573  {
575  }
576 
577  //! Returns boundary conditions handler.
578  /*!
579  @return Reference of boundary conditions handler.
580  */
582  {
584  }
585 
586  //! Returns Epetra local map.
587  /*!
588  @return Constant MapEpetra reference of the problem.
589  */
590  const map_Type& getMap () const
591  {
592  return M_hybridField->getFESpace().map();
593  }
594 
595  //! Returns Epetra communicator.
596  /*!
597  @return Reference of the shared pointer of the communicator of the problem.
598  */
599  const commPtr_Type& getCommPtr () const
600  {
601  return M_displayer->comm();
602  }
603 
604  //@}
605 
606 protected:
607 
608  //! @name Private Constructors
609  //@{
610 
611  //! Inhibited copy constructor.
613 
614  //@}
615 
616  //! @name Private Operators
617  //@{
618 
619  //! Inhibited assign operator.
621 
622  //@}
623 
624  //! @name Protected Methods
625  //@{
626 
627  //! Perform all the operations before doing the loop on volume elements.
628  /*!
629  Computes the element independent matrices, clean all the fields and
630  all the algebraich stuff. Useful for extentions in child classes.
631  */
633  {
634  // Update all the variables, e.g. reset the hybrid matrix
636  }
637 
638  //! Pre-computes local (element independant) matrices
639  /*!
640  Compute all the local matrices that are independant
641  from the geometrical element.
642  @param elmatMix The local matrix in mixed form.
643  */
644  void computeConstantMatrices ( MatrixElemental& elmatMix );
645 
646  //! Computes local (element dependent) matrices
647  /*!
648  Locally update the current finite element for the dual finite element space,
649  then compute the Hdiv mass matrix.
650  @param iElem Id of the current geometrical element.
651  @param elmatMix The local matrix in mixed form.
652  @param elmatReactionTerm The local matrix for the reaction term.
653  */
654  virtual void localMatrixComputation ( const UInt& iElem,
655  MatrixElemental& elmatMix,
656  MatrixElemental& elmatReactionTerm );
657 
658  //! Computes local (element dependent) vectors
659  /*!
660  Locally update the current finite element for the primal
661  and dual finite element space, then compute the Hdiv and L2 source
662  vectors.
663  @param iElem Id of the current geometrical element.
664  @param elvecMix The local vector in mixed form.
665  */
666  virtual void localVectorComputation ( const UInt& iElem,
667  VectorElemental& elvecMix );
668 
669  //! Performs static condensation
670  /*!
671  Locally eliminate pressure and velocity DOFs, create the local
672  hybrid matrix and local hybrid right hand side.
673  @param localMatrixHybrid The matrix which will store the hybrid local matrix.
674  @param localVectorHybrid The vector which will store the hybrid local vector.
675  @param elmatMix The local matrix in mixed form.
676  @param elmatReactionTerm The local matrix for the reaction term.
677  @param elvecMix The local vector in mixed form.
678  */
679  void staticCondensation ( MatrixElemental& localMatrixHybrid,
680  VectorElemental& localVectorHybrid,
681  MatrixElemental& elmatMix,
682  MatrixElemental& elmatReactionTerm,
683  VectorElemental& elvecMix );
684 
685  //! Compute locally, as a post process, the primal and dual variable given the hybrid.
686  /*!
687  @param localSolution A vector which stores the dual, primal and hybrid local solution.
688  @param elmatMix The local matrix in mixed form.
689  @param elmatReactionTerm The local matrix for the reaction term.
690  @param elvecMix The local vector in mixed form.
691  */
692  void localComputePrimalAndDual ( VectorElemental& localSolution,
693  MatrixElemental& elmatMix,
694  MatrixElemental& elmatReactionTerm,
695  VectorElemental& elvecMix );
696 
697  //! Do some computation after the calculation of the primal and dual variable.
698  /*!
699  The function is empty while it is useful in derived classes, i.e. DarcySolverTransient.
700  */
701  virtual void postComputePrimalAndDual () {};
702 
703  //! Update all problem variables
704  /*!
705  Update all the variables of the problem before the construction of
706  the global hybrid matrix, e.g. reset the global hybrid matrix.
707  It is principally used for a time dependent derived class, in fact we
708  want to clear each time step all the variables.
709  */
710  virtual void resetVariables ();
711 
712  //! Apply the boundary condition
713  /* Apply BC to the hybrid global matrix and to the hybrid global right hand side.
714  */
715  void applyBoundaryConditions ();
716 
717  //! Make matrix symmetric
718  /*!
719  Transform a symmetric matrix that is stored only in the lower
720  triangular part in a full symmetric matrix.
721  @param N The size of the matrix A.
722  @tparam A The matrix to be reordered.
723  */
724  template < typename MatrixType >
725  void symmetrizeMatrix ( Int N, MatrixType& A );
726 
727  //@}
728 
729  // Parallel stuff
730  //! @name Parallel stuff
731  //@{
732 
733  //! Displayer for parallel cout
735 
736  //@}
737 
738  // Data of the problem.
739  //! @name Data of the problem
740  //@{
741 
742  //! Data for Darcy solvers.
744 
745  //! Source function.
747 
748  //! Vector source function.
750 
751  //! Reaction term function.
753 
754  //! Inverse of the permeability tensor.
756 
757  //! Bondary conditions handler.
759 
760  //@}
761 
762  // Solution fields stuff.
763  //! @name Solution fields stuff
764  //@{
765 
766  //! Primal solution.
768 
769  //! Dual solution.
771 
772  //! Hybrid solution.
774 
775  //@}
776 
777  // Algebraic stuff.
778  //! @name Algebraic stuff
779  //@{
780 
781  //! Hybrid matrix.
782  matrixPtr_Type M_matrHybrid;
783 
784  //! Right hand side.
785  vectorPtr_Type M_rhs;
786 
787  //! Residual.
788  vectorPtr_Type M_residual;
789 
790  //! Linear solver.
792 
793  //! Epetra preconditioner for the linear system.
794  preconditionerPtr_Type M_prec;
795 
796  //@}
797 
798 }; // class DarcySolverLinear
799 
800 //
801 // IMPLEMENTATION
802 //
803 
804 // ===========================================================================================
805 // Public methods
806 // ==========================================================================================
807 
808 // Build the global hybrid matrix and global hybrid right hand side, with boundary conditions.
809 template < typename MeshType >
810 void
811 DarcySolverLinear < MeshType >::
813 {
814 
815  // Check if the primal field is set or not.
816  ASSERT ( M_primalField.get(), "DarcySolverLinear : primal field not set." );
817 
818  // Check if the dual field is set or not.
819  ASSERT ( M_dualField.get(), "DarcySolverLinear : dual field not set." );
820 
821  // Check if the hybrid field is set or not.
822  ASSERT ( M_hybridField.get(), "DarcySolverLinear : hybrid field not set." );
823 
824  // LifeChronos.
825  LifeChrono chronoStaticCondensation;
826  LifeChrono chronoAssemble;
827 
828  // The total number of elements in the mesh.
829  const UInt meshNumberOfElements = M_primalField->getFESpace().mesh()->numElements();
830 
831  // Check if the displayer is set or not.
832  ASSERT ( M_displayer.get(), "DarcySolverLinear : displayer not set." );
833 
834  M_displayer->leaderPrint ( "Perform Static Condensation..." );
835  chronoStaticCondensation.start();
836 
837  /* Elemental matrix for mixed hybrid matrix, maps [A | B | C] in
838  | A B C |
839  | B^T 0 0 |
840  | C^T 0 0 | */
841  const UInt primalNbDof = M_primalField->getFESpace().refFE().nbDof();
842  const UInt dualNbDof = M_dualField->getFESpace().refFE().nbDof();
843  const UInt hybridNbDof = M_hybridField->getFESpace().refFE().nbDof();
844 
845  MatrixElemental elmatMix ( dualNbDof, 1, 1,
846  primalNbDof, 0, 1,
847  hybridNbDof, 0, 1 );
848 
849  // Elemental vector for the source terms of the problem, lives in RTk(fe) + Qk(fe).
850  VectorElemental elvecMix ( dualNbDof, 1,
851  primalNbDof, 1 );
852 
853  // Elemental matrix for the reaction term.
854  MatrixElemental elmatReactionTerm ( primalNbDof, 1, 1 );
855 
856  // Elemental matrix stores the local hybrid matrix.
857  MatrixElemental localMatrixHybrid ( hybridNbDof, 1, 1 );
858 
859  // Elemental vector stores the local hybrid right hand side.
860  VectorElemental localVectorHybrid ( hybridNbDof, 1 );
861 
862  // Compute all the constant matrices, e.g. the matrix B and C
863  computeConstantMatrices ( elmatMix );
864 
865  // Prepare all the stuff before the loop on all the volume elements.
867 
868  //! Loop on all the volume elements.
869  for ( UInt iElem (0); iElem < meshNumberOfElements; ++iElem )
870  {
871 
872  // Clear the local hybrid matrix and the local hybrid right hand side.
873  localMatrixHybrid.zero();
874  localVectorHybrid.zero();
875 
876  // Compute the Hdiv mass matrix as a local matrix depending on the current element.
877  localMatrixComputation ( iElem, elmatMix, elmatReactionTerm );
878 
879  // Compute the source vectors as a local vectors depending on the current element.
880  localVectorComputation ( iElem, elvecMix );
881 
882  // Perform the static condensation to compute the local hybrid matrix and the local hybrid right hand side.
883  staticCondensation ( localMatrixHybrid, localVectorHybrid,
884  elmatMix, elmatReactionTerm, elvecMix );
885 
886  /* Assemble the global hybrid matrix.
887  M_primal_FESpace is used instead of M_hybridField_FESpace for currentLocalId,
888  because currentFE cannot store a ReferenceFEHybrid. */
889  assembleMatrix ( *M_matrHybrid,
890  M_primalField->getFESpace().fe().currentLocalId(),
891  localMatrixHybrid,
892  hybridNbDof,
893  M_hybridField->getFESpace().dof(),
894  0, 0, 0, 0 );
895 
896  /* Assemble the global hybrid right hand side.
897  M_primal_FESpace is used instead of M_hybridField_FESpace for currentLocalId,
898  because currentFE cannot store a ReferenceFEHybrid. */
899  assembleVector ( *M_rhs,
900  M_primalField->getFESpace().fe().currentLocalId(),
901  localVectorHybrid,
902  hybridNbDof,
903  M_hybridField->getFESpace().dof(), 0 );
904  }
905  //! End of loop volume operation.
906 
907  chronoStaticCondensation.stop();
908  M_displayer->leaderPrintMax ( " done in " , chronoStaticCondensation.diff() );
909 
910  M_displayer->leaderPrint ( "Apply boundary conditions and assemble global matrix and vector..." );
911 
912  chronoAssemble.start();
913 
914  // Apply boundary conditions to the hybrid global matrix and to the hybrid global right hand side.
916 
917  // Assemble the global hybrid matrix.
918  M_matrHybrid->globalAssemble();
919 
920  // Assemble the global hybrid vector.
921  M_rhs->globalAssemble();
922 
923  chronoAssemble.stop();
924 
925  M_displayer->leaderPrintMax ( " done in " , chronoAssemble.diff() );
926 
927 } // buildSystem
928 
929 // Set up the linear solver and the preconditioner.
930 template < typename MeshType >
931 void
932 DarcySolverLinear < MeshType >::
934 {
935  // Setup the linear solver.
936  M_linearSolver.setParameters ( M_data->linearSolverList() );
937  M_linearSolver.setCommunicator ( M_displayer->comm() );
938 
939  // Choose the preconditioner type.
940  const std::string precType = M_data->preconditionerList().template get<std::string> ( "prectype" );
941 
942  // Create a preconditioner object.
943  M_prec.reset ( PRECFactory::instance().createObject ( precType ) );
944  ASSERT ( M_prec.get() != 0, "DarcySolverLinear : Preconditioner not set" );
945 
946  // Set the data for the preconditioner.
947  M_prec->setParametersList ( M_data->preconditionerList().sublist ( precType ) );
948 } // setup
949 
950 // Solve the linear system.
951 template < typename MeshType >
952 void
953 DarcySolverLinear < MeshType >::
955 {
956 
957  // Set the matrix.
958  M_linearSolver.setOperator ( M_matrHybrid );
959 
960  // Set the righthand side.
961  M_linearSolver.setRightHandSide ( M_rhs );
962 
963  // Set and build the preconditioner.
964  M_linearSolver.setPreconditioner ( M_prec );
965  M_linearSolver.buildPreconditioner ();
966 
967  // Create the solution vector, it has to be of Unique type.
968  vectorPtr_Type solution ( new vector_Type ( M_hybridField->getFESpace().map(), Unique ) );
969 
970  // Solve the linear system.
971  M_linearSolver.solve ( solution );
972 
973  // Save the solution into the hybrid variable.
974  M_hybridField->setVector ( *solution );
975 
976 } // solveLinearSystem
977 
978 // Compute primal and dual unknown as a post process.
979 template < typename MeshType >
980 void
981 DarcySolverLinear < MeshType >::
983 {
984 
985  // LifeChrono.
986  LifeChrono chronoComputePrimalAndDual;
987 
988  M_displayer->leaderPrint ( "Compute pressure and flux..." );
989  chronoComputePrimalAndDual.start();
990 
991  // The total number of elements in the mesh.
992  const UInt meshNumberOfElements = M_primalField->getFESpace().mesh()->numElements();
993 
994  // Number of local faces for the geometrical element
995  const UInt elementNumberFacets = mesh_Type::element_Type::S_numFacets;
996 
997  /*==========================================
998  POST PROCESSING
999  compute the pressure (Qk or Pk / element)
1000  and the velocity (RTk / element) => 2 (opposite) velocities / face
1001  ==========================================*/
1002 
1003  /* The vector M_hybridField can be scalar field with an unique epetra vector, so it does not share one layer elements.
1004  The reconstruction of the primal and dual variabile need this share, so we create a repeated
1005  epetra vector. This operation maximize the efficiency of send/receive time cost instead to
1006  send and receive each time a single datum. */
1007  vector_Type hybrid_Repeated ( M_hybridField->getVector(), Repeated );
1008 
1009  // Clean the vector for the primal and the dual variable
1010  M_primalField->cleanField();
1011  M_dualField->cleanField();
1012 
1013  /* Elemental matrix for mixed hybrid matrix, maps [A | B | C] in
1014  | A B C |
1015  | B^T 0 0 |
1016  | C^T 0 0 | */
1017  const UInt primalNbDof = M_primalField->getFESpace().refFE().nbDof();
1018  const UInt dualNbDof = M_dualField->getFESpace().refFE().nbDof();
1019  const UInt hybridNbDof = M_hybridField->getFESpace().refFE().nbDof();
1020 
1021  MatrixElemental elmatMix ( dualNbDof, 1, 1,
1022  primalNbDof, 0, 1,
1023  hybridNbDof, 0, 1 );
1024 
1025  // Elemental vector for the source terms of the problem, lives in RTk(fe) + Qk(fe).
1026  VectorElemental elvecMix ( dualNbDof, 1,
1027  primalNbDof, 1 );
1028 
1029  // Elemental matrix for the reaction term.
1030  MatrixElemental elmatReactionTerm ( primalNbDof, 1, 1 );
1031 
1032  // Compute all the constant matrices, e.g. the matrix B and C
1033  computeConstantMatrices ( elmatMix );
1034 
1035  // Element vector stores the local solution: (dual, primal, hybrid).
1036  VectorElemental localSolution ( dualNbDof, 1,
1037  primalNbDof, 1,
1038  hybridNbDof, 1 );
1039 
1040  //! Loop on all the volume elements.
1041  for ( UInt iElem (0); iElem < meshNumberOfElements; ++iElem )
1042  {
1043  // Clear the local solution vector.
1044  localSolution.zero();
1045 
1046  // Compute the Hdiv mass matrix as a local matrix depending on the current element.
1047  localMatrixComputation ( iElem, elmatMix, elmatReactionTerm );
1048 
1049  // Compute the source vectors as local vector depending on the current element.
1050  localVectorComputation ( iElem, elvecMix );
1051 
1052  // Extract the computed hybrid variable for the current finite element and put it into localHybrid.
1053  extract_vec ( hybrid_Repeated,
1054  localSolution,
1055  M_hybridField->getFESpace().refFE (),
1056  M_hybridField->getFESpace().dof (),
1057  M_primalField->getFESpace().fe().currentLocalId (), 2 );
1058 
1059  // Given the local hybrid variable, computes locally the primal and dual variable.
1060  localComputePrimalAndDual ( localSolution, elmatMix, elmatReactionTerm, elvecMix );
1061 
1062  // Put the primal variable of the current finite element in the global vector M_primalField.
1063  assembleVector ( M_primalField->getVector (),
1064  M_primalField->getFESpace().fe().currentLocalId (),
1065  localSolution,
1066  primalNbDof,
1067  M_primalField->getFESpace().dof (), 1 );
1068 
1069  for ( UInt iLocalFacet (0); iLocalFacet < elementNumberFacets; ++iLocalFacet )
1070  {
1071  const UInt iGlobalFacet ( M_dualField->getFESpace().mesh()->localFacetId ( iElem, iLocalFacet ) );
1072  if ( M_dualField->getFESpace().mesh()->facet ( iGlobalFacet ).firstAdjacentElementIdentity() != iElem )
1073  {
1074  localSolution.block ( 0 ) [ iLocalFacet ] = 0.;
1075  }
1076  }
1077 
1078  // Put the dual variable of the current finite element in the global vector M_dualField.
1079  assembleVector ( M_dualField->getVector (),
1080  M_dualField->getFESpace().fe().currentLocalId (),
1081  localSolution,
1082  dualNbDof,
1083  M_dualField->getFESpace().dof (), 0 );
1084 
1085  }
1086  //! End of loop on the volume elements.
1087 
1088  // Assemble the primal variable.
1089  M_primalField->getVector().globalAssemble ();
1090 
1091  // It is wrong to assemble the dual variable, no communications required.
1092 
1094 
1095  chronoComputePrimalAndDual.stop ();
1096  M_displayer->leaderPrintMax ( " done in " , chronoComputePrimalAndDual.diff() );
1097 
1098 } // computePrimalAndDual
1099 
1100 // Solve the Darcy problem.
1101 template < typename MeshType >
1102 void
1103 DarcySolverLinear < MeshType >::
1105 {
1106  // Create the hybrid system using the static condensation.
1107  buildSystem ();
1108 
1109  // Solve the linear system.
1111 
1112  // Given the hybrid solution computes the primal and dual solutions.
1114 
1115 } // solve
1116 
1117 // ==============================================================================
1118 // Protected methods
1119 // ==============================================================================
1120 
1121 // Compute all the constant matrices.
1122 template < typename MeshType >
1123 void
1124 DarcySolverLinear < MeshType >::
1125 computeConstantMatrices ( MatrixElemental& elmatMix )
1126 {
1127 
1128  // Clean the local matrix which will store the matrix B.
1129  elmatMix.block ( 0, 1 ) = static_cast<Real> (0.);
1130 
1131  // Clean the local matrix which will store the matrix C.
1132  elmatMix.block ( 0, 2 ) = static_cast<Real> (0.);
1133 
1134  /* Update the divergence matrix, it is independent of the current element
1135  thanks to the Piola transform. */
1136  AssemblyElemental::grad_Hdiv ( static_cast<Real> (1.), elmatMix, M_dualField->getFESpace().fe(),
1137  M_primalField->getFESpace().fe(), 0, 1 );
1138 
1139  // Select the correct element which represent ( RT0 \cdot N ) * Hybrid.
1140  const ReferenceFEHybrid* feRT0VdotNHyb = 0;
1141 
1142  // Selection, in the opt mode the switch is suppressed.
1143  switch ( mesh_Type::elementShape_Type::S_shape )
1144  {
1145  case TRIANGLE:
1146  feRT0VdotNHyb = &feTriaRT0VdotNHyb;
1147  break;
1148  case TETRA:
1149  feRT0VdotNHyb = &feTetraRT0VdotNHyb;
1150  break;
1151  case HEXA:
1152  feRT0VdotNHyb = &feHexaRT0VdotNHyb;
1153  break;
1154  default:
1155  ASSERT ( false, "DarcySolverLinear : Hybrid finite element not found." );
1156  }
1157 
1158  /* Update the boundary matrix, it is independent of the current element
1159  thanks to the Piola transform.
1160  Here we use the fact that a RefHybridFE "IS A" ReferenceFE and the method refFE of
1161  a FESpace object. In fact the method refFE return a const ReferenceFE&, but the function
1162  TP_VdotN_Hdiv takes two const RefHybridFE& so we must cast a const ReferenceFE&
1163  to a const RefHybridFE&. The cast of type is static and uses pointers. */
1164  AssemblyElemental::TP_VdotN_Hdiv ( 1., elmatMix,
1165  *static_cast < const ReferenceFEHybrid* > (& ( M_hybridField->getFESpace().refFE() ) ),
1166  *feRT0VdotNHyb, 0, 2 );
1167 
1168 } // computeConstantMatrices
1169 
1170 // Update the primal and dual variable at the current element and compute the element Hdiv mass matrix.
1171 template < typename MeshType >
1172 void
1173 DarcySolverLinear < MeshType >::
1174 localMatrixComputation ( const UInt& iElem, MatrixElemental& elmatMix,
1175  MatrixElemental& elmatReactionTerm )
1176 {
1177  // Element of current id.
1178  const typename mesh_Type::element_Type& element = M_primalField->getFESpace().mesh()->element ( iElem );
1179 
1180  /* Modify the (0,0) block (A) of the matrix elmatMix. The blocks (0,1) (B)
1181  and (0,2) (C) are independent of the element and have already been computed. */
1182 
1183  // Only one block is set to zero since the other ones are not recomputed.
1184  elmatMix.block ( 0, 0 ) = 0.;
1185 
1186  // Update the current element of ID iElem for the dual variable.
1187  M_dualField->getFESpace().fe().update ( element, UPDATE_PHI_VECT | UPDATE_WDET );
1188 
1189  // Get the coordinate of the barycenter of the current element of ID iElem.
1190  Vector3D barycenter;
1191  M_dualField->getFESpace().fe().barycenter ( barycenter[0], barycenter[1], barycenter[2] );
1192 
1193  // Check if the inverse of permeability is set or not.
1194  ASSERT ( M_inversePermeabilityFct.get(), "DarcySolverLinear : inverse of the permeability tensor not set." );
1195 
1196  // Computes the value of the permeability tensor.
1197  const Matrix permeabilityValue = M_inversePermeabilityFct->eval ( iElem, barycenter, M_data->dataTimePtr()->time() );
1198 
1199  /* Compute the Hdiv mass matrix. We pass the time at the inverse of the permeability
1200  because the DarcySolverTransient needs the permeability time dependent. In this case
1201  we do not have a time evolution. */
1202  AssemblyElemental::mass_Hdiv ( permeabilityValue, elmatMix, M_dualField->getFESpace().fe(), 0, 0 );
1203 
1204  // Check if the reaction term is set or not.
1205  ASSERT ( M_reactionTermFct.get(), "DarcySolverLinear : reaction term not set." );
1206 
1207  // Clean the reaction matrix.
1208  elmatReactionTerm.zero();
1209 
1210  // Computes the value for the reaction term.
1211  const Real reactionValue = M_reactionTermFct->eval ( iElem, barycenter, M_data->dataTimePtr()->time() );
1212 
1213  // Update the current element of ID iElem for the primal variable.
1214  M_primalField->getFESpace().fe().update ( element, UPDATE_WDET );
1215 
1216  // Compute the reaction matrix.
1217  AssemblyElemental::mass ( reactionValue, elmatReactionTerm, M_primalField->getFESpace().fe(), 0, 0 );
1218 
1219 } // localMatrixComputation
1220 
1221 // Update the primal and dual variable at the current element and compute the element Hdiv mass matrix.
1222 template < typename MeshType >
1223 void
1224 DarcySolverLinear < MeshType >::
1225 localVectorComputation ( const UInt& iElem, VectorElemental& elvecMix )
1226 {
1227  // Element of current id.
1228  const typename mesh_Type::element_Type& element = M_primalField->getFESpace().mesh()->element ( iElem );
1229 
1230  // Update the current element of ID iElem only for the dual variable.
1231  M_dualField->getFESpace().fe().update ( element, UPDATE_PHI_VECT | UPDATE_WDET );
1232 
1233  // Get the coordinate of the barycenter of the current element of ID iElem.
1234  Vector3D barycenter;
1235  M_dualField->getFESpace().fe().barycenter ( barycenter[0], barycenter[1], barycenter[2] );
1236 
1237  // Clear the source vector.
1238  elvecMix.zero();
1239 
1240  // Check if the vector source term is set or not.
1241  ASSERT ( M_vectorSourceFct.get(), "DarcySolverLinear : vector source term not set." );
1242 
1243  // Computes the value of the vector source.
1244  const Vector vectorSourceValue = M_vectorSourceFct->eval ( iElem, barycenter, M_data->dataTimePtr()->time() );
1245 
1246  // Compute the vector source term.
1247  AssemblyElemental::source_Hdiv ( vectorSourceValue, elvecMix, M_dualField->getFESpace().fe(), 0 );
1248 
1249  // Check if the scalar source term is set or not.
1250  ASSERT ( M_scalarSourceFct.get(), "DarcySolverLinear : scalar source term not set." );
1251 
1252  // Computes the scalar source.
1253  const Real scalarSourceValue = M_scalarSourceFct->eval ( iElem, barycenter, M_data->dataTimePtr()->time() );
1254 
1255  /* Update the current element of ID iElem only for the primal variable,
1256  it is used for computing the source term. */
1257  M_primalField->getFESpace().fe().update ( element, UPDATE_WDET );
1258 
1259  // Compute the scalar source term.
1260  AssemblyElemental::source ( scalarSourceValue, elvecMix, M_primalField->getFESpace().fe(), 1 );
1261 
1262 } // localVectorComputation
1263 
1264 // Perform the static condensation for the local hybrid matrix.
1265 template < typename MeshType >
1266 void
1267 DarcySolverLinear < MeshType >::
1268 staticCondensation ( MatrixElemental& localMatrixHybrid,
1269  VectorElemental& localVectorHybrid,
1270  MatrixElemental& elmatMix,
1271  MatrixElemental& elmatReactionTerm,
1272  VectorElemental& elvecMix )
1273 {
1274 
1275  // LAPACK wrapper of Epetra.
1276  Epetra_LAPACK lapack;
1277 
1278  // BLAS wrapper of Epetra.
1279  Epetra_BLAS blas;
1280 
1281  // Flags for the BLAS and LAPACK routine.
1282  Int INFO[1] = {0};
1283 
1284  // Number of columns of the right hand side := 1.
1285  const Int NBRHS = 1;
1286  // Primal variable degrees of freedom.
1287  const Int primalNbDof = M_primalField->getFESpace().refFE().nbDof();
1288  // Dual variable degrees of freedom.
1289  const Int dualNbDof = M_dualField->getFESpace().refFE().nbDof();
1290  // Hybrid variable degree of freedom.
1291  const Int hybridNbDof = M_hybridField->getFESpace().refFE().nbDof();
1292 
1293  const Real ONE = 1.0;
1294  const Real MINUSONE = -1.0;
1295  const Real ZERO = 0.0;
1296 
1297  // Parameter that indicate the Lower storage of matrices.
1298  const char UPLO = 'L';
1299 
1300  // Paramater that indicate the Transpose of matrices.
1301  const char TRANS = 'T';
1302  const char NOTRANS = 'N';
1303 
1304  // Parameter that indicates whether the matrix has diagonal unit ('N' means no).
1305  const char NODIAG = 'N';
1306 
1307  // Create and assign the local matrices A, B and C.
1308  MatrixElemental::matrix_type A = elmatMix.block ( 0, 0 );
1309  MatrixElemental::matrix_type B = elmatMix.block ( 0, 1 );
1310  MatrixElemental::matrix_type C = elmatMix.block ( 0, 2 );
1311 
1312  // Create and assign the local vectors fv and fp.
1313  VectorElemental::super fv = elvecMix.block ( 0 );
1314  VectorElemental::super fp = elvecMix.block ( 1 );
1315 
1316  // Create local matrices.
1317  MatrixElemental::matrix_type BtB ( primalNbDof, primalNbDof );
1318  MatrixElemental::matrix_type CtC ( hybridNbDof, hybridNbDof );
1319  MatrixElemental::matrix_type BtC ( primalNbDof, hybridNbDof );
1320 
1321  // Clean the local matrices.
1322  BtB *= 0.;
1323  CtC *= 0.;
1324  BtC *= 0.;
1325 
1326  //! Matrix operations.
1327  /* Put in A the matrix L and L^T, where L and L^T is the Cholesky factorization of A.
1328  For more details see http://www.netlib.org/lapack/double/dpotrf.f */
1329  lapack.POTRF ( UPLO, dualNbDof, A, dualNbDof, INFO );
1330  ASSERT_PRE ( !INFO[0], "Lapack factorization of A is not achieved." );
1331 
1332  /* Put in B the matrix L^{-1} * B, solving a triangular system.
1333  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1334  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, dualNbDof, primalNbDof, A, dualNbDof, B, dualNbDof, INFO );
1335  ASSERT_PRE ( !INFO[0], "Lapack Computation B = L^{-1} B is not achieved." );
1336 
1337  /* Put in C the matrix L^{-1} * C, solving a triangular system.
1338  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1339  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, dualNbDof, hybridNbDof, A, dualNbDof, C, hybridNbDof, INFO );
1340  ASSERT_PRE ( !INFO[0], "Lapack Computation C = L^{-1} C is not achieved." );
1341 
1342  /* Put in BtB the matrix B^T * L^{-T} * L^{-1} * B = B^T * A^{-1} * B
1343  BtB stored only on lower part.
1344  For more details see http://www.netlib.org/lapack/lapack-3.1.1/BLAS/SRC/dsyrk.f */
1345  blas.SYRK ( UPLO, TRANS, primalNbDof, dualNbDof, ONE, B, dualNbDof, ZERO, BtB, primalNbDof );
1346 
1347  /* Put in BtB the matrix
1348  BtB + M_elmatReactionTerm = B^T * A^{-1} * B + elmatReactionTerm
1349  BtB stored only on lower part. */
1350  BtB += elmatReactionTerm.mat();
1351 
1352  /* Put in CtC the matrix C^T * L^{-T} * L^{-1} * C = C^T * A^{-1} * C
1353  CtC stored only on lower part.
1354  For more details see http://www.netlib.org/slatec/lin/dsyrk.f */
1355  blas.SYRK ( UPLO, TRANS, hybridNbDof, dualNbDof, ONE, C, dualNbDof, ZERO, CtC, hybridNbDof );
1356 
1357  /* Put in BtC the matrix B^T * L^{-T} * L^{-1} * C = B^T * A^{-1} * C
1358  BtC fully stored.
1359  For more details see http://www.netlib.org/blas/dgemm.f */
1360  blas.GEMM ( TRANS, NOTRANS, primalNbDof, hybridNbDof, dualNbDof, ONE, B, dualNbDof, C, dualNbDof,
1361  ZERO, BtC, primalNbDof );
1362 
1363  /* Put in BtB the matrix LB and LB^T where LB and LB^T is the cholesky
1364  factorization of B^T * A^{-1} * B + elmatReactionTerm.
1365  For more details see http://www.netlib.org/lapack/double/dpotrf.f */
1366  lapack.POTRF ( UPLO, primalNbDof, BtB, primalNbDof, INFO );
1367  ASSERT_PRE ( !INFO[0], "Lapack factorization of BtB is not achieved." );
1368 
1369  /* Put in BtC the matrix LB^{-1} * BtC = LB^{-1} * B^T * A^{-1} * C.
1370  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1371  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, primalNbDof, hybridNbDof, BtB, primalNbDof, BtC, primalNbDof, INFO );
1372  ASSERT_PRE ( !INFO[0], "Lapack Computation BtC = LB^{-1} BtC is not achieved." );
1373 
1374  /* Put in CtC the matrix -CtC + BtC^T * BtC
1375  Result stored only on lower part, the matrix CtC stores
1376  -C^T * A^{-1} * C + C^T * A^{-t} * B * ( B^T * A^{-1} * B + elmatReactionTerm )^{-1} * B^T * A^{-1} * C.
1377  For more details see http://www.netlib.org/slatec/lin/dsyrk.f */
1378  blas.SYRK ( UPLO, TRANS, hybridNbDof, primalNbDof, ONE, BtC, primalNbDof, MINUSONE, CtC, hybridNbDof );
1379 
1380  //! End of matrix operations.
1381 
1382  /*
1383  Sum up of the previews steps
1384  A stores L and L^T where L and L^T is the Cholesky factorization of A
1385  B stores L^{-1} * B
1386  C stores L^{-1} * C
1387  B^T stores LB and LB^T where LB and LB^T is the factorization of B^T * A^{-1} * B + elmatReactionTerm
1388  BtC stores LB^{-1} * B^T * A^{-1} * C
1389  CtC stores -C^T * A^{-1} * C + C^T * A^{-t} * B * ( B^T * A^{-1} * B + elmatReactionTerm )^{-1} * B^T * A^{-1} * C
1390  */
1391 
1392  //! Vector operations.
1393 
1394  /* Put in fp the vector LB^{-1} * fp = LB^{-1} Fp
1395  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1396  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, primalNbDof, NBRHS, BtB, primalNbDof, fp, primalNbDof, INFO );
1397  ASSERT_PRE ( !INFO[0], "Lapack Computation fp = LB^{-1} fp is not achieved." );
1398 
1399  /* Put in localVectorHybrid the vector BtC^T * fp =
1400  C^T * A^{-1} * B^T * ( B^T * A^{-1} * B + elmatReactionTerm )^{-1} * Fp
1401  localVectorHybrid is fully stored.
1402  For more details see http://www.netlib.org/blas/dgemm.f */
1403  blas.GEMM ( TRANS, NOTRANS, hybridNbDof, NBRHS, primalNbDof, ONE, BtC, primalNbDof, fp, primalNbDof,
1404  ZERO, localVectorHybrid, hybridNbDof );
1405 
1406  /* Put in fv the vector L^{-1} * fv = L^{-1} * Fv, solving a triangular system.
1407  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1408  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, dualNbDof, NBRHS, A, dualNbDof, fv, dualNbDof, INFO );
1409  ASSERT_PRE ( !INFO[0], "Lapack Computation fv = L^{-1} fv is not achieved." );
1410 
1411  /* Put in localVectorHybrid the vector - C^T * fv + localVectorHybrid =
1412  = C^T * A^{-1} * ( B^T * ( B^T * A^{-1} * B + elmatReactionTerm )^{-1} * Fp - Fv )
1413  localVectorHybrid is fully stored.
1414  For more details see http://www.netlib.org/blas/dgemm.f */
1415  blas.GEMM ( TRANS, NOTRANS, hybridNbDof, NBRHS, hybridNbDof, MINUSONE, C, hybridNbDof, fv, dualNbDof,
1416  ONE, localVectorHybrid, hybridNbDof );
1417 
1418  /* Put in fp the vector B^T * L^{-T} * fv = B^T * A^{-1} * Fv
1419  fp fully stored.
1420  For more details see http://www.netlib.org/blas/dgemm.f */
1421  blas.GEMM ( TRANS, TRANS, primalNbDof, NBRHS, dualNbDof, ONE, B, dualNbDof, fv, NBRHS, ZERO, fp, NBRHS );
1422 
1423  /* Put in fp the vector LB^{-1} * fp = LB^{-1} * B^T * A^{-1} * Fv
1424  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1425  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, primalNbDof, NBRHS, BtB, primalNbDof, fp, NBRHS, INFO );
1426  ASSERT_PRE ( !INFO[0], "Lapack Computation fp = LB^{-1} rhs is not achieved." );
1427 
1428  /* Put in M_elvecHyb the vector BtC^T * fp + localVectorHybrid =
1429  C^T * A^{-1} * [ B^T * ( B^T * A^{-1} * B + elmatReactionTerm )^{-1} * ( B^T * A^{-1} + Fp ) - Fv ]
1430  localVectorHybrid is fully stored.
1431  For more details see http://www.netlib.org/blas/dgemm.f */
1432  blas.GEMM ( TRANS, NOTRANS, hybridNbDof, NBRHS, primalNbDof, ONE, BtC, primalNbDof, fp, NBRHS, ONE,
1433  localVectorHybrid, hybridNbDof );
1434 
1435  //! End of vector operations.
1436 
1437  /* Previously the matrix CtC is stored only in the lower part, but at the moment there is not
1438  a function assembleMatrix that store a lower triangular sparse matrix.
1439  Remind to correct these line in the future. */
1440  symmetrizeMatrix ( hybridNbDof, CtC );
1441 
1442  // Update the hybrid element matrix.
1443  localMatrixHybrid.block (0, 0) = CtC;
1444 
1445 } // staticCondensation
1446 
1447 // Locally compute the primal and dual variable.
1448 template < typename MeshType >
1449 void
1450 DarcySolverLinear < MeshType >::
1451 localComputePrimalAndDual ( VectorElemental& localSolution,
1452  MatrixElemental& elmatMix,
1453  MatrixElemental& elmatReactionTerm,
1454  VectorElemental& elvecMix )
1455 {
1456 
1457  // LAPACK wrapper of Epetra
1458  Epetra_LAPACK lapack;
1459 
1460  // BLAS wrapper of Epetra
1461  Epetra_BLAS blas;
1462 
1463  // Flags for the BLAS and LAPACK routine.
1464 
1465  Int INFO[1] = {0};
1466 
1467  // Number of columns of the right hand side := 1.
1468  const Int NBRHS = 1;
1469  // Primal variable degrees of freedom.
1470  const Int primalNbDof = M_primalField->getFESpace().refFE().nbDof();
1471  // Dual variable degrees of freedom.
1472  const Int dualNbDof = M_dualField->getFESpace().refFE().nbDof();
1473  // Hybrid variable degree of freedom.
1474  const Int hybridNbDof = M_hybridField->getFESpace().refFE().nbDof();
1475 
1476  const Real ONE = 1.0;
1477  const Real MINUSONE = -1.0;
1478  const Real ZERO = 0.0;
1479 
1480  // Parameter that indicate the Lower storage of matrices.
1481  const char UPLO = 'L';
1482  // Parameter that indicate the Transpose of matrices.
1483  const char TRANS = 'T';
1484  const char NOTRANS = 'N';
1485  // Parameter that indicates whether the matrix has diagonal unit ('N' means no)
1486  const char NODIAG = 'N';
1487 
1488  // No need for CtC in this part, and last dsyrk, the only differences.
1489  MatrixElemental::matrix_type A = elmatMix.block ( 0, 0 );
1490  MatrixElemental::matrix_type B = elmatMix.block ( 0, 1 );
1491  MatrixElemental::matrix_type C = elmatMix.block ( 0, 2 );
1492 
1493  VectorElemental::super fv = elvecMix.block ( 0 );
1494  VectorElemental::super fp = elvecMix.block ( 1 );
1495 
1496  // Matrix Operations
1497 
1498  // Create local matrices.
1499  MatrixElemental::matrix_type BtB ( primalNbDof, primalNbDof );
1500  MatrixElemental::matrix_type BtC ( primalNbDof, hybridNbDof );
1501 
1502  // Clean the local matrices.
1503  BtB *= 0.;
1504  BtC *= 0.;
1505 
1506  // Matrix Operations
1507 
1508  /* Put in A the matrix L and L^T, where L and L^T is the Cholesky factorization of A.
1509  For more details see http://www.netlib.org/lapack/double/dpotrf.f */
1510  lapack.POTRF ( UPLO, dualNbDof, A, dualNbDof, INFO );
1511  ASSERT_PRE ( !INFO[0], "Lapack factorization of A is not achieved." );
1512 
1513  /* Put in B the matrix L^{-1} * B, solving a triangular system.
1514  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1515  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, dualNbDof, primalNbDof, A, dualNbDof, B, dualNbDof, INFO );
1516  ASSERT_PRE ( !INFO[0], "Lapack Computation B = L^{-1} B is not achieved." );
1517 
1518  /* Put in C the matrix L^{-1} * C, solving a triangular system.
1519  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1520  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, dualNbDof, hybridNbDof, A, dualNbDof, C, dualNbDof, INFO );
1521  ASSERT_PRE ( !INFO[0], "Lapack Computation C = L^{-1} C is not achieved." );
1522 
1523  /* Put in BtB the matrix B^T * L^{-T} * L^{-1} * B = B^T * A^{-1} * B
1524  BtB stored only on lower part.
1525  For more details see http://www.netlib.org/slatec/lin/dsyrk.f */
1526  blas.SYRK ( UPLO, TRANS, primalNbDof, dualNbDof, ONE, B, dualNbDof, ZERO, BtB, primalNbDof );
1527 
1528  /* Put in BtB the matrix
1529  BtB + elmatReactionTerm = B^T * A^{-1} * B + elmatReactionTerm
1530  BtB stored only on lower part. */
1531  BtB += elmatReactionTerm.mat();
1532 
1533  /* Put in BtC the matrix B^T * L^{-T} * L^{-1} * C = B^T * A^{-1} * C
1534  BtC fully stored.
1535  For more details see http://www.netlib.org/blas/dgemm.f */
1536  blas.GEMM ( TRANS, NOTRANS, primalNbDof, hybridNbDof, dualNbDof, ONE, B, dualNbDof, C,
1537  dualNbDof, ZERO, BtC, primalNbDof );
1538 
1539  /* Put in BtB the matrix LB and LB^T where LB and LB^T is the cholesky
1540  factorization of B^T * A^{-1} * B + elmatReactionTerm.
1541  For more details see http://www.netlib.org/lapack/double/dpotrf.f */
1542  lapack.POTRF ( UPLO, primalNbDof, BtB, primalNbDof, INFO );
1543  ASSERT_PRE ( !INFO[0], "Lapack factorization of BtB is not achieved." );
1544 
1545  /* Put in BtC the matrix LB^{-1} * BtC = LB^{-1} * B^T * A^{-1} * C.
1546  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1547  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, primalNbDof, hybridNbDof, BtB, primalNbDof, BtC, primalNbDof, INFO );
1548  ASSERT_PRE ( !INFO[0], "Lapack Computation BtC = LB^{-1} BtC is not achieved." );
1549 
1550  //! End of matrix operations.
1551 
1552  /* Sum up of the previews steps
1553  A stores L and L^T where L and L^T is the Cholesky factorization of A
1554  B stores L^{-1} * B
1555  C stores L^{-1} * C
1556  BtB stores LB and LB^T where LB and LB^T is the factorization of
1557  B^T * A^{-1} * B + elmatReactionTerm
1558  BtC stores LB^{-1} * B^T * A^{-1} * C
1559  */
1560 
1561  //! Vector operations, computation of primal and dual variable.
1562 
1563  //! Computation of the primal variable
1564 
1565  // Save in localDual the values of fv useful for the dual variable.
1566  localSolution.block ( 0 ) = fv;
1567 
1568  /* Put in fv the vector L^{-1} * fv, solving a triangular system.
1569  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1570  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, dualNbDof, NBRHS, A, dualNbDof, fv, dualNbDof, INFO );
1571  ASSERT_PRE ( !INFO[0], "Lapack Computation fv = L^{-1} fv is not achieved." );
1572 
1573  /* Put in fp the vector B^T * L^{-T} * fv + fp = B^T * A^{-1} * fv + fp
1574  fp fully stored.
1575  For more details see http://www.netlib.org/blas/dgemm.f */
1576  blas.GEMM ( TRANS, TRANS, primalNbDof, NBRHS, dualNbDof, ONE, B, dualNbDof, fv, NBRHS, ONE, fp, NBRHS );
1577 
1578  /* Put in fp the vector LB^{-1} * fp = LB^{-1} * ( B^T * A^{-1} * fv + fp )
1579  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1580  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, primalNbDof, NBRHS, BtB, primalNbDof, fp, primalNbDof, INFO );
1581  ASSERT_PRE ( !INFO[0], "Lapack Computation fp = LB^{-1} fp is not achieved." );
1582 
1583  /* Put in fp the vector
1584  BtC * localHybrid + fp = LB^{-1} * ( B^T * A^{-1} * C * lambda_K - B^T * A^{-1} * fv - fp )
1585  For more details see http://www.netlib.org/blas/dgemm.f */
1586  blas.GEMM ( NOTRANS, NOTRANS, primalNbDof, NBRHS, hybridNbDof, MINUSONE, BtC, primalNbDof,
1587  localSolution.block ( 2 ), hybridNbDof, MINUSONE, fp, primalNbDof );
1588 
1589  /* Put in fp the vector LB^{-T} * fp, where fp stores
1590  - ( B^T * A^{-1} * B + elmatReactionTerm )^{-1} * [ B^T * A^{-1} * ( C * lambda_K - fv ) - fp ]
1591  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1592  lapack.TRTRS ( UPLO, TRANS, NODIAG, primalNbDof, NBRHS, BtB, primalNbDof, fp, primalNbDof, INFO );
1593  ASSERT_PRE ( !INFO[0], "Lapack Computation fp = LB^{-T} fp is not achieved." );
1594 
1595  // Copy the local primal stored in fp into the localPrimal.
1596  localSolution.block ( 1 ) = fp;
1597 
1598  //! Computation of the dual variable.
1599 
1600  /* Put in localDual the vector L^{-1} * fv, solving a triangular system.
1601  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1602  lapack.TRTRS ( UPLO, NOTRANS, NODIAG, dualNbDof, NBRHS, A, dualNbDof, localSolution.block ( 0 ), dualNbDof, INFO );
1603  ASSERT_PRE ( !INFO[0], "Lapack Computation localDual = L^{-1} localDual is not achieved." );
1604 
1605  /* Put in localDual the vector B * localPrimal - localDual = L^{-1} * ( B * primal_K - fv )
1606  For more details see http://www.netlib.org/slatec/lin/dgemv.f */
1607  blas.GEMV ( NOTRANS, dualNbDof, primalNbDof, ONE, B, dualNbDof, localSolution.block ( 1 ),
1608  MINUSONE, localSolution.block ( 0 ) );
1609 
1610  /* Put in localDual the vector - C * localHybrid - localDual =
1611  = - L^{-1} * ( C * lambda_K + B^T * primal_K - fv )
1612  For more details see http://www.netlib.org/slatec/lin/dgemv.f */
1613  blas.GEMV ( NOTRANS, dualNbDof, hybridNbDof, MINUSONE, C, hybridNbDof, localSolution.block ( 2 ),
1614  MINUSONE, localSolution.block ( 0 ) );
1615 
1616  /* Put in localDual the vector L^{-T} * localDual =
1617  = - A^{-1} ( C^T * lambda_K - B^T * primal_K + fv )
1618  For more details see http://www.netlib.org/lapack/lapack-3.1.1/SRC/dtrtrs.f */
1619  lapack.TRTRS ( UPLO, TRANS, NODIAG, dualNbDof, NBRHS, A, dualNbDof, localSolution.block ( 0 ), dualNbDof, INFO );
1620  ASSERT_PRE ( !INFO[0], "Lapack Computation localDual = L^{-T} localDual is not achieved.");
1621 
1622  //! End of vector computation.
1623 
1624 } // localComputePrimalAndDual
1625 
1626 // Update all the variables of the problem.
1627 template < typename MeshType >
1628 void
1629 DarcySolverLinear < MeshType >::
1631 {
1632 
1633  const map_Type& problemMap = M_hybridField->getFESpace().map();
1634 
1635  // Reset the global hybrid matrix.
1636  M_matrHybrid.reset ( new matrix_Type ( problemMap ) );
1637 
1638  // Reset the global right hand side vector
1639  M_rhs.reset ( new vector_Type ( problemMap ) );
1640 
1641  // Reset the global residual vector
1642  M_residual.reset ( new vector_Type ( problemMap ) );
1643 
1644  // Reset the global primal vector
1645  M_primalField->cleanField();
1646 
1647  // Reset the global dual vector
1648  M_dualField->cleanField();
1649 
1650  // Reset the global hybrid vector
1651  M_hybridField->cleanField();
1652 
1653 } // resetVariables
1654 
1655 // Apply the boundary conditions to the global hybrid matrix and the global hybrid right hand side.
1656 template < typename MeshType >
1657 void
1658 DarcySolverLinear < MeshType >::
1660 {
1661 
1662  // Check if the boundary conditions are set or not.
1663  ASSERT ( M_boundaryConditionHandler.get(), "DarcySolverLinear : boundary conditions not set." );
1664 
1665  // Check if the boundary conditions were updated.
1666  if ( !M_boundaryConditionHandler->bcUpdateDone() )
1667  {
1668  // Update the boundary conditions handler. We use the finite element of the boundary of the dual variable.
1669  M_boundaryConditionHandler->bcUpdate ( *M_dualField->getFESpace().mesh(),
1670  M_dualField->getFESpace().feBd(),
1671  M_dualField->getFESpace().dof() );
1672  }
1673 
1674  // Ignoring non-local entries, otherwise they are summed up lately.
1675  vector_Type rhsFull ( *M_rhs, Unique );
1676 
1677  /* Update the global hybrid matrix and the global hybrid right hand side with the boundary conditions.
1678  It takes care of the current time for DarcySolverTransient derived class. */
1679  bcManage ( *M_matrHybrid, rhsFull, *M_dualField->getFESpace().mesh(),
1680  M_dualField->getFESpace().dof(), *M_boundaryConditionHandler, M_dualField->getFESpace().feBd(), 1.,
1681  M_data->dataTimePtr()->time() );
1682 
1683  // Save the global hybrid right hand side.
1684  *M_rhs = rhsFull;
1685 
1686 } // applyBoundaryConditions
1687 
1688 // Reorder a non full stored symmetric matrix.
1689 template < typename MeshType >
1690 template < typename MatrixType >
1691 void
1692 DarcySolverLinear < MeshType >::
1693 symmetrizeMatrix ( Int N, MatrixType& A )
1694 {
1695 
1696  for ( UInt i ( 0 ); i < static_cast<UInt> (N); ++i )
1697  {
1698  for ( UInt j ( i + 1 ); j < static_cast<UInt> (N); ++j )
1699  {
1700  A ( i, j ) = A ( j, i );
1701  }
1702  }
1703 
1704 } //symmetrizeMatrix
1705 
1706 
1707 } // namespace LifeV
1708 
1709 
1710 #endif //_DARCYSOLVERLINEAR_HPP_
1711 
1712 // -*- mode: c++ -*-
void solveLinearSystem()
Solve the global hybrid system.
virtual void setup()
Set up the linear solver and the preconditioner for the linear system.
void setCommunicator(const commPtr_Type &comm)
Set the communicator and, implicitly, the displayer.
vectorPtr_Type & residualPtr()
void setVectorSource(const vectorFctPtr_Type &vectorSourceFct)
Set vector source term.
FESpace< mesh_Type, map_Type > fESpace_Type
Finite element space.
solver_Type M_linearSolver
Linear solver.
void computeConstantMatrices(MatrixElemental &elmatMix)
Pre-computes local (element independant) matrices.
scalarFieldPtr_Type & dualFieldPtr()
Returns pointer to the dual solution field.
scalarFieldPtr_Type M_hybridField
Hybrid solution.
void buildSystem()
Build the global hybrid system, the right hand and apply the boundary conditions. ...
scalarFctPtr_Type M_scalarSourceFct
Source function.
FESpace - Short description here please!
Definition: FESpace.hpp:78
scalarFctPtr_Type M_reactionTermFct
Reaction term function.
const scalarFieldPtr_Type & primalFieldPtr() const
Returns pointer to the primal solution field.
virtual void localVectorComputation(const UInt &iElem, VectorElemental &elvecMix)
Computes local (element dependent) vectors.
matrixFctPtr_Type M_inversePermeabilityFct
Inverse of the permeability tensor.
std::shared_ptr< vectorFct_Type > vectorFctPtr_Type
Shared pointer to a vector value function.
DarcySolverLinear()
Constructor for the class.
void computePrimalAndDual()
Compute primal and dual variables from the hybrid variable as a post process.
virtual void setInversePermeability(const matrixFctPtr_Type &invPermFct)
Set inverse diffusion tensor.
std::shared_ptr< scalarFct_Type > scalarFctPtr_Type
Shared pointer to a scalar value function.
std::shared_ptr< vectorField_Type > vectorFieldPtr_Type
Shared pointer to a scalar field.
vectorPtr_Type M_residual
Residual.
const vectorPtr_Type & residualPtr() const
scalarFieldPtr_Type & hybridFieldPtr()
Returns pointer to the hybrid solution field.
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
std::shared_ptr< Displayer > displayerPtr_Type
Shared pointer to a displayer.
displayerPtr_Type M_displayer
Displayer for parallel cout.
DarcyData< mesh_Type > data_Type
Typedef for the data type.
std::shared_ptr< data_Type > dataPtr_Type
Shared pointer for the data type.
FEFunction< mesh_Type, map_Type, Matrix > matrixFct_Type
Matrix value funcion.
DarcySolverLinear< mesh_Type > darcySolver_Type
Self typedef.
FEScalarField - This class gives an abstract implementation of a finite element scalar field...
Definition: FEField.hpp:307
void setPrimalField(const scalarFieldPtr_Type &primalField)
Set the primal field vector.
const map_Type & getMap() const
Returns Epetra local map.
FEScalarField< mesh_Type, map_Type > scalarField_Type
Scalar field.
MeshType mesh_Type
Typedef for mesh template.
void applyBoundaryConditions()
Apply the boundary condition.
std::shared_ptr< bcHandler_Type > bcHandlerPtr_Type
Shared pointer to a boundary condition handler.
void setBoundaryConditions(bcHandlerPtr_Type &bcHandler)
Set the boundary conditions.
#define ASSERT_PRE(X, A)
Definition: LifeAssert.hpp:96
#define ASSERT(X, A)
Definition: LifeAssert.hpp:90
void setReactionTerm(const scalarFctPtr_Type &reactionTermFct)
Set the coefficient for the reaction term.
std::shared_ptr< Epetra_Comm > commPtr_Type
Shared pointer to a MPI communicator.
virtual void preLoopElementsComputation()
Perform all the operations before doing the loop on volume elements.
void setScalarSource(const scalarFctPtr_Type &scalarSourceFct)
Set scalar source term.
void staticCondensation(MatrixElemental &localMatrixHybrid, VectorElemental &localVectorHybrid, MatrixElemental &elmatMix, MatrixElemental &elmatReactionTerm, VectorElemental &elvecMix)
Performs static condensation.
void setDualField(const scalarFieldPtr_Type &dualField)
Set the dual field vector.
const scalarFieldPtr_Type & hybridFieldPtr() const
Returns pointer to the hybrid solution field.
std::shared_ptr< fESpace_Type > fESpacePtr_Type
Shared pointer to a finite element space.
std::shared_ptr< scalarField_Type > scalarFieldPtr_Type
Shared pointer to a scalar field.
const bcHandlerPtr_Type & boundaryConditionHandlerPtr() const
Returns boundary conditions handler.
std::shared_ptr< matrixFct_Type > matrixFctPtr_Type
Shared pointer to a matrix value function.
void symmetrizeMatrix(Int N, MatrixType &A)
Make matrix symmetric.
std::vector< FEVectorFieldPtr_Type > FEVectorFieldPtrContainer_Type
Definition: FEFunction.hpp:100
void setDisplayer(const displayerPtr_Type &displayer)
Set the displayer and, implicitly, the communicator.
bcHandlerPtr_Type M_boundaryConditionHandler
Bondary conditions handler.
vectorPtr_Type M_rhs
Right hand side.
LinearSolver solver_Type
Typedef for solver template.
double Real
Generic real data.
Definition: LifeV.hpp:175
implements a mixed-hybrid FE Darcy solver.
virtual void postComputePrimalAndDual()
Do some computation after the calculation of the primal and dual variable.
scalarFieldPtr_Type & primalFieldPtr()
Returns pointer to the primal solution field.
FEVectorField< mesh_Type, map_Type > vectorField_Type
Vector field.
FEVectorField - This class gives an abstract implementation of a finite element vector field...
Definition: FEField.hpp:405
void setHybridField(const scalarFieldPtr_Type &hybridField)
Set the hybrid field vector.
virtual void localMatrixComputation(const UInt &iElem, MatrixElemental &elmatMix, MatrixElemental &elmatReactionTerm)
Computes local (element dependent) matrices.
MapEpetra map_Type
Map type.
preconditionerPtr_Type M_prec
Epetra preconditioner for the linear system.
darcySolver_Type & operator=(const darcySolver_Type &)
Inhibited assign operator.
FEFunction< mesh_Type, map_Type, Real > scalarFct_Type
Scalar value function.
VectorSmall< 3 > Vector3D
matrixPtr_Type M_matrHybrid
Hybrid matrix.
DarcySolverLinear(const darcySolver_Type &)
Inhibited copy constructor.
contain the basic data for the Darcy solver.
Definition: DarcyData.hpp:61
virtual void resetVariables()
Update all problem variables.
FEFunction< mesh_Type, map_Type, Vector > vectorFct_Type
Vector value function.
scalarFieldPtr_Type M_dualField
Dual solution.
bcHandlerPtr_Type & boundaryConditionHandlerPtr()
Returns boundary conditions handler.
const commPtr_Type & getCommPtr() const
Returns Epetra communicator.
vectorFctPtr_Type M_vectorSourceFct
Vector source function.
scalarFieldPtr_Type M_primalField
Primal solution.
virtual void solve()
Solve the Darcy problem grouping other public methods.
void localComputePrimalAndDual(VectorElemental &localSolution, MatrixElemental &elmatMix, MatrixElemental &elmatReactionTerm, VectorElemental &elvecMix)
Compute locally, as a post process, the primal and dual variable given the hybrid.
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191
void setData(dataPtr_Type &data)
Set the data.
dataPtr_Type M_data
Data for Darcy solvers.
const scalarFieldPtr_Type & dualFieldPtr() const
Returns pointer to the dual solution field.
void setFields(const scalarFieldPtr_Type &dualField, const scalarFieldPtr_Type &primalField, const scalarFieldPtr_Type &hybridField)
Set the fields.
BCHandler bcHandler_Type
Boundary condition handler.
virtual ~DarcySolverLinear()
Virtual destructor.