LifeV
PostProcessingBoundary.hpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6  Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8  This file is part of LifeV.
9 
10  LifeV is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  LifeV is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 
27 /*!
28  @file
29  @brief File containing a class with methods to manage fields defined on the domain boundary
30 
31  @author Alessandro Veneziani <ale@mathcs.emory.edu>
32  @author Tiziano Passerini <tiziano@mathcs.emory.edu>
33 
34  @maintainer Tiziano Passerini <tiziano@mathcs.emory.edu>
35 
36  @date 09-2008
37  */
38 
39 #ifndef POSTPROCESSINGBOUNDARY_H
40 #define POSTPROCESSINGBOUNDARY_H 1
41 
42 //#include <string>
43 //#include <iostream>
44 //#include <sstream>
45 #include <lifev/core/filter/GetPot.hpp>
46 #include <lifev/core/LifeV.hpp>
47 
48 namespace LifeV
49 {
50 
51 //! Class with methods to manage fields defined on the domain boundary
52 /*!
53  The data structures are based on vector M_vectorNumberingPerFacetVector:
54  <ol>
55  <li> the size is equal to the number of boundary facets in the mesh
56  <li> each component is a vector of identifiers
57  <li> in each vector of identifiers, the i-th component is the position in vector
58  M_dofGlobalIdVector where to find the global Id for i-th dof in the facet
59  </ol>
60 
61  Vector M_dofGlobalIdVector has this usage:
62  <ol>
63  <li> the size is equal to the total number of boundary dof's
64  <li> the k-th component is the global numbering of the k-th boundary dof
65  </ol>
66 
67  How to use M_vectorNumberingPerFacetVector and M_dofGlobalIdVector together?
68  <ol>
69  <li> M_vectorNumberingPerFacetVector[ j ] is a vector containing the vector indices
70  for boundary face j
71  <li> M_dofGlobalIdVector[ M_vectorNumberingPerFacetVector[ j ][ i ] ] is the global ID
72  associated to the i-th dof on j-th face
73  </ol>
74 
75  NB: here "global" is intended wrt the global mesh (prior to partitioning, if this applies)
76  */
77 template <typename MeshType>
78 class PostProcessingBoundary
79 {
80 
81  //! @name Public Types
82  //@{
83  typedef typename MeshType::elementShape_Type elementGeometricShape_Type;
84  typedef typename elementGeometricShape_Type::GeoBShape facetGeometricShape_Type;
85  typedef MeshType mesh_Type;
86  typedef std::shared_ptr<MeshType> meshPtr_Type;
87  typedef CurrentFEManifold* currentBdFEPtr_Type;
88  typedef DOF* dofPtr_Type;
89  //@}
90 
91 public:
92 
93  //! @name Constructors & Destructor
94  //@{
95 
96  //! Empty Constructor
97  PostProcessingBoundary<MeshType>()
98  {}
99 
100  //! Copy constructor
101  /*!
102  @note all pointer members are copied (no new allocation is done in the class)
103  */
104  PostProcessingBoundary ( const PostProcessingBoundary& /*postProc*/ )
105  {}
106 
107  //! Constructor
108  /*!
109  In this general case we allow to pass an arbitrary number (nFESpaces) of dof/fe classes
110 
111  NOTE: in most parts of the code, only currentBdFEVector[0] and dofVector[0] will be considered
112 
113  \param mesh the mesh
114  \param currentBdFEVector a vector of finite element prototypes for boundary elements
115  \param dofVector a vector of classes for the description of degrees of freedom
116  \param epetraMap the map describing the partition over different processors
117  \param nFESpaces number of elements in vectors currentBdFEVector, dofVector
118  */
119  PostProcessingBoundary<MeshType> ( meshPtr_Type mesh,
120  std::vector<currentBdFEPtr_Type > currentBdFEVector,
121  std::vector<dofPtr_Type > dofVector,
122  const MapEpetra& epetraMap, UInt nFESpaces = 1 );
123 
124  /*!
125  \brief Constructor for the case in which we have only one currentBdFE and dof
126  */
127  PostProcessingBoundary<MeshType> ( meshPtr_Type mesh,
128  currentBdFEPtr_Type currentBdFE, dofPtr_Type dof,
129  const MapEpetra& epetraMap );
130 
131  /*!
132  \brief Constructor for the case in which we have two currentBdFE's and dof's
133 
134  This is the case of NS problem, in which we will want to consider both
135  velocity and pressure dof/fe classes
136  */
137  PostProcessingBoundary<MeshType> ( meshPtr_Type mesh,
138  currentBdFEPtr_Type feBdu, dofPtr_Type dofu,
139  currentBdFEPtr_Type feBdp, dofPtr_Type dofp,
140  const MapEpetra& epetraMap );
141 
142  //@}
143 
144  /*! @name Methods */
145  //@{
146 
147  /*! @defgroup boundary_methods
148  These methods compute quantities on boundary sections associated to a given flag
149  */
150 
151  /*!
152  This method computes the measure of boundary section "flag"
153  @ingroup boundary_methods
154 
155  \param flag is the marker of the considered boundary section
156  */
157  Real measure ( const markerID_Type& flag );
158 
159  /*!
160  This method computes the flux of vectorField across boundary section "flag"
161  @ingroup boundary_methods
162 
163  \tparam VectorType Vector type. Basic policy for type VectorType: operator[] available
164  \param vectorField is intended to be a vector field
165  \param flag is the marker of the considered boundary section
166  \param feSpace is the identifier of the desired FE Space in M_feSpaceVector
167  \param nDim is the dimension of vectorField
168  */
169  template< typename VectorType >
170  Real flux ( const VectorType& vectorField, const markerID_Type& flag, UInt feSpace = 0, UInt nDim = nDimensions );
171 
172  /*! Compute the kinetic normal stress (i.e., the normal stress due to the kinetic energy) on a boundary face.
173  *
174  * @see \cite BlancoMalossi2012 \cite Malossi-Thesis
175  * @ingroup boundary_methods
176  *
177  * This method computes the following quantity:
178  *
179  * \f[
180  * \mathcal{K} = \frac{1}{2}\rho_\textrm{F}\frac{1}{\left|\Gamma^t_{\textrm{F},j}\right|}\displaystyle\int_{\Gamma^t_{\textrm{F},j}}\left({\mathbf{u}}_\textrm{F} \mathbf{\cdot} {\mathbf{n}}_\textrm{F}\right)^2 \textrm{d} \Gamma
181  * \f]
182  *
183  * @param velocity velocity
184  * @param density density of the fluid
185  * @param flag the flag of the boundary face
186  * @param feSpace the FE space
187  * @param nDim the dimension size
188  * @return the kinetic normal stress
189  */
190  template< typename VectorType >
191  Real kineticNormalStress ( const VectorType& velocity, const Real& density, const markerID_Type& flag, UInt feSpace = 0, UInt nDim = nDimensions );
192 
193  /*! Compute the derivative of the kinetic normal stress (i.e., the derivative of the normal stress due to the kinetic energy) on a boundary face.
194  *
195  * @see \cite BlancoMalossi2012 \cite Malossi-Thesis
196  * @ingroup boundary_methods
197  *
198  * This method computes the following quantity:
199  *
200  * \f[
201  * \begin{array}{r@{\,\,}c@{\,\,}l@{\qquad}l}
202  * \textrm{D}\mathcal{K} &=&\displaystyle\frac{1}{2}\rho_\textrm{F} \displaystyle\frac{1}{{\left|\Gamma^t_{\textrm{F},j_1}\right|}^2}
203  * \left(\displaystyle\int_{\Gamma^t_{\textrm{F},j_1}}{\mathbf\nabla}_\Gamma \mathbf \cdot \delta {\mathbf d}_\textrm{F} \textrm{d} \Gamma\right)
204  * \left(\displaystyle\int_{\Gamma^t_{\textrm{F},j_1}}{\left({\mathbf u}_\textrm{F} \mathbf \cdot {\mathbf n}_\textrm{F}\right)}^2 \textrm{d} \Gamma \right) \\[4ex]
205  * &-&\displaystyle\frac{1}{2}\rho_\textrm{F}\displaystyle\frac{1}{\left|\Gamma^t_{\textrm{F},j_1}\right|}
206  * \left(\displaystyle\int_{\Gamma^t_{\textrm{F},j_1}}2({\mathbf u}_\textrm{F}\mathbf \cdot {\mathbf n}_\textrm{F})\left(\delta {\mathbf u}_\textrm{F} \mathbf \cdot {\mathbf n}_\textrm{F}\right) \textrm{d} \Gamma
207  * +\displaystyle\int_{\Gamma^t_{\textrm{F},j_1}}\left({\mathbf\nabla}_\Gamma \mathbf \cdot \delta {\mathbf d}_\textrm{F}\right)\left({\mathbf u}_\textrm{F} \mathbf \cdot {\mathbf n}_\textrm{F}\right)^2 \textrm{d} \Gamma \right)
208  * \end{array}
209  * \f]
210  *
211  * @param velocity velocity
212  * @param velocityDerivative velocity derivative
213  * @param density density of the fluid
214  * @param flag the flag of the boundary face
215  * @param feSpace the FE space
216  * @param nDim the dimension size
217  * @return the kinetic normal stress derivative
218  */
219  template< typename VectorType >
220  Real kineticNormalStressDerivative ( const VectorType& velocity, const VectorType& velocityDerivative, const Real& density, const markerID_Type& flag, UInt feSpace = 0, UInt nDim = nDimensions );
221 
222  /*!
223  This method computes the average value of a field on the boundary section "flag"
224  @ingroup boundary_methods
225 
226  \tparam VectorType Vector type. Basic policy for type VectorType: operator[] available
227 
228  \param field is intended to be a vector or a scalar (pressure in NS problem),
229  this method computes the average value of field on section "flag"
230 
231  \return the averaged vector
232  */
233  template< typename VectorType >
234  Vector average ( const VectorType& field, const markerID_Type& flag, UInt feSpace = 0, UInt nDim = 1 );
235 
236  /*!
237  This method computes an approximate normal vector on the boundary section "flag"
238  @ingroup boundary_methods
239 
240  \return the approximate normal vector
241  */
242  Vector normal ( const markerID_Type& flag, UInt feSpace = 0, UInt nDim = nDimensions );
243 
244  /*! Compute the geometric center of a boundary face.
245  *
246  * This method computes the geometric center of a boundary section "flag"
247  *
248  * @param flag the flag of the boundary face
249  * @param feSpace the FE space
250  * @param nDim the dimension size
251  * @return the vector containing the x-y-z coordinates of the geometric center
252  *
253  */
254  Vector geometricCenter ( const markerID_Type& flag, UInt feSpace = 0, UInt nDim = nDimensions );
255 
256  // NOT READY!
257 #if 0
258  /*!
259  This procedure computes the tangential stresses on the boundary of the domain
260  starting from an estimate of the viscous stresses on the boundary.
261 
262  The basic approach resorts to weak (residual-based) computing of the stresses.
263 
264  \param r contains the estimate of the viscous stresses
265  \param residual switches two possibilities:
266  If (residual == true), vector r contains the residual of the fluid problem,
267  i. e. the integral over the domain of the product of the stress and the test functions
268  r_i = \int_Omega tau \cdot \phi_i domega
269 
270  If (residual == false), vector r represents an estimate of the stress
271  in each dof of the _boundary_
272  r_i = tau_i
273  */
274  template<typename VectorType>
275  VectorType compute_sstress ( const VectorType& r, UInt ncomp, bool residual ) const;
276 
277  /*!
278  Here we compute the stress over the boundary, _given_ the velocity gradient
279 
280  s(n) = nu ( grad(u) + grad(u)^T ) \cdot n
281  component-wise:
282  s_i = nu ( d u_i / d x_j + d u_j / d x_i ) n_j
283 
284  \param grad the velocity gradient
285  grad[ dofGlobalId-1 + ncomp*dim + scomp*nDimensions*dim ] =
286  = ( d u_{scomp} / d x_ncomp + d u_{ucomp} / d x_scomp )
287  (at node dofGlobalId)
288  */
289  template<typename VectorType>
290  VectorType compute_stress ( const VectorType& grad, const UInt& dim, const Real& visc ) const;
291 #endif
292  //@}
293 
294  /*! @name Methods */
295  //@{
296  /*!
297  These methods print to screen information about the class data structures
298  */
299  void showDOFIndexMap ( std::ostream& output = std::cout ) const;
300 
301  void showPatchesMeasure ( std::ostream& output = std::cout ) const;
302 
303  void showPatchesNormal ( std::ostream& output = std::cout ) const;
304 
305  void showPatchesPhi ( std::ostream& output = std::cout ) const;
306 
307  /*!
308  Access to private members
309  */
310  const Vector& patchMeasureInFESpace ( const UInt& feSpace = 0 ) const
311  {
312  return M_patchMeasureVector[feSpace];
313  }
314 
315  const Vector& patchNormalInFESpace ( const UInt& feSpace = 0 ) const
316  {
317  return M_patchNormalVector[feSpace];
318  }
319 
320  const std::vector< ID >& dofGlobalIdInFESpace ( const UInt& feSpace = 0 ) const
321  {
322  return M_dofGlobalIdVector[feSpace];
323  }
324 
325  //! Number of boundary DOF for the mesh at hand
326  const UInt& numBoundaryDofInFESpace ( const UInt& feSpace = 0 ) const
327  {
328  return M_numBoundaryDofVector[feSpace];
329  }
330  //@}
331 
332 
333 private:
334  /*! @name Private Methods */
335  //@{
336  /*!
337  These methods build the data structures describing patches of boundary elements
338  (patch measure, patch normal and integral of the test function over the patch)
339  */
340  void computePatchesMeasure();
341  void computePatchesNormal();
342  void computePatchesPhi();
343  void buildVectors();
344  //@{
345 
346  UInt M_numFESpaces;
347 
348  std::vector<UInt> M_numBoundaryDofVector;
349  std::vector<UInt> M_numDofPerPeakVector, M_numDofPerRidgeVector, M_numDofPerFacetVector;
350  UInt M_numRidgesPerFacet, M_numFacetPerFacet;
351  UInt M_numPeaksPerElement, M_numRidgesPerElement;
352  std::vector<UInt> M_numPeakDofPerFacetVector, M_numRidgeDofPerFacetVector;
353  std::vector<UInt> M_numTotalDofPerFacetVector;
354  std::vector<UInt> M_numPeakDofPerElement, M_numRidgeDofPerElementVector;
355  UInt M_numBoundaryFacets;
356  std::vector<UInt> M_numTotalDofVector;
357  // vector whose ith-component is the measure of the patch of the ith-node on the boundary
358  std::vector<Vector > M_patchMeasureVector;
359  // vector with the components of the average normal vector of each boundary node
360  std::vector<Vector > M_patchNormalVector;
361  // vector with \int_{Patch(i)} \phi_i dx where \phi_i is the basis function.
362  std::vector<Vector > M_patchIntegratedPhiVector;
363 
364  // store once for all a map, with key={boundary flag}, value={ID list}
365  std::map< markerID_Type, std::list<ID> > M_boundaryMarkerToFacetIdMap;
366 
367  // for each boundary face, it contains the numbering of the dof of the face
368  std::vector< std::vector< std::vector<ID> > > M_vectorNumberingPerFacetVector;
369  // it converts from a local numbering over the boundary faces on the global numbering of the mesh
370  std::vector< std::vector< ID > > M_dofGlobalIdVector;
371 
372  // reference to the current boundary FE
373  std::vector<currentBdFEPtr_Type > M_currentBdFEPtrVector;
374  // reference to a DOF class
375  std::vector<dofPtr_Type > M_dofPtrVector;
376  // pointer to the mesh
377  meshPtr_Type M_meshPtr;
378  // pointer to the processor mapping
379  std::shared_ptr<MapEpetra> M_epetraMapPtr;
380 
381  const Int M_geoDimension;
382 
383 };
384 
385 //
386 // IMPLEMENTATIONS
387 //
388 template <typename MeshType>
389 PostProcessingBoundary<MeshType>::PostProcessingBoundary ( meshPtr_Type meshPtr,
390  std::vector<currentBdFEPtr_Type > currentBdFEVector,
391  std::vector<dofPtr_Type > dofVector,
392  const MapEpetra& epetraMap, UInt nvar ) :
393  M_numFESpaces (nvar),
394  M_numBoundaryDofVector (M_numFESpaces),
395  M_numDofPerPeakVector (M_numFESpaces), M_numDofPerRidgeVector (M_numFESpaces), M_numDofPerFacetVector (M_numFESpaces),
396  M_numPeakDofPerFacetVector (M_numFESpaces), M_numRidgeDofPerFacetVector (M_numFESpaces),
397  M_numTotalDofPerFacetVector (M_numFESpaces),
398  M_numPeakDofPerElement (M_numFESpaces), M_numRidgeDofPerElementVector (M_numFESpaces),
399  M_numTotalDofVector (M_numFESpaces),
400  M_patchMeasureVector (M_numFESpaces), M_patchNormalVector (M_numFESpaces),
401  M_patchIntegratedPhiVector (M_numFESpaces),
402  M_vectorNumberingPerFacetVector (M_numFESpaces), M_dofGlobalIdVector (M_numFESpaces),
403  M_currentBdFEPtrVector (currentBdFEVector), M_dofPtrVector (dofVector),
404  M_meshPtr ( meshPtr ), M_epetraMapPtr ( new MapEpetra (epetraMap) ),
405  M_geoDimension (MeshType::S_geoDimensions)
406 {
407  for (UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace)
408  {
409  M_vectorNumberingPerFacetVector[M_numFESpaces].clear();
410  M_dofGlobalIdVector[iFESpace].clear();
411  }
412  // Some useful local variables, to save some typing
413  M_numRidgesPerFacet = facetGeometricShape_Type::S_numRidges; // Number of face's vertices
414  M_numFacetPerFacet = facetGeometricShape_Type::S_numFacets; // Number of face's ridges
415 
416  M_numPeaksPerElement = elementGeometricShape_Type::S_numPeaks; // Number of element's vertices
417  M_numRidgesPerElement = elementGeometricShape_Type::S_numRidges; // Number of element's ridges
418 
419  M_numBoundaryFacets = M_meshPtr->numBoundaryFacets(); // number of faces on boundary
420 
421  // Construction of M_vectorNumberingPerFacetVector & other data structures
422  buildVectors();
423 
424  computePatchesMeasure();
425  computePatchesNormal();
426  computePatchesPhi();
427 }
428 
429 template <typename MeshType>
430 PostProcessingBoundary<MeshType>::PostProcessingBoundary ( meshPtr_Type mesh,
431  currentBdFEPtr_Type currentBdFE, dofPtr_Type dof,
432  const MapEpetra& epetraMap ) :
433  M_numFESpaces (1),
434  M_numBoundaryDofVector (M_numFESpaces),
435  M_numDofPerPeakVector (M_numFESpaces), M_numDofPerRidgeVector (M_numFESpaces), M_numDofPerFacetVector (M_numFESpaces),
436  M_numPeakDofPerFacetVector (M_numFESpaces), M_numRidgeDofPerFacetVector (M_numFESpaces),
437  M_numTotalDofPerFacetVector (M_numFESpaces),
438  M_numPeakDofPerElement (M_numFESpaces), M_numRidgeDofPerElementVector (M_numFESpaces),
439  M_numTotalDofVector (M_numFESpaces),
440  M_patchMeasureVector (M_numFESpaces), M_patchNormalVector (M_numFESpaces), M_patchIntegratedPhiVector (M_numFESpaces),
441  M_vectorNumberingPerFacetVector (M_numFESpaces), M_dofGlobalIdVector (M_numFESpaces),
442  M_currentBdFEPtrVector (M_numFESpaces), M_dofPtrVector (M_numFESpaces),
443  M_meshPtr ( mesh ), M_epetraMapPtr ( new MapEpetra (epetraMap) ),
444  M_geoDimension (MeshType::S_geoDimensions)
445 {
446  M_currentBdFEPtrVector[0] = currentBdFE;
447  M_dofPtrVector[0] = dof;
448 
449  // Some useful local variables, to save some typing
450  M_numRidgesPerFacet = facetGeometricShape_Type::S_numRidges; // Number of facet's ridges
451  M_numFacetPerFacet = facetGeometricShape_Type::S_numFacets; // Number of facet's facets
452 
453  M_numPeaksPerElement = elementGeometricShape_Type::S_numPeaks; // Number of element's vertices
454  M_numRidgesPerElement = elementGeometricShape_Type::S_numRidges; // Number of element's ridges
455 
456  M_numBoundaryFacets = M_meshPtr->numBoundaryFacets(); // number of faces on boundary
457 
458  // Construction of M_vectorNumberingPerFacetVector & other data structures
459  buildVectors();
460 
461  computePatchesMeasure();
462  computePatchesNormal();
463  computePatchesPhi();
464 }
465 
466 template <typename MeshType>
467 PostProcessingBoundary<MeshType>::PostProcessingBoundary ( meshPtr_Type mesh,
468  currentBdFEPtr_Type feBdu, dofPtr_Type dofu,
469  currentBdFEPtr_Type feBdp, dofPtr_Type dofp,
470  const MapEpetra& epetraMap ) :
471  M_numFESpaces (2),
472  M_numBoundaryDofVector (M_numFESpaces),
473  M_numDofPerPeakVector (M_numFESpaces), M_numDofPerRidgeVector (M_numFESpaces), M_numDofPerFacetVector (M_numFESpaces),
474  M_numPeakDofPerFacetVector (M_numFESpaces), M_numRidgeDofPerFacetVector (M_numFESpaces),
475  M_numTotalDofPerFacetVector (M_numFESpaces),
476  M_numPeakDofPerElement (M_numFESpaces), M_numRidgeDofPerElementVector (M_numFESpaces),
477  M_numTotalDofVector (M_numFESpaces),
478  M_patchMeasureVector (M_numFESpaces), M_patchNormalVector (M_numFESpaces), M_patchIntegratedPhiVector (M_numFESpaces),
479  M_vectorNumberingPerFacetVector (M_numFESpaces), M_dofGlobalIdVector (M_numFESpaces),
480  M_currentBdFEPtrVector (M_numFESpaces), M_dofPtrVector (M_numFESpaces),
481  M_meshPtr ( mesh ), M_epetraMapPtr ( new MapEpetra (epetraMap) ),
482  M_geoDimension (MeshType::S_geoDimensions)
483 {
484  M_currentBdFEPtrVector[0] = feBdu;
485  M_dofPtrVector[0] = dofu;
486  M_currentBdFEPtrVector[1] = feBdp;
487  M_dofPtrVector[1] = dofp;
488 
489  // Some useful local variables, to save some typing
490  M_numRidgesPerFacet = facetGeometricShape_Type::S_numRidges; // Number of face's vertices
491  M_numFacetPerFacet = facetGeometricShape_Type::S_numFacets; // Number of face's ridges
492 
493  M_numPeaksPerElement = elementGeometricShape_Type::S_numPeaks; // Number of element's vertices
494  M_numRidgesPerElement = elementGeometricShape_Type::S_numRidges; // Number of element's ridges
495 
496  M_numBoundaryFacets = M_meshPtr->numBoundaryFacets(); // number of faces on boundary
497 
498  // Construction of M_vectorNumberingPerFacetVector & other data structures
499  buildVectors();
500 
501  computePatchesMeasure();
502  computePatchesNormal();
503  computePatchesPhi();
504 }
505 
506 // Measure of faces with a certain marker
507 template<typename MeshType>
508 void PostProcessingBoundary<MeshType>::buildVectors()
509 {
510  std::vector<ID> boundaryDofGlobalIdVector;
511 
512  UInt iFirstAdjacentElement, iPeakLocalId, iFacetLocalId, iRidgeLocalId;
513  ID dofLocalId, dofGlobalId, dofAuxiliaryId;
514  std::vector<ID> numBoundaryDofVector (M_numFESpaces);
515  std::vector<ID>::iterator dofGlobalIdVectorIterator;
516  markerID_Type boundaryFlag;
517 
518  for (UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace)
519  {
520 
521  numBoundaryDofVector[iFESpace] = 0;
522 
523  // Some useful local variables, to save some typing
524  M_numDofPerPeakVector[iFESpace] = M_dofPtrVector[iFESpace]->localDofPattern().nbDofPerPeak(); // number of DOF per vertices
525  M_numDofPerRidgeVector[iFESpace] = M_dofPtrVector[iFESpace]->localDofPattern().nbDofPerRidge(); // number of DOF per ridges
526  M_numDofPerFacetVector[iFESpace] = M_dofPtrVector[iFESpace]->localDofPattern().nbDofPerFacet(); // number of DOF per faces
527 
528  // number of peak's DOF on a face
529  M_numPeakDofPerFacetVector[iFESpace] = M_numDofPerPeakVector[iFESpace] * M_numRidgesPerFacet;
530  // number of ridge's DOF on a face
531  M_numRidgeDofPerFacetVector[iFESpace] = M_numDofPerRidgeVector[iFESpace] * M_numFacetPerFacet;
532 
533  // number of total DOF on a face
534  M_numTotalDofPerFacetVector[iFESpace] =
535  M_numPeakDofPerFacetVector[iFESpace] + M_numRidgeDofPerFacetVector[iFESpace] + M_numDofPerFacetVector[iFESpace];
536  // number of peak's DOF on a Element
537  M_numPeakDofPerElement[iFESpace] = M_numPeaksPerElement * M_numDofPerPeakVector[iFESpace];
538  // number of ridge's DOF on a Element
539  M_numRidgeDofPerElementVector[iFESpace] = M_numRidgesPerElement * M_numDofPerRidgeVector[iFESpace];
540 
541  M_numTotalDofVector[iFESpace] = M_dofPtrVector[iFESpace]->numTotalDof();
542  }
543 
544  // ===================================================
545  // Loop on boundary faces
546  // ===================================================
547  for ( ID iboundaryFacet = 0 ; iboundaryFacet < M_numBoundaryFacets; ++iboundaryFacet )
548  {
549 
550  iFirstAdjacentElement = M_meshPtr->boundaryFacet ( iboundaryFacet ).firstAdjacentElementIdentity(); // id of the element adjacent to the face
551  iFacetLocalId = M_meshPtr->boundaryFacet ( iboundaryFacet ).firstAdjacentElementPosition(); // local id of the face in its adjacent element
552 
553  boundaryFlag = M_meshPtr->boundaryFacet (iboundaryFacet ).markerID();
554  M_boundaryMarkerToFacetIdMap[boundaryFlag].push_back ( iboundaryFacet ); // fill the flag-to-faceIdList map
555 
556  for (UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace)
557  {
558  clearVector (boundaryDofGlobalIdVector);
559 
560  //OLD: boundaryDofGlobalIdVector.clearVector();
561  boundaryDofGlobalIdVector.resize ( M_numTotalDofPerFacetVector[iFESpace] );
562 
563  // updating finite element information
564  M_currentBdFEPtrVector[iFESpace]->update ( M_meshPtr->boundaryFacet ( iboundaryFacet ), UPDATE_W_ROOT_DET_METRIC );
565 
566  // ===================================================
567  // Peak based Dof
568  // ===================================================
569  if ( M_numDofPerPeakVector[iFESpace] )
570  {
571 
572  // loop on face vertices
573  for ( ID iRidgePerFacet = 0; iRidgePerFacet < M_numRidgesPerFacet; ++iRidgePerFacet )
574  {
575  // local peak number (in element)
576  iPeakLocalId = elementGeometricShape_Type::faceToPoint ( iFacetLocalId, iRidgePerFacet );
577 
578  // Loop number of DOF per peak
579  for ( ID localDof = 0; localDof < M_numDofPerPeakVector[iFESpace]; ++localDof )
580  {
581  dofLocalId = iRidgePerFacet * M_numDofPerPeakVector[iFESpace] + localDof ; // local Dof
582  dofGlobalId = M_dofPtrVector[iFESpace]->localToGlobalMap (
583  iFirstAdjacentElement, ( iPeakLocalId ) * M_numDofPerPeakVector[iFESpace] + localDof ); // global Dof
584  dofGlobalIdVectorIterator = find (
585  M_dofGlobalIdVector[iFESpace].begin(), M_dofGlobalIdVector[iFESpace].end(), dofGlobalId );
586  if ( dofGlobalIdVectorIterator == M_dofGlobalIdVector[iFESpace].end() )
587  {
588  // the dofGlobalId has been encountered for the first time
589  boundaryDofGlobalIdVector[ dofLocalId ] = numBoundaryDofVector[iFESpace];
590  M_dofGlobalIdVector[iFESpace].push_back ( dofGlobalId ); // local to boundary global on this face
591  numBoundaryDofVector[iFESpace]++;
592  }
593  else
594  {
595  // the dofGlobalId has been already inserted in the M_dofGlobalIdVector vector
596  dofAuxiliaryId = ( ID ) ( ( dofGlobalIdVectorIterator - M_dofGlobalIdVector[iFESpace].begin() ) );
597  boundaryDofGlobalIdVector[ dofLocalId ] = dofAuxiliaryId; // local to boundary global on this face
598  }
599  }
600  }
601  }
602  // ===================================================
603  // Ridge based Dof
604  // ===================================================
605  if ( M_numDofPerRidgeVector[iFESpace] )
606  {
607  // loop on face ridges
608  for ( ID iFacetPerFacet = 0; iFacetPerFacet < M_numFacetPerFacet; ++iFacetPerFacet )
609  {
610  // local ridge number (in element)
611  iRidgeLocalId = elementGeometricShape_Type::facetToRidge ( iFacetLocalId, iFacetPerFacet );
612  // Loop number of DOF per ridge
613  for ( ID localDof = 0; localDof < M_numDofPerRidgeVector[iFESpace]; ++localDof )
614  {
615  dofLocalId = M_numPeakDofPerFacetVector[iFESpace] +
616  iFacetPerFacet * M_numDofPerRidgeVector[iFESpace] + localDof ; // local Dof
617  dofGlobalId = M_dofPtrVector[iFESpace]->localToGlobalMap (
618  iFirstAdjacentElement, M_numPeakDofPerElement[iFESpace] + iRidgeLocalId *
619  M_numDofPerRidgeVector[iFESpace] + localDof ); // global Dof
620  dofGlobalIdVectorIterator = find (
621  M_dofGlobalIdVector[iFESpace].begin(), M_dofGlobalIdVector[iFESpace].end(), dofGlobalId );
622  if ( dofGlobalIdVectorIterator == M_dofGlobalIdVector[iFESpace].end() )
623  {
624  // the dofGlobalId has been encountered for the first time
625  boundaryDofGlobalIdVector[ dofLocalId ] = numBoundaryDofVector[iFESpace];
626  M_dofGlobalIdVector[iFESpace].push_back ( dofGlobalId ); // local to boundary global on this facet
627  numBoundaryDofVector[iFESpace]++;
628  }
629  else
630  {
631  // the dofGlobalId has been already inserted in the M_dofGlobalIdVector vector
632  dofAuxiliaryId = ( ID ) ( dofGlobalIdVectorIterator - M_dofGlobalIdVector[iFESpace].begin() );
633  boundaryDofGlobalIdVector[ dofLocalId ] = dofAuxiliaryId; // local to boundary global on this facet
634  }
635  }
636  }
637  }
638  // ===================================================
639  // Facet based Dof
640  // ===================================================
641  // Loop on number of DOF per facet
642  for ( ID localDof = 0; localDof < M_numDofPerFacetVector[iFESpace]; ++localDof )
643  {
644  // local Dof
645  dofLocalId = M_numRidgeDofPerFacetVector[iFESpace] + M_numPeakDofPerFacetVector[iFESpace] + localDof;
646  dofGlobalId = M_dofPtrVector[iFESpace]->localToGlobalMap (
647  iFirstAdjacentElement, M_numRidgeDofPerElementVector[iFESpace] + M_numPeakDofPerElement[iFESpace] +
648  iFacetLocalId * M_numDofPerFacetVector[iFESpace] + localDof ); // global Dof
649  dofGlobalIdVectorIterator = find (
650  M_dofGlobalIdVector[iFESpace].begin(), M_dofGlobalIdVector[iFESpace].end(), dofGlobalId );
651  if ( dofGlobalIdVectorIterator == M_dofGlobalIdVector[iFESpace].end() )
652  {
653  // the dofGlobalId has been encountered for the first time
654  boundaryDofGlobalIdVector[ dofLocalId ] = numBoundaryDofVector[iFESpace];
655  M_dofGlobalIdVector[iFESpace].push_back ( dofGlobalId ); // local to boundary global on this facet
656  numBoundaryDofVector[iFESpace]++;
657  }
658  else
659  {
660  // the dofGlobalId has been already inserted in the M_dofGlobalIdVector vector
661  dofAuxiliaryId = ( ID ) ( dofGlobalIdVectorIterator - M_dofGlobalIdVector[iFESpace].begin() ) ;
662  boundaryDofGlobalIdVector[ dofLocalId ] = dofAuxiliaryId; // local to boundary global on this facet
663  }
664  }
665 
666  M_vectorNumberingPerFacetVector[iFESpace].push_back ( boundaryDofGlobalIdVector );
667  }
668  }
669 
670  for (UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace)
671  {
672  // each processor holds information on HIS OWN patches
673  M_numBoundaryDofVector[iFESpace] = M_dofGlobalIdVector[iFESpace].size();
674 
675  M_patchMeasureVector[iFESpace].resize ( M_numBoundaryDofVector[iFESpace] );
676  for ( Vector::iterator it = M_patchMeasureVector[iFESpace].begin(); it < M_patchMeasureVector[iFESpace].end(); it++ )
677  {
678  *it = 0.0;
679  }
680 
681  M_patchNormalVector[iFESpace].resize ( M_numBoundaryDofVector[iFESpace] * M_geoDimension );
682  for ( Vector::iterator it = M_patchNormalVector[iFESpace].begin(); it < M_patchNormalVector[iFESpace].end(); it++ )
683  {
684  *it = 0.0;
685  }
686 
687  M_patchIntegratedPhiVector[iFESpace].resize ( M_numBoundaryDofVector[iFESpace] );
688  for ( Vector::iterator it = M_patchIntegratedPhiVector[iFESpace].begin();
689  it < M_patchIntegratedPhiVector[iFESpace].end(); it++ )
690  {
691  *it = 0.0;
692  }
693  }
694 }
695 
696 ///////////////////////////////////////////////
697 
698 
699 // Measure of facets with a certain marker
700 template<typename MeshType>
701 Real PostProcessingBoundary<MeshType>::measure ( const markerID_Type& flag )
702 {
703  // Each processor computes the measure across his own flagged facets --> measureScatter
704  // At the end I'll reduce the process measures --> measure
705  Real measureScatter (0.0), measure (0.);
706 
707  std::list<ID> facetList ( M_boundaryMarkerToFacetIdMap[flag] );
708  typedef std::list<ID>::iterator Iterator;
709 
710  //
711  // Loop on flagged processor facets
712  //
713  for ( Iterator j = facetList.begin(); j != facetList.end(); ++j )
714  {
715 
716  M_currentBdFEPtrVector[0]->update ( M_meshPtr->boundaryFacet ( *j ), UPDATE_W_ROOT_DET_METRIC ); // updating finite element information
717 
718  measureScatter += M_currentBdFEPtrVector[0]->measure();
719 
720  }
721 
722  // reducing per-processor information
723  M_epetraMapPtr->comm().SumAll ( &measureScatter, &measure, 1 );
724 
725  return measure;
726 }
727 
728 
729 // flux of vector field "field" through facets with a certain marker
730 template<typename MeshType>
731 template<typename VectorType>
732 Real PostProcessingBoundary<MeshType>::flux ( const VectorType& field, const markerID_Type& flag, UInt feSpace, UInt nDim )
733 {
734  // Each processor computes the flux across his own flagged facets --> fluxScatter
735  // At the end I'll reduce the process fluxes --> flux
736  Real fluxScatter (0.0), flux (0.);
737 
738  // I need the global DOF ID to query the vector
739  // dofVectorIndex is the index of the dof in the data structure of PostProcessingBoundary class
740  // dofGlobalId is the corresponding ID in the GLOBAL mesh (prior to partitioning)
741  UInt dofVectorIndex, dofGlobalId;
742 
743  // list of flagged facets on current processor
744  std::list<ID> facetList ( M_boundaryMarkerToFacetIdMap[flag] );
745  typedef std::list<ID>::iterator Iterator;
746 
747  // Nodal values of field in the current facet
748  Vector localFieldVector (nDim * M_numTotalDofPerFacetVector[feSpace]);
749 
750  // Loop on facetList
751  for (Iterator j = facetList.begin(); j != facetList.end(); ++j)
752  {
753 
754  // Updating quadrature data on the current facet
755  M_currentBdFEPtrVector[feSpace]->update (M_meshPtr->boundaryFacet (*j), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS );
756 
757  // Quadrature formula
758  // Loop on quadrature points
759  for (UInt iq = 0; iq < M_currentBdFEPtrVector[feSpace]->nbQuadPt(); ++iq)
760  {
761 
762  // Dot product
763  // Loop on components
764  for (UInt iComponent = 0; iComponent < nDim; ++iComponent)
765  {
766 
767  // Interpolation
768  // Loop on local dof
769  for (ID iDof = 0; iDof < M_numTotalDofPerFacetVector[feSpace]; ++iDof)
770  {
771 
772  // Extracting nodal values of field in the current facet
773  dofVectorIndex = M_vectorNumberingPerFacetVector[feSpace][ ( UInt ) * j ][ iDof ];
774  dofGlobalId = M_dofGlobalIdVector[feSpace][dofVectorIndex]; // this is in the GLOBAL mesh
775 
776  localFieldVector[iComponent * M_numTotalDofPerFacetVector[feSpace] + iDof] =
777  field[iComponent * M_numTotalDofVector[feSpace] + dofGlobalId];
778 
779  fluxScatter += M_currentBdFEPtrVector[feSpace]->wRootDetMetric (iq)
780  * localFieldVector[iComponent * M_numTotalDofPerFacetVector[feSpace] + iDof]
781  * M_currentBdFEPtrVector[feSpace]->phi (iDof, iq)
782  * M_currentBdFEPtrVector[feSpace]->normal (iComponent, iq);
783  }
784  }
785  }
786  }
787  // Reducing per-processor values
788  M_epetraMapPtr->comm().SumAll ( &fluxScatter, &flux, 1 );
789 
790  return flux;
791 }
792 
793 template<typename MeshType>
794 template<typename VectorType>
795 Real PostProcessingBoundary<MeshType>::kineticNormalStress ( const VectorType& velocity, const Real& density, const markerID_Type& flag, UInt feSpace, UInt /*nDim*/ )
796 {
797  // Each processor computes the quantities across his own flagged facets
798  Real kineticNormalStressScatter (0.0), kineticNormalStress (0.0);
799  Real areaScatter (0.0), area (0.0);
800  Real temp (0.0);
801 
802  // Compute the normal
803  Vector faceNormal = normal ( flag );
804 
805  // I need the global DOF ID to query the vector
806  // dofVectorIndex is the index of the dof in the data structure of PostProcessingBoundary class
807  // dofGlobalId is the corresponding ID in the GLOBAL mesh (prior to partitioning)
808  UInt dofVectorIndex, dofGlobalId;
809 
810  // List of flagged facets on current processor
811  std::list<ID> facetList ( M_boundaryMarkerToFacetIdMap[flag] );
812 
813  // Loop on facetList
814  for ( std::list<ID>::iterator j (facetList.begin() ); j != facetList.end(); ++j )
815  {
816  // Updating quadrature data on the current facet
817  M_currentBdFEPtrVector[feSpace]->update ( M_meshPtr->boundaryFacet ( *j ), UPDATE_NORMALS | UPDATE_W_ROOT_DET_METRIC );
818 
819  // Computing the area
820  areaScatter += M_currentBdFEPtrVector[0]->measure();
821 
822  // Quadrature formula (loop on quadrature points)
823  for ( UInt iq (0); iq < M_currentBdFEPtrVector[feSpace]->nbQuadPt(); ++iq )
824  {
825  // Loop on local dof
826  for ( ID iDof (0); iDof < M_numTotalDofPerFacetVector[feSpace]; ++iDof )
827  {
828  // Extracting nodal values of field in the current facet
829  dofVectorIndex = M_vectorNumberingPerFacetVector[feSpace][ ( UInt ) * j ][ iDof ];
830  dofGlobalId = M_dofGlobalIdVector[feSpace][dofVectorIndex]; // this is in the GLOBAL mesh
831 
832  temp = velocity[0 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[0] // u_x * n_x
833  + velocity[1 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[1] // u_y * n_y
834  + velocity[2 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[2]; // u_z * n_z
835 
836  kineticNormalStressScatter += M_currentBdFEPtrVector[feSpace]->wRootDetMetric (iq)
837  * M_currentBdFEPtrVector[feSpace]->phi (Int (iDof), iq)
838  * temp * temp;
839  }
840  }
841  }
842 
843  // Reducing per-processor values
844  M_epetraMapPtr->comm().SumAll ( &areaScatter, &area, 1 );
845  M_epetraMapPtr->comm().SumAll ( &kineticNormalStressScatter, &kineticNormalStress, 1 );
846 
847  return 0.5 * density * kineticNormalStress / area;
848 }
849 
850 template<typename MeshType>
851 template<typename VectorType>
852 Real PostProcessingBoundary<MeshType>::kineticNormalStressDerivative ( const VectorType& velocity, const VectorType& velocityDerivative,
853  const Real& density, const markerID_Type& flag, UInt feSpace, UInt /*nDim*/ )
854 {
855  //TODO The two terms which depend on the displacement of the fluid have still to be coded
856 
857  // Each processor computes the quantities across his own flagged facets
858  Real kineticNormalStressScatter (0.0), kineticNormalStress (0.0);
859  Real areaScatter (0.0), area (0.0);
860  Real temp (0.0);
861 
862  // Compute the normal
863  Vector faceNormal = normal ( flag );
864 
865  // I need the global DOF ID to query the vector
866  // dofVectorIndex is the index of the dof in the data structure of PostProcessingBoundary class
867  // dofGlobalId is the corresponding ID in the GLOBAL mesh (prior to partitioning)
868  UInt dofVectorIndex, dofGlobalId;
869 
870  // List of flagged facets on current processor
871  std::list<ID> facetList ( M_boundaryMarkerToFacetIdMap[flag] );
872 
873  // Loop on facetList
874  for ( std::list<ID>::iterator j (facetList.begin() ); j != facetList.end(); ++j )
875  {
876  // Updating quadrature data on the current facet
877  M_currentBdFEPtrVector[feSpace]->update ( M_meshPtr->boundaryFacet ( *j ), UPDATE_NORMALS | UPDATE_W_ROOT_DET_METRIC );
878 
879  // Computing the area
880  areaScatter += M_currentBdFEPtrVector[0]->measure();
881 
882  // Quadrature formula (loop on quadrature points)
883  for ( UInt iq (0); iq < M_currentBdFEPtrVector[feSpace]->nbQuadPt(); ++iq )
884  {
885  // Loop on local dof
886  for ( ID iDof (0); iDof < M_numTotalDofPerFacetVector[feSpace]; ++iDof )
887  {
888  // Extracting nodal values of field in the current facet
889  dofVectorIndex = M_vectorNumberingPerFacetVector[feSpace][ ( UInt ) * j ][ iDof ];
890  dofGlobalId = M_dofGlobalIdVector[feSpace][dofVectorIndex]; // this is in the GLOBAL mesh
891 
892  temp = (
893  velocity[0 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[0] // u_x * n_x
894  + velocity[1 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[1] // u_y * n_y
895  + velocity[2 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[2] // u_z * n_z
896  )
897  * (
898  velocityDerivative[0 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[0] // du_x * n_x
899  + velocityDerivative[1 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[1] // du_y * n_y
900  + velocityDerivative[2 * M_numTotalDofVector[feSpace] + dofGlobalId] * faceNormal[2] // du_z * n_z
901  );
902 
903  kineticNormalStressScatter += M_currentBdFEPtrVector[feSpace]->wRootDetMetric (iq)
904  * M_currentBdFEPtrVector[feSpace]->phi (Int (iDof), iq)
905  * temp;
906  }
907  }
908  }
909 
910  // Reducing per-processor values
911  M_epetraMapPtr->comm().SumAll ( &areaScatter, &area, 1 );
912  M_epetraMapPtr->comm().SumAll ( &kineticNormalStressScatter, &kineticNormalStress, 1 );
913 
914  return density * kineticNormalStress / area;
915 }
916 
917 // Average value of field on facets with a certain marker
918 template<typename MeshType>
919 template<typename VectorType>
920 Vector PostProcessingBoundary<MeshType>::average ( const VectorType& field, const markerID_Type& flag, UInt feSpace, UInt nDim )
921 {
922  // Each processor computes the average value on his own flagged facets --> fieldAverageScatter
923  // At the end I'll reduce the process values --> fieldAverage
924  Vector fieldAverageScatter (nDim), fieldAverage (nDim), localField (nDim);
925  // basic policy for type VectorType: operator[] available
926  for ( UInt iComponent = 0; iComponent < nDim; ++iComponent )
927  {
928  fieldAverageScatter[iComponent] = 0.;
929  fieldAverage[iComponent] = 0.;
930  localField[iComponent] = 0.;
931  }
932 
933  // The total measure of the considered facets
934  Real measureScatter (0.), measure;
935 
936  // I need the global Dof ID to query the Oseen solution vector
937  // dofVectorIndex is the id of the DOF in the data structure of PostProcessingBoundary class
938  // dofGlobalId is the corresponding ID in the GLOBAL mesh (prior to partitioning)
939  UInt dofVectorIndex, dofGlobalId;
940 
941  // list of flagged facets on current processor
942  std::list<ID> facetList ( M_boundaryMarkerToFacetIdMap[flag] );
943  typedef std::list<ID>::iterator Iterator;
944 
945  // Nodal values of field in the current facet
946  Vector localFieldVector (M_numTotalDofPerFacetVector[feSpace]);
947 
948  // Loop on facets
949  for (Iterator j = facetList.begin(); j != facetList.end(); ++j)
950  {
951 
952  // basic policy for type VectorType: operator[] available
953  for ( UInt iComponent = 0; iComponent < nDim; ++iComponent )
954  {
955  localField[iComponent] = 0.;
956  }
957 
958  // Updating quadrature data on the current facet
959  M_currentBdFEPtrVector[feSpace]->update (M_meshPtr->boundaryFacet (*j), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS );
960 
961  // Loop on components
962  for (UInt iComponent = 0; iComponent < nDim; ++iComponent)
963  {
964 
965  // Quadrature formula
966  // Loop on quadrature points
967  for (UInt iq = 0; iq < M_currentBdFEPtrVector[feSpace]->nbQuadPt(); ++iq)
968  {
969 
970  // Interpolation
971  // Loop on local dof
972  for (ID iDof = 0; iDof < M_numTotalDofPerFacetVector[feSpace]; ++iDof)
973  {
974 
975  // Extracting nodal values of field in the current facet
976  dofVectorIndex = M_vectorNumberingPerFacetVector[feSpace][ ( UInt ) * j ][ iDof];
977  dofGlobalId = M_dofGlobalIdVector[feSpace][dofVectorIndex]; // this is in the GLOBAL mesh
978 
979  // basic policy for type VectorType: operator[] available
980  localFieldVector[iDof] = field[iComponent * M_numTotalDofVector[feSpace] + dofGlobalId];
981 
982  localField[iComponent] += M_currentBdFEPtrVector[feSpace]->wRootDetMetric (iq)
983  * localFieldVector[iDof] * M_currentBdFEPtrVector[feSpace]->phi (Int (iDof), iq);
984  }
985  }
986  // Computing the field integral over the boundary facets
987  fieldAverageScatter[iComponent] += localField[iComponent];
988  }
989 
990  // Computing the measure
991  measureScatter += M_currentBdFEPtrVector[feSpace]->measure();
992  }
993 
994  M_epetraMapPtr->comm().SumAll ( &measureScatter, &measure, 1 );
995 
996  // Reducing per-processor values
997  for ( UInt iComponent (0); iComponent < nDim; ++iComponent )
998  {
999  M_epetraMapPtr->comm().SumAll ( &fieldAverageScatter[iComponent], &fieldAverage[iComponent], 1 );
1000  }
1001 
1002  return fieldAverage / measure;
1003 }
1004 
1005 // approximate normal for a certain marker
1006 template<typename MeshType>
1007 Vector PostProcessingBoundary<MeshType>::normal ( const markerID_Type& flag, UInt feSpace, UInt nDim )
1008 {
1009  // Each processor computes the normal on his own flagged facets --> normalScatter
1010  // At the end I'll reduce the process normals --> normal
1011  Vector normalScatter (3) , normal (3);
1012 
1013  // Initialize vectors to zero
1014  normal[0] = 0.0;
1015  normal[1] = 0.0;
1016  normal[2] = 0.0;
1017 
1018  normalScatter[0] = 0.0;
1019  normalScatter[1] = 0.0;
1020  normalScatter[2] = 0.0;
1021 
1022  // list of flagged facets on current processor
1023  std::list<ID> facetList ( M_boundaryMarkerToFacetIdMap[flag] );
1024  typedef std::list<ID>::iterator Iterator;
1025 
1026  // Nodal values of field in the current facet
1027  Vector localFieldVector ( nDim * M_numTotalDofPerFacetVector[feSpace] );
1028 
1029  // Loop on facetList
1030  for (Iterator j = facetList.begin(); j != facetList.end(); ++j)
1031  {
1032  // Updating quadrature data on the current facet
1033  M_currentBdFEPtrVector[feSpace]->update ( M_meshPtr->boundaryFacet (*j), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS );
1034 
1035  // Quadrature formula (loop on quadrature points)
1036  for ( UInt iq (0); iq < M_currentBdFEPtrVector[feSpace]->nbQuadPt(); ++iq )
1037  {
1038  // Dot product (loop on components)
1039  for ( UInt iComponent (0); iComponent < nDim; ++iComponent )
1040  {
1041  // Interpolation (loop on local dof)
1042  for (ID iDof (0); iDof < M_numTotalDofPerFacetVector[ feSpace ]; ++iDof)
1043  {
1044  normalScatter (iComponent) += M_currentBdFEPtrVector[feSpace]->wRootDetMetric ( iq )
1045  * M_currentBdFEPtrVector[feSpace]->phi ( Int (iDof), iq )
1046  * M_currentBdFEPtrVector[feSpace]->normal ( Int (iComponent), iq );
1047  }
1048  }
1049  }
1050  }
1051 
1052  // Reducing per-processor values
1053  M_epetraMapPtr->comm().SumAll ( &normalScatter (0), &normal (0), 1 );
1054  M_epetraMapPtr->comm().SumAll ( &normalScatter (1), &normal (1), 1 );
1055  M_epetraMapPtr->comm().SumAll ( &normalScatter (2), &normal (2), 1 );
1056 
1057  // Scale normal to unity length
1058  Real nn = std::sqrt ( normal (0) * normal (0) + normal (1) * normal (1) + normal (2) * normal (2) );
1059 
1060 #ifdef DEBUG
1061  if ( std::fabs ( nn ) < 1e-6 )
1062  {
1063  debugStream ( 5000 ) << "Approximate surface normal could not be reliably computed.\n";
1064  debugStream ( 5000 ) << "Modulus of the integrated normal vector was: " << nn << "\n";
1065  }
1066 #endif
1067 
1068  return ( normal / nn );
1069 }
1070 
1071 // approximate geometric center for a certain marker
1072 template<typename MeshType>
1073 Vector PostProcessingBoundary<MeshType>::geometricCenter ( const markerID_Type& flag, UInt feSpace, UInt nDim )
1074 {
1075  // Each processor computes the geometric center on his own flagged facets --> geometricCenterScatter
1076  // At the end I'll reduce the process geometricCenterScatter --> geometricCenter
1077  Real areaScatter (0.0), area (0.0);
1078  Vector geometricCenterScatter (3), geometricCenter (3);
1079 
1080  geometricCenter[0] = 0.0;
1081  geometricCenter[1] = 0.0;
1082  geometricCenter[2] = 0.0;
1083 
1084  geometricCenterScatter[0] = 0.0;
1085  geometricCenterScatter[1] = 0.0;
1086  geometricCenterScatter[2] = 0.0;
1087 
1088  // list of flagged facets on current processor
1089  std::list<ID> facetList ( M_boundaryMarkerToFacetIdMap[flag] );
1090  typedef std::list<ID>::iterator Iterator;
1091 
1092  // Nodal values of field in the current facet
1093  Vector localFieldVector (nDim * M_numTotalDofPerFacetVector[feSpace]);
1094 
1095  // Loop on facetList
1096  for (Iterator j = facetList.begin(); j != facetList.end(); ++j)
1097  {
1098  // Updating quadrature data on the current facet
1099  M_currentBdFEPtrVector[feSpace]->update (M_meshPtr->boundaryFacet (*j), UPDATE_QUAD_NODES | UPDATE_NORMALS | UPDATE_W_ROOT_DET_METRIC );
1100 
1101  // Compute the area of the facet
1102  areaScatter += M_currentBdFEPtrVector[0]->measure();
1103 
1104  // Quadrature formula (loop on quadrature points)
1105  for (UInt iq (0); iq < M_currentBdFEPtrVector[feSpace]->nbQuadPt(); ++iq)
1106  {
1107  // Dot product (loop on components)
1108  for (UInt iComponent (0); iComponent < nDim; ++iComponent)
1109  {
1110  // Interpolation (loop on local dof)
1111  for (ID iDof (0); iDof < M_numTotalDofPerFacetVector[feSpace]; ++iDof)
1112  {
1113  geometricCenterScatter (iComponent) += M_currentBdFEPtrVector[feSpace]->wRootDetMetric (iq)
1114  * M_currentBdFEPtrVector[feSpace]->phi (Int (iDof), iq)
1115  * M_currentBdFEPtrVector[feSpace]->quadPt (iq, Int (iComponent) );
1116  }
1117  }
1118  }
1119  }
1120 
1121  // Reducing per-processor values
1122  M_epetraMapPtr->comm().SumAll ( &geometricCenterScatter (0), &geometricCenter (0), 1 );
1123  M_epetraMapPtr->comm().SumAll ( &geometricCenterScatter (1), &geometricCenter (1), 1 );
1124  M_epetraMapPtr->comm().SumAll ( &geometricCenterScatter (2), &geometricCenter (2), 1 );
1125 
1126  M_epetraMapPtr->comm().SumAll ( &areaScatter, &area, 1 );
1127 
1128  // Didive by the area
1129  geometricCenter /= area;
1130 
1131  return geometricCenter;
1132 }
1133 
1134 
1135 // Measure of patches on the boundary
1136 template<typename MeshType>
1137 void PostProcessingBoundary<MeshType>::computePatchesMeasure()
1138 {
1139  for ( UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace )
1140  {
1141 
1142  // measure of the mesh facet
1143  Real localMeasure;
1144 
1145  // index of the considered dof in this class' vectors
1146  ID dofVectorIndex;
1147 
1148  // ===================================================
1149  // Loop on boundary facets
1150  // ===================================================
1151  for ( ID iboundaryFacet = 0 ; iboundaryFacet < M_numBoundaryFacets; ++iboundaryFacet )
1152  {
1153  // updating finite element information
1154  M_currentBdFEPtrVector[iFESpace]->update ( M_meshPtr->boundaryFacet ( iboundaryFacet ), UPDATE_W_ROOT_DET_METRIC );
1155 
1156  localMeasure = M_currentBdFEPtrVector[iFESpace]->measure();
1157  // Loop on the total DOF per Facet
1158  for ( ID iDof = 0; iDof < M_numTotalDofPerFacetVector[iFESpace]; ++iDof )
1159  {
1160  // Extracting local ID of iDof
1161  dofVectorIndex = M_vectorNumberingPerFacetVector[iFESpace][ iboundaryFacet ][ iDof];
1162  M_patchMeasureVector[iFESpace][dofVectorIndex] += localMeasure;
1163  }
1164  }
1165  }
1166 }
1167 
1168 template <typename MeshType>
1169 void PostProcessingBoundary<MeshType>::showPatchesMeasure ( std::ostream& output ) const
1170 {
1171  for ( UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace )
1172  {
1173 
1174  output << "\n***** Post Proc: Measure of the patches *****"
1175  << "\n\tfor variable " << iFESpace << std::endl;
1176  ID counter = 0;
1177 
1178  for ( Vector::const_iterator it = M_patchMeasureVector[iFESpace].begin();
1179  it != M_patchMeasureVector[iFESpace].end(); it++ )
1180  {
1181  output << "Boundary DOF: " << counter
1182  << ", corresponding to Global DOF: " << M_dofGlobalIdVector[iFESpace][ counter ]
1183  << " has patch measure: " << *it << std::endl;
1184  counter++;
1185  }
1186  }
1187 }
1188 
1189 template<typename MeshType>
1190 void PostProcessingBoundary<MeshType>::showDOFIndexMap ( std::ostream& output ) const
1191 {
1192  for ( UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace )
1193  {
1194  output << "\n***** Data for variable " << iFESpace << "*****" << std::endl;
1195 
1196  Int counter = 0;
1197  output << "\n***** Post Proc: Vector Indexes per Facet *****" << std::endl;
1198  output << M_vectorNumberingPerFacetVector[iFESpace].size() << std::endl;
1199  for ( std::vector<std::vector<ID> >::iterator it1 = M_vectorNumberingPerFacetVector[iFESpace].begin();
1200  it1 < M_vectorNumberingPerFacetVector[iFESpace].end(); it1++ )
1201  {
1202  counter++;
1203  output << "Boundary Facet " << counter << ", indexes: " << std::endl;
1204  for ( std::vector<ID>::iterator it2 = it1->begin(); it2 < it1->end(); it2++ )
1205  {
1206  output << *it2 << ",";
1207  }
1208  output << std::endl;
1209  }
1210 
1211  output << "***** Post Proc: From Vector Index to Global DOF *****" << std::endl;
1212  output << M_dofGlobalIdVector[iFESpace].size() << std::endl;
1213 
1214  for ( std::vector<ID>::iterator it3 = M_dofGlobalIdVector[iFESpace].begin();
1215  it3 < M_dofGlobalIdVector[iFESpace].end(); it3++ )
1216  {
1217  output << "Index :" << it3 - M_dofGlobalIdVector[iFESpace].begin()
1218  << ", Global DOF: " << *it3 << std::endl;
1219  }
1220  }
1221 }
1222 
1223 /////////////////////////////////////////////////
1224 
1225 ///////////////////////////////////////////////
1226 
1227 
1228 // Normal vectors of patches on the boundary
1229 template<typename MeshType>
1230 void PostProcessingBoundary<MeshType>::computePatchesNormal()
1231 {
1232  for ( UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace )
1233  {
1234 
1235  // for each patch, the average of each component of the normal vector
1236  Real sum;
1237 
1238  // index of the considered dof in this class' vectors
1239  ID dofVectorIndex;
1240 
1241  // ===================================================
1242  // Loop on boundary facets
1243  // ===================================================
1244  for ( ID iboundaryFacet = 0 ; iboundaryFacet < M_numBoundaryFacets; ++iboundaryFacet )
1245  {
1246  // updating finite element information
1247  M_currentBdFEPtrVector[iFESpace]->update ( M_meshPtr->boundaryFacet ( iboundaryFacet ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS );
1248 
1249  // Loop on the components
1250  for ( Int iComponent = 0; iComponent < M_geoDimension; iComponent++ )
1251  {
1252  sum = 0.;
1253  // Loop on the quadrature points
1254  for ( UInt iQuadraturePoint = 0; iQuadraturePoint < M_currentBdFEPtrVector[iFESpace]->nbQuadPt();
1255  ++iQuadraturePoint )
1256  {
1257  sum += M_currentBdFEPtrVector[iFESpace]->normal ( iComponent, iQuadraturePoint ) *
1258  M_currentBdFEPtrVector[iFESpace]->wRootDetMetric ( iQuadraturePoint );
1259  }
1260  for ( ID iDof = 0; iDof < M_numTotalDofPerFacetVector[iFESpace]; ++iDof )
1261  {
1262  // Extracting local ID of iDof
1263  dofVectorIndex = M_vectorNumberingPerFacetVector[iFESpace][ iboundaryFacet ][ iDof ];
1264  M_patchNormalVector[iFESpace][ iComponent * M_numBoundaryDofVector[iFESpace] + dofVectorIndex ] += sum;
1265  }
1266  }
1267  }
1268  // Normalization of the averaged normals with the patch measure
1269  for ( UInt iBoundaryDof = 0; iBoundaryDof < M_numBoundaryDofVector[iFESpace]; ++iBoundaryDof )
1270  {
1271  Real localMeasure = M_patchMeasureVector[iFESpace][ iBoundaryDof ];
1272  for ( Int icc = 0; icc < M_geoDimension; icc++ )
1273  {
1274  M_patchNormalVector[iFESpace][ icc * M_numBoundaryDofVector[iFESpace] + iBoundaryDof ] *= 1. / localMeasure;
1275  }
1276  }
1277  }
1278 }
1279 
1280 
1281 template <typename MeshType>
1282 void PostProcessingBoundary<MeshType>::showPatchesNormal ( std::ostream& output ) const
1283 {
1284  for ( UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace )
1285  {
1286 
1287  output << "\n***** Post Proc: Normal vector on the patches *****"
1288  << "\n\tfor variable " << iFESpace << std::endl;
1289 
1290  ID counter = 0;
1291 
1292  for ( Vector::const_iterator it = M_patchMeasureVector[iFESpace].begin();
1293  it != M_patchMeasureVector[iFESpace].end(); it++ )
1294  {
1295  output << "Boundary DOF: " << counter
1296  << ", corresponding to Global DOF: " << M_dofGlobalIdVector[iFESpace][ counter ]
1297  << " has patch measure: " << *it << std::endl;
1298  output << "and normal components " ;
1299  for ( Int iComponent = 0; iComponent < M_geoDimension; iComponent++ )
1300  output <<
1301  M_patchNormalVector[iFESpace][ iComponent * M_numBoundaryDofVector[iFESpace] + counter ] << " ";
1302 
1303  output << std::endl;
1304  counter++;
1305  }
1306  }
1307 
1308  output << "End SHOW NORMAL" << std::endl;
1309 }
1310 
1311 //////////////////////////////////////////////////
1312 //
1313 ///////////////////////////////////////////////////
1314 
1315 // Vector with the integral of the shape functions on the patches on the boundary
1316 template<typename MeshType>
1317 void PostProcessingBoundary<MeshType>::computePatchesPhi()
1318 {
1319  for ( UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace )
1320  {
1321 
1322  // sum contributions from each facet of the patch
1323  Real sum;
1324 
1325  // ID of the considered dof in this class' vectors
1326  ID dofVectorIndex;
1327 
1328  // ===================================================
1329  // Loop on boundary facets
1330  // ===================================================
1331  for ( ID iboundaryFacet = 0 ; iboundaryFacet < M_numBoundaryFacets; ++iboundaryFacet )
1332  {
1333  // updating finite element information
1334  M_currentBdFEPtrVector[iFESpace]->update ( M_meshPtr->boundaryFacet ( iboundaryFacet ), UPDATE_W_ROOT_DET_METRIC );
1335 
1336  for ( ID iDof = 0; iDof < M_numTotalDofPerFacetVector[iFESpace]; ++iDof )
1337  {
1338  sum = 0.0;
1339  // global dof
1340  dofVectorIndex = M_vectorNumberingPerFacetVector[iFESpace][ iboundaryFacet ][ iDof ];
1341 
1342  // Loop on the quadrature points
1343  for ( UInt iQuadraturePoint = 0; iQuadraturePoint < M_currentBdFEPtrVector[iFESpace]->nbQuadPt();
1344  ++iQuadraturePoint )
1345  {
1346  sum += M_currentBdFEPtrVector[iFESpace]->phi ( ( Int ) ( iDof), iQuadraturePoint )
1347  * M_currentBdFEPtrVector[iFESpace]->wRootDetMetric ( iQuadraturePoint );
1348  }
1349  M_patchIntegratedPhiVector[iFESpace][ dofVectorIndex ] += sum;
1350  }
1351  }
1352  }
1353 }
1354 
1355 
1356 template <typename MeshType>
1357 void PostProcessingBoundary<MeshType>::showPatchesPhi ( std::ostream& output ) const
1358 {
1359  for ( UInt iFESpace = 0; iFESpace < M_numFESpaces; ++iFESpace )
1360  {
1361 
1362  output << "\n***** Post Proc: Average phi on the patches *****"
1363  << "\n\tfor variable " << iFESpace << std::endl;
1364 
1365  ID counter = 0;
1366 
1367  for ( Vector::const_iterator it = M_patchMeasureVector[iFESpace].begin();
1368  it != M_patchMeasureVector[iFESpace].end(); it++ )
1369  {
1370  output << "Boundary DOF: " << counter
1371  << ", corresponding to Global DOF: " << M_dofGlobalIdVector[iFESpace][ counter ]
1372  << " has patch measure: " << *it << std::endl;
1373  output << "and average phi " << M_patchIntegratedPhiVector[iFESpace][ counter ] << std::endl ;
1374  counter++;
1375  }
1376  }
1377  output << "End SHOW PHI" << std::endl;
1378 }
1379 
1380 // the following part is definitely not ready yet TP 09/2008
1381 #if 0
1382 ////////////////////////////////
1383 ////////////////////////////////
1384 ////////////////////////////////
1385 template<typename MeshType>
1386 template<typename VectorType>
1388 {
1389  ASSERT ( ncomp = M_geoDimension, "Error: Shear stress computation possible only for vector unknowns" );
1390 
1391  // prepare the vectors
1393  stress.clear();
1395  nstress.clear();
1397  sstress.clear();
1399 
1400  // number of DOFs for each component
1401  UInt dim = r.size() / ncomp;
1402 
1403  // helper structures to avoid "if" statement
1404  // if residual==true, vector r has ncomp*M_numBoundaryDofVector components
1405  // if residual==false, vector r has ncomp*M_numTotalDofVector components
1406  Vector coef (2);
1407  std::vector<ID> index (2);
1408 
1409  // loop on locally stored DOFs
1410  for ( counter = 0; counter < M_numBoundaryDofVector[0]; ++counter )
1411  {
1412  // find global ID for boundary dof
1413  dofGlobalId = M_dofGlobalIdVector[0][counter]; // this is in the GLOBAL mesh
1414 
1415  coef[0] = 1.;
1416  index[0] = counter;
1417  coef[1] = 1. / M_patchIntegratedPhiVector[0][counter];
1418  index[1] = dofGlobalId;
1419 
1420  for ( UInt ind_comp = 0; ind_comp < ncomp; ++ind_comp )
1421  {
1422  stress[ counter + ind_comp * M_numBoundaryDofVector[0] ] = //damned conventions trouble : 0 or 1
1423  coef[residual] * r[ index[residual] + ind_comp * dim ];
1424  }
1425  }
1426 
1427  Real sn = 0.;
1428  ///// Normal stress
1429  for ( counter = 0; counter < M_numBoundaryDofVector[0]; counter++ )
1430  {
1431  sn = 0.;
1432  for ( UInt ind_comp = 0; ind_comp < ncomp; ind_comp++ )
1435 
1436  for ( UInt ind_comp = 0; ind_comp < ncomp; ind_comp++ )
1439  }
1440 
1441  // Shear Stress: this vector lives on the patches (ncomp*M_numBoundaryDofVector components)
1442  sstress = stress - nstress;
1443 
1444  return sstress;
1445 } // compute_sstress
1446 
1447 
1448 
1449 ////////////////////////////////
1450 ////////////////////////////////
1451 ///////////////////////////////
1452 template<typename MeshType>
1453 template<typename VectorType>
1455  const Real& visc ) const
1456 {
1458  stress.clear();
1459 
1460  ID dofGlobalId;
1461 
1462  // cycle over boundary dof
1464  {
1465  // find global ID for boundary dof
1466  dofGlobalId = M_dofGlobalIdVector[0][bound_dof]; // this is in the GLOBAL mesh
1467 
1468  // cycle over stress components
1469  for ( UInt scomp = 0; scomp < M_geoDimension; ++scomp )
1470 
1471  // cycle over normal components
1472  for ( UInt ncomp = 0; ncomp < M_geoDimension; ++ncomp )
1473  {
1475  // grad!
1476  ( grad[ dofGlobalId + ncomp * dim + scomp * nDimensions * dim ] +
1477  // transpose grad!
1478  grad[ dofGlobalId + scomp * dim + ncomp * nDimensions * dim ] )
1480  }
1481  }
1482 
1483 
1484  return stress;
1485 } // compute_stress
1486 #endif
1487 } // namespace LifeV
1488 
1489 #endif /* POSTPROCESSINGBOUNDARY_H */
A class for a finite element on a manifold.
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
ID markerID_Type
markerID_Type is the type used to store the geometric entity marker IDs
Definition: Marker.hpp:81
void updateInverseJacobian(const UInt &iQuadPt)
Epetra_Import const & importer()
Getter for the Epetra_Import.
Definition: MapEpetra.cpp:394
uint32_type ID
IDs.
Definition: LifeV.hpp:194
double Real
Generic real data.
Definition: LifeV.hpp:175
const UInt nDimensions(NDIM)
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191