ParallelDofMapping.h 16.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ============================================================================
// ==                                                                        ==
// == AMDiS - Adaptive multidimensional simulations                          ==
// ==                                                                        ==
// ==  http://www.amdis-fem.org                                              ==
// ==                                                                        ==
// ============================================================================
//
// Software License for AMDiS
//
// Copyright (c) 2010 Dresden University of Technology 
// All rights reserved.
// Authors: Simon Vey, Thomas Witkowski et al.
//
// This file is part of AMDiS
//
// See also license.opensource.txt in the distribution.



/** \file FeSpaceMapping.h */

23
24
25
26
#ifndef AMDIS_FE_SPACE_MAPPING_H
#define AMDIS_FE_SPACE_MAPPING_H

#include <mpi.h>
27
#include <vector>
28
#include <map>
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
29
#include <set>
30
31
#include <petsc.h>
#include <petscis.h>
32
33
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
34
35

#include "AMDiS_fwd.h"
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
36
#include "parallel/DofComm.h"
37
38
#include "parallel/MpiHelper.h"
#include "parallel/ParallelTypes.h"
39
#include "parallel/StdMpi.h"
40
41

namespace AMDiS {
Thomas Witkowski's avatar
Thomas Witkowski committed
42

43
44
  using namespace std;

45
  /** \brief
46
47
48
   * Is used to store matrix indices to all DOFs in rank's subdomain. Thus, the
   * class defines a mapping from component number and DOF index to a global
   * matrix index. This class does not calculate the indices by itself!
49
50
51
52
53
54
55
56
57
58
59
60
   */
  class DofToMatIndex
  {
  public:
    DofToMatIndex() {}

