dune-fem  2.4.1-rc
petscdofmappings.hh
Go to the documentation of this file.
1 // vim: set expandtab ts=2 sw=2 sts=2:
2 #ifndef DUNE_FEM_PETSCDOFMAPPING_HH
3 #define DUNE_FEM_PETSCDOFMAPPING_HH
4 
5 #include <vector>
6 #include <utility>
7 #include <algorithm>
8 #include <iostream>
9 
10 
15 
16 #if HAVE_PETSC
17 
19 // #include <dune/fem/gridpart/common/persistentindexset.hh>
20 
21 namespace Dune
22 {
23  namespace Fem
24  {
25 
26 
27  /* =================================================
28  * class PetscDofMappings
29  *
30  * This class implements 2 mappings what we need for PETSc integration.
31  *
32  * 1) The local slave mapping which maps local dune dof indices to the local indices the PETSc Vec. This mapping also
33  * knows about slave dofs.
34  *
35  * 2) The global mapping, that maps local dune dof indices to global PETSc indices.
36  *
37  * =================================================
38  */
39  template< class SlaveDofs >
40  class PetscDofMappings
41  // : public PersistentIndexSetBase< typename SlaveDofs::GridPartType::GridType, PetscDofMappings< SlaveDofs > >
42  {
43  typedef PetscDofMappings< SlaveDofs > ThisType;
44  // typedef PersistentIndexSetBase< typename SlaveDofs::GridPartType::GridType, PetscDofMappings< SlaveDofs > > BaseType;
45 
46  public:
47  typedef SlaveDofs SlaveDofsType;
48 
49  typedef std::vector< int > DofMappingType;
50  typedef DofMappingType::size_type IndexType;
51  typedef typename DofMappingType::value_type DofType;
52 
53  typedef PetscInt GlobalDofType ;
54  typedef DynamicVector< GlobalDofType > GlobalDofMappingType ;
55 
56  PetscDofMappings ( SlaveDofs *slaveDofs )
57  // : BaseType( slaveDofs->space().gridPart().grid() ),
58  : slaveDofs_( *slaveDofs ),
59  numOwnedDofBlocks_( 0 ),
60  numSlaveBlocks_( 0 ),
61  processStartIndex_( 0 ),
62  localSlaveMapping_(),
63  globalDofMapping_(),
64  sequence_( -1 )
65  {
66  // update dof mapping
67  update();
68  }
69 
70  bool update ()
71  {
72  slaveDofs_.rebuild();
73  const int sequence = slaveDofs_.space().sequence();
74  if( sequence_ != sequence )
75  {
76  initialize( slaveDofs_ );
77  sequence_ = sequence ;
78  return true ;
79  }
80  return false ;
81  }
82 
83 
84  GlobalDofType numOwnedDofBlocks () const { return numOwnedDofBlocks_; }
85 
86  GlobalDofType numSlaveBlocks () const { return numSlaveBlocks_; }
87 
88  GlobalDofType processStartIndex () const { return processStartIndex_; }
89 
90  size_t size () const { return localSlaveMapping_.size(); }
91 
92  const DofType& localSlaveMapping ( IndexType index ) const
93  {
94  return localSlaveMapping_[ index ];
95  }
96 
97  const GlobalDofType& globalMapping ( const IndexType index ) const
98  {
99  return globalDofMapping_[ index ];
100  }
101 
102  // is the dof with global DUNE index 'i' a slave dof?
103  bool isSlave ( IndexType i ) const
104  {
105  return static_cast< int >( localSlaveMapping( i ) ) >= numOwnedDofBlocks();
106  }
107 
108 
110  // interface methods for PersistentIndexSet
112  template < class Stream >
113  void write( const Stream& ) const {}
114 
115  template < class Stream >
116  void read( const Stream& ) {}
117 
118  void resize () { update (); }
119  bool compress() { return update (); }
120 
121  private:
123  // forbidden methods
125  PetscDofMappings ();
126  PetscDofMappings ( const ThisType& );
127  PetscDofMappings& operator= ( const ThisType& );
128 
129  /*
130  * private methods
131  */
132  template< typename SlaveDofProvider >
133  void initializeMappings ( SlaveDofProvider& slaveDofs )
134  {
135  // How the local slave mapping is build:
136  // Let s_1 < ... < s_n be the slave dof indices (as given by the slaveDofs object) and let
137  // d_1 < ... < d_m be the dof indices of dofs that are owned by this proces. Petsc thinks of slave dofs as
138  // dofs in a PETSc Vec 'behind the array'. So the local slave mapping is now simply a vector with the following
139  // components:
140  // d_1, d_2, ..., d_n, s_1, s_2, ..., s_n
141 
142  typedef typename SlaveDofProvider :: DiscreteFunctionSpaceType SpaceType;
143  const SpaceType& space = slaveDofs.space();
144 
145  #ifndef NDEBUG
146  int ownedDofBlocks = 0;
147  #endif
148 
149  localSlaveMapping_.resize( space.blockMapper().size(), -1 );
150  globalDofMapping_.resize( space.blockMapper().size(), 0 );
151 
152  // global dof index
153  GlobalDofType index = processStartIndex_ ;
154  for( int slave = 0, i = 0; slave < slaveDofs.size(); ++slave )
155  {
156  const int nextSlave = slaveDofs[ slave ];
157  for(; i < nextSlave; ++i )
158  {
159  localSlaveMapping_[ i ] = i - slave;
160  globalDofMapping_[ i ] = index++;
161 
162  #ifndef NDEBUG
163  ++ownedDofBlocks;
164  #endif
165  }
166 
167  // omit the last slave
168  if( static_cast< size_t >( i ) == localSlaveMapping_.size() )
169  break;
170 
171  assert( static_cast< size_t >( i ) < localSlaveMapping_.size() );
172  // skip the slave dof
173  localSlaveMapping_[ i ] = numOwnedDofBlocks_ + slave;
174  globalDofMapping_[ i ] = 0;
175  ++i;
176  }
177 
178  #ifndef NDEBUG
179  checkDofMappingConsistency();
180  #endif
181  assert( numOwnedDofBlocks_ == ownedDofBlocks );
182 
183  typedef typename SpaceType :: template ToNewDimRange< 1 > :: Type DofSpaceType ;
184 
185  if( space.continuous() )
186  {
187  typedef DofSpaceType GlobalDofSpaceType ;
188  GlobalDofSpaceType dofSpace( space.gridPart() );
189 
190  // store global dofs as a discrete function to use the already
191  // built communication patterns to sum up the global dofs
192  // which in this case simply sets the global numbers of the dofs
193  // from the other ranks (we have to use the space's range field type)
194  VectorDiscreteFunction< GlobalDofSpaceType, GlobalDofMappingType >
195  dofMappingFunc( "globalDofs", dofSpace, globalDofMapping_ );
196 
197  // do communication
198  dofMappingFunc.communicate();
199  }
200  else
201  {
202  // for discontinuous solution we only need one dof per element --> FV space
203  typedef FiniteVolumeSpace< typename DofSpaceType :: FunctionSpaceType,
204  typename DofSpaceType :: GridPartType > GlobalDofSpaceType ;
205  GlobalDofSpaceType dofSpace( space.gridPart() );
206 
207  // store global dofs as a discrete function to use the already
208  // built communication patterns to sum up the global dofs
209  // which in this case simply sets the global numbers of the dofs
210  // from the other ranks (we have to use the space's range field type)
211  VectorDiscreteFunction< GlobalDofSpaceType, GlobalDofMappingType >
212  dofMappingFunc( "globalDofs", dofSpace, globalDofMapping_ );
213 
214  // do communication
215  dofMappingFunc.communicate();
216  }
217  }
218 
219  void initialize ( const SlaveDofsType& slaveDofs )
220  {
221  numSlaveBlocks_ = slaveDofs.size() - 1;
222  numOwnedDofBlocks_ = slaveDofs.space().blockMapper().size() - numSlaveBlocks_;
223 
224  // start with index 0 (use unsigned long as buffers)
225  unsigned long processStartIndex = 0;
226  unsigned long numOwnedDofBlocks = numOwnedDofBlocks_;
227 
228  // initialize count start index for each process
229  MPI_Exscan( &numOwnedDofBlocks, &processStartIndex, 1, MPI_UNSIGNED_LONG, MPI_SUM, PETSC_COMM_WORLD );
230 
231  // store my start index
232  processStartIndex_ = processStartIndex ;
233 
234  initializeMappings( slaveDofs );
235 
236  #ifndef NDEBUG
237  checkSlaveConsistency( slaveDofs );
238  #endif
239  }
240 
242  // Methods for consistency checking, only used when NDEBUG is not set
244  template< typename SlavesType >
245  void checkSlaveConsistency ( const SlavesType& slaves ) const
246  {
247  for( size_t i = 0; i < size(); ++i )
248  {
249  assert( isSlave( i ) == slaves.isSlave( i ) );
250  }
251  }
252 
253  void checkDofMappingConsistency () const
254  {
255  // Check if the dof mapping is bijective and valid. This piece of code does not strive to be
256  // efficient...
257  std::map< DofType, bool > buf;
258  for( std::vector< int >::const_iterator it = localSlaveMapping_.begin(); it != localSlaveMapping_.end(); ++it )
259  {
260  if( *it < 0 )
261  {
262  std::cerr << "localSlaveMapping_ has not been initialized completely on rank " << MPIManager::rank() << std::endl;
263  assert( false );
264  }
265 
266  if( buf.find( *it ) != buf.end() )
267  {
268  std::cerr << *it << " was found more than once in localSlaveMapping_ (on rank " << MPIManager::rank() << ")\n";
269  assert( false );
270  }
271  else
272  {
273  buf[ *it ] = true;
274  }
275  }
276  }
277 
279  // data fields
281  SlaveDofsType& slaveDofs_; // reference to slave dofs
282  GlobalDofType numOwnedDofBlocks_; // number of blocks where this proc is master
283  GlobalDofType numSlaveBlocks_; // number of slave blocks
284  GlobalDofType processStartIndex_; // Start index of this process' portion of the PETSc Vec.
285  DofMappingType localSlaveMapping_; // local mapping (used for Discrete Function)
286  GlobalDofMappingType globalDofMapping_; // global mapping (needed for matrices)
287  int sequence_ ; // sequence number of adaptive grid
288  };
289 
290  } // namespace Fem
291 
292 } // namespace Dune
293 
294 #endif // #if HAVE_PETSC
295 
296 #endif // DUNE_FEM_PETSCDOFMAPPING_HH
static int rank()
Definition: mpimanager.hh:116
static const int MPI_SUM
Definition: odeobjectfiles.cc:18
Definition: coordinate.hh:4