    /// Reset the data structure.
    inline void clear()
    {
      data.clear();
    }

61
62
63
64
65
66
67
    /** Add a new mapping for a given DOF.
     * 
     * \param[in]   component       Component number for which the mapping 
     *                              is defined.
     * \param[in]   dof             DOF index
     * \param[in]   globalMatIndex  Global matrix index.
     */
68
69
70
71
72
    inline void add(int component, DegreeOfFreedom dof, int globalMatIndex)
    {
      data[component][dof] = globalMatIndex;
    }

73
    /// Maps a global DOF index to the global matrix index for a specific 
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    /// system component number.
    inline int get(int component, DegreeOfFreedom dof)
    {
      FUNCNAME("DofToMatIndex::get()");

      TEST_EXIT_DBG(data.count(component))
	("No mapping data for component %d available!\n", component);

      TEST_EXIT_DBG(data[component].count(dof))
	("Mapping for DOF %d in component %d does not exists!\n",
	 dof, component);

      return data[component][dof];
    }

89
90
91
92
93
    /// Returns for a given matrix index the component and (local or global) DOF
    /// index. As the data structure is not made for this kind of reverse
    /// search, this is very slow and should be only used for debugging.
    void getReverse(int rowIndex, int &component, int &dofIndex);

94
95
96
  private:
    /// The mapping data. For each system component there is a specific map that
    /// maps global DOF indices to global matrix indices.
97
98
    //    map<int, map<DegreeOfFreedom, int> > data;
    map<int, boost::container::flat_map<DegreeOfFreedom, int> > data;
99
100
101
  };


102
103
104
105
106
107
  /**
   * This class defines the parallel mapping of DOFs for one FE space. It is used
   * by the class \ref ParallelDofMapping to specifiy the mapping for a set of 
   * FE spaces.
   */
  class FeSpaceDofMap
108
109
  {
  public:
110
111
    /// This constructor exists only to create std::map of this class and make
    /// use of the operator [] for read access. Should never be called.
112
    FeSpaceDofMap() 
113
114
115
    {
      ERROR_EXIT("Should not be called!\n");
    }
116
117
     
    /// This is the only valid constructur to be used. 
118
    FeSpaceDofMap(MeshLevelData* ld);
119
120

    /// Clears all data of the mapping.
121
    void clear();
122

123
124
    /// Maps a DOF index to both, the local and global index of the mapping. The
    /// global index must not be set.
Thomas Witkowski's avatar
Thomas Witkowski committed
125
    MultiIndex& operator[](DegreeOfFreedom d)
126
    {
127
      TEST_EXIT_DBG(dofMap.count(d))("DOF %d is not in map!\n", d);
128

129
      return dofMap[d];
130
    }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

    /** \brief
     * Searchs the map for a given DOF. It does not fail, if the DOF is not 
     * mapped by this mapping. In this case, it returns false. If the DOF is 
     * mapped, the result is stored and the function returns true.
     *
     * \param[in]    dof     DOF index for which a mapping is searched.
     * \param[out]   index   In the case that the DOF is mapped, the result
     *                       is stored here.
     */
    inline bool find(DegreeOfFreedom dof, MultiIndex& index)
    {
      DofMap::iterator it = dofMap.find(dof);
      if (it == dofMap.end())
	return false;

      index = it->second;
      return true;
    }
150
    
151
152
    /// Inserts a new DOF to rank's mapping. The DOF is assumed to be owend by
    /// the rank.
153
    void insertRankDof(DegreeOfFreedom dof0, DegreeOfFreedom dof1 = -1)
154
    {
155
      FUNCNAME("FeSpaceDofMap::insertRankDof()");
156
      
157
      TEST_EXIT_DBG(dofMap.count(dof0) == 0)("Should not happen!\n");
158
      
159
160
      dofMap[dof0].local = dof1;
      nLocalDofs++;
Thomas Witkowski's avatar
Thomas Witkowski committed
161
      if (dof1 != -1)
162
	nRankDofs++;
163
164
    }
    
165
166
    /// Inserts a new DOF to rank's mapping. The DOF exists in rank's subdomain
    /// but is owned by a different rank, thus it is part of an interior boundary.
167
    void insertNonRankDof(DegreeOfFreedom dof0, DegreeOfFreedom dof1 = -1)
168
    {
169
      FUNCNAME("FeSpaceDofMap::insertNonRankDof()");
170
      
171
      TEST_EXIT_DBG(dofMap.count(dof0) == 0)("Should not happen!\n");
172
      
173
174
175
      dofMap[dof0].local = dof1;
      nLocalDofs++;
      nonRankDofs.insert(dof0);
176
177
    }
    
178
    /// Checks if a given DOF is in the DOF mapping.
179
    bool isSet(DegreeOfFreedom dof)
180
    {
181
      return static_cast<bool>(dofMap.count(dof));
182
    }
183

Thomas Witkowski's avatar
Blbu  
Thomas Witkowski committed
184
185
186
    /// Checks if a given DOF is a rank owned DOF of the DOF mapping. The DOF
    /// must be a DOF of the mapping (this is not checked here), otherwise the
    /// result is meaningsless.
187
    bool isRankDof(DegreeOfFreedom dof)
188
    {
189
      return !(static_cast<bool>(nonRankDofs.count(dof)));
190
    }
Thomas Witkowski's avatar
Blbu  
Thomas Witkowski committed
191
192
193
194
195

    bool isRankGlobalDof(int dof)
    {
      return (dof >= rStartDofs && dof < rStartDofs + nRankDofs);
    }
196
    
197
    /// Returns number of DOFs in the mapping.
198
    unsigned int size()
199
    {
200
      return dofMap.size();
201
202
    }
    
203
    /// Returns the raw data of the mapping.
204
    DofMap& getMap()
205
    {
206
      return dofMap;
207
    }
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
208

209
210
211
212
213
214
215
216
217
218
    DofMap::iterator begin()
    {
      return dofMap.begin();
    }

    DofMap::iterator end()
    {
      return dofMap.end();
    }

219
220
    /// Recomputes the mapping.
    void update();
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
221

222
    /// Sets the FE space this mapping corresponds to.
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
223
224
225
226
227
    void setFeSpace(const FiniteElemSpace *fe)
    {
      feSpace = fe;
    }

228
229
    /// Informs the mapping whether the mapping will include DOFs that are not
    /// owned by the rank.
230
    void setNonLocal(bool b)
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
231
    {
232
      isNonLocal = b;
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
233
234
    }

235
    /// Informs the mapping whether a global index must be computed.
236
    void setNeedGlobalMapping(bool b)
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
237
    {
238
      needGlobalMapping = b;
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
239
240
    }

241
    /// Sets the DOF communicator.
242
    void setDofComm(DofComm &dc)
Thomas Witkowski's avatar
Thomas Witkowski committed
243
    {
244
      dofComm = &dc;
Thomas Witkowski's avatar
Thomas Witkowski committed
245
246
    }

247
248
249
250
251
252
    void setMpiComm(MPI::Intracomm &m, int l)
    {
      mpiComm = m;
      meshLevel = l;
    }

253
  private:
254
    /// Computes a global mapping from the local one.
255
    void computeGlobalMapping();
256
257
258

    /// Computes the global indices of all DOFs in the mapping that are not owned
    /// by the rank.
259
    void computeNonLocalIndices();
260
261

  private:
262
    MeshLevelData *levelData;
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
263

264
265
    /// DOF communicator for all DOFs on interior boundaries.
    DofComm *dofComm;
266

267
268
269
270
    MPI::Intracomm mpiComm;

    int meshLevel;

271
    /// The FE space this mapping belongs to. This is used only the get the
272
    /// correct DOF communicator in \ref dofComm.
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
273
274
    const FiniteElemSpace *feSpace;

275
    /// Mapping data from DOF indices to local and global indices.
276
    DofMap dofMap;
277

278
    /// Set of all DOFs that are in mapping but are not owned by the rank.
279
    boost::container::flat_set<DegreeOfFreedom> nonRankDofs;
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
280

281
    /// If true, a global index mapping will be computed for all DOFs.
Thomas Witkowski's avatar
Thomas Witkowski committed
282
    bool needGlobalMapping;
Thomas Witkowski's avatar
FETI-DP  
Thomas Witkowski committed
283

284
285
286
    /// Is true if there are DOFs in at least one subdomain that are not owned
    /// by the rank. If the value is false, each rank contains only DOFs that
    /// are also owned by this rank.
287
    bool isNonLocal;
288

289
290
  public:
    /// 
291
    int nRankDofs, nLocalDofs, nOverallDofs, rStartDofs;
292
293
  };
  
294
295
296
297
298
299
  
  /**
   * Implements the mapping from sets of distributed DOF indices to local and
   * global indices. The mapping works for a given set of FE spaces. Furthermore,
   * this class may compute the matrix indices of the set of DOF indices.
   */
Thomas Witkowski's avatar
Thomas Witkowski committed
300
  class ParallelDofMapping
301
302
  {
  public:
Thomas Witkowski's avatar
Thomas Witkowski committed
303
    ParallelDofMapping() 
304
      : levelData(NULL),
305
	dofComm(NULL),
306
	isNonLocal(true),
307
	needMatIndexFromGlobal(false),
308
	feSpaces(0),
309
310
311
312
313
	nRankDofs(1),
	nLocalDofs(1),
	nOverallDofs(1),
	rStartDofs(1)
    {
314
315
316
317
      nRankDofs = -1;
      nLocalDofs = -1;
      nOverallDofs = -1;
      rStartDofs = -1;
318
    } 
319

320
321
322
323
    /** \brief Initialize the parallel DOF mapping.
     *
     * \param[in]  m                  MPI communicator.
     * \param[in]  fe                 The FE spaces of all components of the 
324
325
326
327
     *                                PDE to be solved.
     * \param[in]  uniqueFe           Unique list of FE spaces. Thus, two
     *                                arbitrary elements of this list are always
     *                                different.
328
     * \param[in]  isNonLocal         If true, at least one rank's mapping con-
329
330
     *                                taines DOFs that are not owend by the rank.
     */
331
    void init(MeshLevelData& mld,
332
	      vector<const FiniteElemSpace*> &fe,
333
	      vector<const FiniteElemSpace*> &uniqueFe,
334
335
336
337
338
339
340
341
342
343
344
345
	      bool isNonLocal = true);

    /// In the case of having only one FE space, this init function can be used.
    void init(MeshLevelData& mld,
	      const FiniteElemSpace *feSpace,
	      bool isNonLocal = true)
    {
      vector<const FiniteElemSpace*> feSpaces;
      feSpaces.push_back(feSpace);
      init(mld, feSpaces, feSpaces, isNonLocal);
    }

346
    void setMpiComm(MPI::Intracomm &m, int l);
347
348
349
    
    /// Clear all data.
    void clear();
350
351
352

    /// Set the DOF communicator objects that are required to exchange information
    /// about DOFs that are on interior boundaries.
353
    void setDofComm(DofComm &dofComm);
354

355
356
357
    /// Returns the DOF communicator.
    DofComm& getDofComm()
    {
358
359
360
      FUNCNAME("ParallelDofMapping::getDofComm()");

      TEST_EXIT_DBG(dofComm)("No DOF communicator object defined!\n");
361
362
363
364

      return *dofComm;
    }

365
366
367
    /// Changes the computation of matrix indices based of either local or
    /// global DOF indices, see \ref needMatIndexFromGlobal
    void setComputeMatIndex(bool global)
368
369
370
371
    {
      needMatIndexFromGlobal = global;
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
372
373
374
375
376
    inline bool isMatIndexFromGlobal()
    {
      return needMatIndexFromGlobal;
    }

377
378
    /// Access the DOF mapping for a given FE space.
    inline FeSpaceDofMap& operator[](const FiniteElemSpace* feSpace)
379
    {
Thomas Witkowski's avatar
Thomas Witkowski committed
380
      FUNCNAME("ParallelDofMapping::operator[]()");
381

382
383
      TEST_EXIT_DBG(data.count(feSpace))
	("No data for FE space at address %p!\n", feSpace);
384
385
386
387

      return data.find(feSpace)->second;
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
388
389
390
391
392
    inline bool isDefinedFor(const FiniteElemSpace* feSpace) const
    {
      return static_cast<bool>(data.count(feSpace));
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
393
394
395
396
397
398
    /// Returns the number of solution components the mapping is defined on.
    inline int getNumberOfComponents() const
    {
      return static_cast<int>(feSpaces.size());
    }

399
    /// Returns \ref nRankDofs, thus the number of DOFs owned by the rank.
400
    inline int getRankDofs()
401
    {
402
      TEST_EXIT_DBG(nRankDofs >= 0)("Should not happen!\n");
403

404
      return nRankDofs;
405
406
    }

407
    /// Returns \ref nLocalDofs, thus the number of DOFs in ranks subdomain.
408
    inline int getLocalDofs()
Thomas Witkowski's avatar
Thomas Witkowski committed
409
    {
410
      TEST_EXIT_DBG(nLocalDofs >= 0)("Should not happen!\n");
Thomas Witkowski's avatar
Thomas Witkowski committed
411

412
      return nLocalDofs;
Thomas Witkowski's avatar
Thomas Witkowski committed
413
414
    }

415
    /// Returns \ref nOverallDofs, thus the number of all DOFs in this mapping.
416
    inline int getOverallDofs()
417
    {
418
      TEST_EXIT_DBG(nOverallDofs >= 0)("Should not happen!\n");
419

420
      return nOverallDofs;
421
422
    }

423
424
    /// Returns \ref rStartDofs, thus the smallest global index of a DOF that is
    /// owned by the rank.
425
    inline int getStartDofs()
426
    {
427
      TEST_EXIT_DBG(rStartDofs >= 0)("Should not happen!\n");
428

429
      return rStartDofs;
430
431
    }

432
    /// Update the mapping.
Thomas Witkowski's avatar
Thomas Witkowski committed
433
    void update();
434

435
436
437
    /// Update the mapping.
    void update(vector<const FiniteElemSpace*>& feSpaces);

438
439
    /// Returns the global matrix index of a given DOF for a given 
    /// component number.
440
    inline int getMatIndex(int ithComponent, DegreeOfFreedom d)
Thomas Witkowski's avatar
Thomas Witkowski committed
441
    {
442
      return dofToMatIndex.get(ithComponent, d);
Thomas Witkowski's avatar
Thomas Witkowski committed
443
444
    }

445
446
447
448
449
450
451
    /// Returns the component number and local/global DOF index for a given
    /// matrix row index. Should be used for debugging only!
    inline void getReverseMatIndex(int index, int &component, int &dofIndex)
    {
      dofToMatIndex.getReverse(index, component, dofIndex);
    }

452
453
    /// Returns the local matrix index of a given DOF for a given 
    /// component number.
454
    inline int getLocalMatIndex(int ithComponent, DegreeOfFreedom d)
455
    {
Thomas Witkowski's avatar
Thomas Witkowski committed
456
      FUNCNAME("ParallelDofMapping::getLocalMatIndex()");
457

458
      TEST_EXIT_DBG(data[feSpaces[ithComponent]].isRankDof(d))
459
460
	("Should not happen!\n");

461
      return dofToMatIndex.get(ithComponent, d) - rStartDofs;
462
463
    }

Thomas Witkowski's avatar
Thomas Witkowski committed
464
465
466
467
468
469
470
471
472
473
474
475
    // Writes all data of this object to an output stream.
    void serialize(ostream &out)
    {
      ERROR_EXIT("MUST BE IMPLEMENTED!\n");
    }

    // Reads the object data from an input stream.
    void deserialize(istream &in)
    {
      ERROR_EXIT("MUST BE IMPLEMENTED!\n");
    }

476
    /// Compute local and global matrix indices.
477
    void computeMatIndex(bool globalIndex);
478

479
480
481
482
    void createIndexSet(IS &is, 
			int firstComponent, 
			int nComponents);

483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
    /// Create a parallel distributed PETSc vector based on this mapping.
    inline void createVec(Vec &vec)
    {
      VecCreateMPI(mpiComm, getRankDofs(), getOverallDofs(), &vec);
    }

    /// Create a parallel distributed PETsc vector based on this mapping but
    /// with a different (larger) global size. This is used in multi-level 
    /// method to embed a local vector into a subdomain spaned by several
    /// ranks.
    inline void createVec(Vec &vec, int nGlobalRows)
    {
      VecCreateMPI(mpiComm, getRankDofs(), nGlobalRows, &vec);
    }

498
499
500
501
502
  protected:
    /// Insert a new FE space DOF mapping for a given FE space.
    void addFeSpace(const FiniteElemSpace* feSpace);

    /// Compute \ref nRankDofs.
503
    int computeRankDofs();
504
505

    /// Compute \ref nLocalDofs.
506
    int computeLocalDofs();
507
508

    /// Compute \ref nOverallDofs.
509
    int computeOverallDofs();
510
511

    /// Compute \ref rStartDofs.
512
    int computeStartDofs();
513

514
  private:
515
516
517
518
    MPI::Intracomm mpiComm;

    int meshLevel;

519
    MeshLevelData *levelData;
520

521
522
    /// DOF communicator for all DOFs on interior boundaries.
    DofComm *dofComm;
523

524
525
526
    /// Is true if there are DOFs in at least one subdomain that are not owned
    /// by the rank. If the value is false, each rank contains only DOFs that
    /// are also owned by this rank.
527
    bool isNonLocal;
528
529
530
531
532

    /// If matrix indices should be computed, this variable defines if the
    /// mapping from DOF indices to matrix row indices is defined on local
    /// or global DOF indices. If true, the mapping is to specify and to use
    /// on global ones, otherwise on local DOF indices.
Thomas Witkowski's avatar
Thomas Witkowski committed
533
534
535
536
537
    /// In most scenarios the mapping stored on local DOF indices is what we
    /// want to have. Only when periodic boundary conditions are used together
    /// with some global matrix approache, the matrix indices must be stored
    /// also for DOFs that are not part of the local subdomain. Thus, the
    /// mapping will be stored on global DOF indices.
538
539
    bool needMatIndexFromGlobal;

540
541
542
543
    /// Maps from FE space pointers to DOF mappings.
    map<const FiniteElemSpace*, FeSpaceDofMap> data;

    /// The FE spaces for all components.
544
545
    vector<const FiniteElemSpace*> feSpaces;

546
547
    /// The set of all FE spaces. It uniquly contains all different FE spaces
    /// from \ref feSpaces.
548
    vector<const FiniteElemSpace*> feSpacesUnique;
Thomas Witkowski's avatar
Thomas Witkowski committed
549

550
    /// Number of DOFs owned by rank.
551
    int nRankDofs;
552
553

    /// Number of DOFs in rank's subdomain.
554
    int nLocalDofs;
555
556

    /// Number of global DOFs (this value is thus the same on all ranks).
557
    int nOverallDofs;
558
559

    /// Smallest global index of a DOF owned by the rank.
560
    int rStartDofs;
561
562
563

    /// Mapping from global DOF indices to global matrix indices under 
    /// consideration of possibly multiple components.
564
    DofToMatIndex dofToMatIndex;
565
566
567
568
569
  };

}

#endif