Commit 7856d906 authored by Thomas Witkowski's avatar Thomas Witkowski

Periodic boundary conditions with mixed finite elements in parallel should work now.

parent 6bfde321
......@@ -57,7 +57,7 @@ namespace AMDiS {
FUNCNAME("DOFMatrix::DOFMatrix()");
TEST_EXIT(rowFeSpace)("No fe space for row!\n");
if (!colFeSpace)
colFeSpace = rowFeSpace;
......@@ -211,16 +211,18 @@ namespace AMDiS {
using namespace mtl;
#if 0
std::cout << "----- PRINT MAT " << rowElInfo->getElement()->getIndex() << "--------" << std::endl;
std::cout << elMat << std::endl;
std::cout << "rows: ";
for (int i = 0; i < rowIndices.size(); i++)
std::cout << rowIndices[i] << " ";
std::cout << std::endl;
std::cout << "cols: ";
for (int i = 0; i < colIndices.size(); i++)
std::cout << colIndices[i] << " ";
std::cout << std::endl;
if (MPI::COMM_WORLD.Get_rank() == 0) {
std::cout << "----- PRINT MAT " << rowElInfo->getElement()->getIndex() << "--------" << std::endl;
std::cout << elMat << std::endl;
std::cout << "rows: ";
for (int i = 0; i < rowIndices.size(); i++)
std::cout << rowIndices[i] << " ";
std::cout << std::endl;
std::cout << "cols: ";
for (int i = 0; i < colIndices.size(); i++)
std::cout << colIndices[i] << " ";
std::cout << std::endl;
}
#endif
for (int i = 0; i < nRow; i++) {
......@@ -229,7 +231,7 @@ namespace AMDiS {
BoundaryCondition *condition =
bound ? boundaryManager->getBoundaryCondition(bound[i]) : NULL;
if (condition && condition->isDirichlet()) {
if (condition && condition->isDirichlet()) {
if (condition->applyBoundaryCondition()) {
#ifdef HAVE_PARALLEL_DOMAIN_AMDIS
if ((*rankDofs)[rowIndices[i]])
......@@ -241,8 +243,9 @@ namespace AMDiS {
} else {
for (int j = 0; j < nCol; j++) {
DegreeOfFreedom col = colIndices[j];
if (fabs(elMat[i][j]) > 1e-10)
if (fabs(elMat[i][j]) > 1e-10) {
ins[row][col] += elMat[i][j];
}
}
}
}
......@@ -259,7 +262,9 @@ namespace AMDiS {
{}
void DOFMatrix::assemble(double factor, ElInfo *elInfo, const BoundaryType *bound)
void DOFMatrix::assemble(double factor,
ElInfo *elInfo,
const BoundaryType *bound)
{
FUNCNAME("DOFMatrix::assemble()");
......@@ -278,7 +283,9 @@ namespace AMDiS {
}
void DOFMatrix::assemble(double factor, ElInfo *elInfo, const BoundaryType *bound,
void DOFMatrix::assemble(double factor,
ElInfo *elInfo,
const BoundaryType *bound,
Operator *op)
{
FUNCNAME("DOFMatrix::assemble()");
......
......@@ -1356,6 +1356,10 @@ namespace AMDiS {
{
FUNCNAME("ProblemStat::addMatrixOperator()");
TEST_EXIT(i < nComponents && j < nComponents)
("Cannot add matrix operator at position %d/%d. The stationary problem has only %d components!\n",
i, j, nComponents);
TEST_EXIT(!boundaryConditionSet)
("Do not add operators after boundary conditions were set!\n");
......@@ -1402,6 +1406,10 @@ namespace AMDiS {
{
FUNCNAME("ProblemStat::addVectorOperator()");
TEST_EXIT(i < nComponents)
("Cannot add vector operator at position %d. The stationary problem has only %d components!\n",
i, nComponents);
TEST_EXIT(!boundaryConditionSet)
("Do not add operators after boundary conditions were set!\n");
......
......@@ -64,17 +64,13 @@ namespace AMDiS {
/// Destructor
virtual ~SubAssembler() {}
/** \brief
* Calculates the element matrix for elInfo and adds it to mat. Memory
* for mat must be provided by the caller.
*/
/// Calculates the element matrix for elInfo and adds it to mat. Memory for
/// mat must be provided by the caller.
virtual void calculateElementMatrix(const ElInfo *elInfo,
ElementMatrix& mat) = 0;
/** \brief
* Calculates the element vector for elInfo and adds it to vec. Memory
* for vec must be provided by the caller.
*/
/// Calculates the element vector for elInfo and adds it to vec. Memory for
/// vec must be provided by the caller.
virtual void calculateElementVector(const ElInfo *elInfo,
ElementVector& vec) = 0;
......@@ -104,10 +100,8 @@ namespace AMDiS {
WorldVector<double>* getCoordsAtQPs(const ElInfo* elInfo,
Quadrature *quad = NULL);
/** \brief
* DOFVector dv evaluated at quadrature points.
* Used by \ref OperatorTerm::initElement().
*/
/// DOFVector dv evaluated at quadrature points.
/// Used by \ref OperatorTerm::initElement().
template<typename T>
void getVectorAtQPs(DOFVectorBase<T>* dv,
const ElInfo* elInfo,
......@@ -122,10 +116,8 @@ namespace AMDiS {
Quadrature *quad,
mtl::dense_vector<T>& vecAtQPs);
/** \brief
* Gradients of DOFVector dv evaluated at quadrature points.
* Used by \ref OperatorTerm::initElement().
*/
/// Gradients of DOFVector dv evaluated at quadrature points.
/// Used by \ref OperatorTerm::initElement().
template<typename T>
void getGradientsAtQPs( DOFVectorBase<T>* dv,
const ElInfo* elInfo,
......@@ -139,11 +131,10 @@ namespace AMDiS {
Quadrature *quad,
mtl::dense_vector<typename GradientType<T>::type>& grdAtQPs);
/** \brief
* The comp'th component of the derivative of DOFVector dv evaluated at quadrature points.
* Used by \ref OperatorTerm::initElement().
* Attention: not caching at the moment! Using cache if gradients for read but not for write
*/
/// The comp'th component of the derivative of DOFVector dv evaluated at
/// quadrature points. Used by \ref OperatorTerm::initElement().
/// Attention: not caching at the moment! Using cache if gradients for read
/// but not for write.
template<typename T>
void getDerivativeAtQPs(DOFVectorBase<T>* dv,
const ElInfo* elInfo,
......@@ -159,11 +150,9 @@ namespace AMDiS {
int comp,
mtl::dense_vector<T>& grdAtQPs);
/** \brief
* Called once for each ElInfo when \ref calculateElementMatrix() or
* \ref calculateElementVector() is called for the first time for this
* Element.
*/
/// Called once for each ElInfo when \ref calculateElementMatrix() or
/// \ref calculateElementVector() is called for the first time for this
/// Element.
virtual void initElement(const ElInfo *smallElInfo,
const ElInfo *largeElInfo = NULL,
Quadrature *quad = NULL);
......@@ -202,16 +191,12 @@ namespace AMDiS {
/// Column FiniteElemSpace.
const FiniteElemSpace *colFeSpace;
/** \brief
* Number of rows of the element matrix and length of the element
* vector. Is equal to the number of row basis functions
*/
/// Number of rows of the element matrix and length of the element
/// vector. Is equal to the number of row basis functions
int nRow;
/** \brief
* Number of columns of the element matrix. Is equal to the number
* of column basis functions
*/
/// Number of columns of the element matrix. Is equal to the number
/// of column basis functions
int nCol;
/// Used for \ref getVectorAtQPs() and \ref getGradientsAtQPs().
......@@ -230,16 +215,15 @@ namespace AMDiS {
std::map<const void*, ValuesAtQPs* > cachedValuesAtQPs;
std::map<const void*, ValuesAtQPs* > cachedGradientsAtQPs;
/** \brief
* Set and updated by \ref initElement() for each ElInfo.
* coordsAtQPs[i] points to the coordinates of the i-th quadrature point.
*/
/// Set and updated by \ref initElement() for each ElInfo.
/// coordsAtQPs[i] points to the coordinates of the i-th quadrature point.
WorldVector<double> *coordsAtQPs;
/// Used for \ref getCoordsAtQPs().
bool coordsValid;
/// Used for \ref getCoordsAtQP(). Stores the number of allocated WorldVectors.
/// Used for \ref getCoordsAtQP(). Stores the number of allocated
/// WorldVectors.
int coordsNumAllocated;
/// Quadrature object to be used for assembling.
......
......@@ -376,6 +376,48 @@ namespace AMDiS {
return;
break;
case EDGE:
{
// === Create boundary information objects for children elements. ===
BoundaryObject nextBound0 = bound;
prepareNextBound(nextBound0, 0);
BoundaryObject nextBound1 = bound;
prepareNextBound(nextBound1, 1);
// === Check for boundary on children elements. ===
if ((nextBound0.ithObj >= 0 || nextBound1.ithObj >= 0) && child[0]) {
// So, the edge is contained in at least on of the children and the
// element is also refined. Then we have go down further in refinement
// hierarchie.
if (bound.reverseMode) {
if (nextBound1.ithObj >= 0)
child[1]->getHigherOrderDofs(feSpace, nextBound1, dofs);
if (nextBound0.ithObj >= 0)
child[0]->getHigherOrderDofs(feSpace, nextBound0, dofs);
} else {
if (nextBound0.ithObj >= 0)
child[0]->getHigherOrderDofs(feSpace, nextBound0, dofs);
if (nextBound1.ithObj >= 0)
child[1]->getHigherOrderDofs(feSpace, nextBound1, dofs);
}
} else {
// Either the edge is not contained in further refined children, or
// the element is not refined further on this edge. Then we can get
// all the DOFs on this edge.
ElementDofIterator elDofIter(feSpace, true);
elDofIter.reset(this);
do {
if (elDofIter.getCurrentPos() == 1 &&
elDofIter.getCurrentElementPos() == bound.ithObj)
dofs.push_back(elDofIter.getDofPtr());
} while(elDofIter.next());
}
}
break;
case FACE:
{
......@@ -403,10 +445,8 @@ namespace AMDiS {
elDofIter.reset(this);
do {
if (elDofIter.getCurrentPos() == 2 &&
elDofIter.getCurrentElementPos() == bound.ithObj) {
ERROR_EXIT("Check this, if it will really work!\n");
elDofIter.getCurrentElementPos() == bound.ithObj)
dofs.push_back(elDofIter.getDofPtr());
}
} while(elDofIter.next());
}
}
......
......@@ -324,10 +324,10 @@ namespace AMDiS {
static const int sideOfChild[3][2][4];
/** \brief
* edgeOfChild[elType][i][j] is the local edge number of the j-th edge within the
* i-th children of an element of elType. If the value is -1, the edge is not
* included in the element's child. Note that the 0 edge is included in both
* children only by its half.
* edgeOfChild[elType][i][j] is the local edge number of the j-th edge within
* the i-th children of an element of elType. If the value is -1, the edge is
* not included in the element's child. Note that the 0 edge is included in
* both children only by its half.
*/
static const int edgeOfChild[3][2][6];
......
......@@ -169,7 +169,7 @@ namespace AMDiS {
break;
default:
ERROR_EXIT("Should never happen!\n");
}
}
}
......
......@@ -77,9 +77,9 @@ namespace AMDiS {
newAssembler = new StandardZOA(op, assembler, quad);
} else {
if (pwConst)
newAssembler = new PrecalcZOA(op, assembler, quad);
newAssembler = new PrecalcZOA(op, assembler, quad);
else
newAssembler = new FastQuadZOA(op, assembler, quad);
newAssembler = new FastQuadZOA(op, assembler, quad);
}
subAssemblers->push_back(newAssembler);
......
......@@ -85,9 +85,12 @@ namespace AMDiS {
periodicFaces[make_pair(face0, face1)] = elInfo->getBoundary(i);
/// Add all three vertices of the face to be periodic.
periodicVertices[make_pair(face0.get<0>(), face1.get<0>())] = boundaryType;
periodicVertices[make_pair(face0.get<1>(), face1.get<1>())] = boundaryType;
periodicVertices[make_pair(face0.get<2>(), face1.get<2>())] = boundaryType;
periodicVertices[make_pair(face0.get<0>(), face1.get<0>())] =
boundaryType;
periodicVertices[make_pair(face0.get<1>(), face1.get<1>())] =
boundaryType;
periodicVertices[make_pair(face0.get<2>(), face1.get<2>())] =
boundaryType;
periodicDofAssoc[face0.get<0>()].insert(boundaryType);
periodicDofAssoc[face0.get<1>()].insert(boundaryType);
......@@ -131,8 +134,8 @@ namespace AMDiS {
TEST_EXIT_DBG(mesh)("Mesh not set!\n");
// === Return, if there are no periodic vertices, i.e., there are no no ===
// === periodic boundaries in the mesh. ===
// === Return, if there are no periodic vertices, i.e., there are no ===
// === periodic boundaries in the mesh. ===
if (periodicVertices.size() == 0)
return;
......@@ -141,9 +144,9 @@ namespace AMDiS {
// === Get all vertex DOFs that have multiple periodic associations. ===
// We group all vertices together, that have either two or three periodic
// associations. For rectangular domains in 2D, the four corner vertices have all
// two periodic associations. For box domains in 3D, the eight corner vertices
// have all three periodic associations.
// associations. For rectangular domains in 2D, the four corner vertices have
// all two periodic associations. For box domains in 3D, the eight corner
// vertices have all three periodic associations.
vector<DegreeOfFreedom> multPeriodicDof2, multPeriodicDof3;
for (map<DegreeOfFreedom, std::set<BoundaryType> >::iterator it = periodicDofAssoc.begin();
......
......@@ -126,11 +126,11 @@ namespace AMDiS {
/** \brief
* Creates final data of the periodic boundaries. Must be called after all
* elements of the mesh are added to the object database. Then this functions
* search for interectly connected vertices in periodic boundaries. This is only
* the case, if there are more than one boundary conditions. Then, e.g., in 2D,
* all edges of a square are iterectly connected. In 3D, if the macro mesh is a
* box, all eight vertex nodes and always four of the 12 edges are iterectly
* connected.
* search for indirectly connected vertices in periodic boundaries. This is
* only the case, if there are more than one boundary conditions. Then, e.g.,
* in 2D, all edges of a square are iterectly connected. In 3D, if the macro
* mesh is a box, all eight vertex nodes and always four of the 12 edges are
* indirectly connected.
*/
void createPeriodicData(const FiniteElemSpace *feSpace);
......
This diff is collapsed.
......@@ -278,47 +278,57 @@ namespace AMDiS {
}
/// Returns the periodic mapping for all boundary DOFs in rank.
inline PeriodicDofMap& getPeriodicMapping()
inline PeriodicDofMap& getPeriodicMapping(const FiniteElemSpace *feSpace)
{
return periodicDof;
return periodicDofMap[feSpace];
}
/// Returns for a global dof index its periodic mapping for a given
/// boundary type.
inline int getPeriodicMapping(int globalDofIndex, BoundaryType type)
/// Returns for a global DOF index of a given FE space its periodic mapping
/// for a given boundary type.
inline int getPeriodicMapping(const FiniteElemSpace *feSpace,
BoundaryType type,
int globalDofIndex)
{
FUNCNAME("MeshDistributor::getPeriodicMapping()");
TEST_EXIT_DBG(periodicDof[type].count(globalDofIndex) == 1)
TEST_EXIT_DBG(periodicDofMap.count(feSpace))("Should not happen!\n");
TEST_EXIT_DBG(periodicDofMap[feSpace][type].count(globalDofIndex) == 1)
("There is no periodic association for global DOF %d for boundary type %d!\n",
globalDofIndex, type);
return periodicDof[type][globalDofIndex];
return periodicDofMap[feSpace][type][globalDofIndex];
}
/// For a given global DOF index, this function returns the set of periodic
/// associations, i.e., the boundary types the DOF is associated to, for
/// this DOF.
inline std::set<BoundaryType>& getPerDofAssociations(int globalDofIndex)
{
TEST_EXIT_DBG(periodicDofAssociations.count(globalDofIndex))
inline std::set<BoundaryType>& getPerDofAssociations(const FiniteElemSpace* feSpace,
int globalDofIndex)
{
FUNCNAME("MeshDistributor::getPerDofAssociations()");
TEST_EXIT_DBG(periodicDofAssociations.count(feSpace))
("Should not happen!\n");
TEST_EXIT_DBG(periodicDofAssociations[feSpace].count(globalDofIndex))
("Should not happen!\n");
return periodicDofAssociations[globalDofIndex];
return periodicDofAssociations[feSpace][globalDofIndex];
}
/// Returns true, if the DOF (global index) is a periodic DOF.
inline bool isPeriodicDof(int globalDofIndex)
inline bool isPeriodicDof(const FiniteElemSpace *feSpace, int globalDofIndex)
{
return (periodicDofAssociations.count(globalDofIndex) > 0 &&
periodicDofAssociations[globalDofIndex].size() > 0);
return (periodicDofAssociations[feSpace].count(globalDofIndex) > 0 &&
periodicDofAssociations[feSpace][globalDofIndex].size() > 0);
}
/// Returns true, if the DOF (global index) is a periodic DOF for the given
/// boundary type.
inline bool isPeriodicDof(int globalDofIndex, BoundaryType type)
/// Returns true, if the DOF (global index) of a given FE space is a
/// periodic DOF for the given boundary type.
inline bool isPeriodicDof(const FiniteElemSpace *feSpace,
BoundaryType type,
int globalDofIndex)
{
return (periodicDof[type].count(globalDofIndex) > 0);
return (periodicDofMap[feSpace][type].count(globalDofIndex) > 0);
}
DofComm& getSendDofs()
......@@ -331,6 +341,11 @@ namespace AMDiS {
return recvDofs;
}
DofComm& getPeriodicDofs()
{
return periodicDofs;
}
/// Return true, if the given DOF is owned by the rank. If false, the DOF
/// is in rank's partition, but is owned by some other rank.
inline bool getIsRankDof(const FiniteElemSpace *feSpace, DegreeOfFreedom dof)
......@@ -470,11 +485,15 @@ namespace AMDiS {
/// changed.
void updateLocalGlobalNumbering(const FiniteElemSpace *feSpace);
/// Calls \ref createPeriodicMap(feSpace) for all FE spaces that are
/// handled by the mesh distributor.
void createPeriodicMap();
/** \brief
* Creates to all dofs in rank's partition that are on a periodic boundary
* the mapping from dof index to the other periodic dof indices. This
* information is stored in \ref periodicDof.
*/
* Creates, for a specific FE space, to all DOFs in rank's partition that
* are on a periodic boundary the mapping from dof index to the other
* periodic dof indices. This information is stored in \ref periodicDofMap.
*/
void createPeriodicMap(const FiniteElemSpace *feSpace);
/** \brief
......@@ -683,13 +702,21 @@ namespace AMDiS {
*/
DofComm recvDofs;
/** \brief
* This map contains on each rank a list of DOFs along the interior bound-
* aries to communicate with other ranks. The DOF indices are given in rank's
* local numbering. Periodic boundaries within one subdomain are not
* considered here.
*/
DofComm periodicDofs;
/** \brief
* If periodic boundaries are used, this map stores, for each periodic
* boundary type, for all DOFs in rank's partition (that are on periodic
* boundaries), the corresponding mapped periodic DOFs. The mapping is
* defined by using global DOF indices.
*/
PeriodicDofMap periodicDof;
PeriodicDofMapFeSpace periodicDofMap;
/** \brief
* If periodic boundaries are used, this map stores to each periodic DOF in
......@@ -698,7 +725,7 @@ namespace AMDiS {
* with all boundaries being periodic, the four corners are associated by
* two different boundaries.
*/
map<int, std::set<BoundaryType> > periodicDofAssociations;
map<const FiniteElemSpace*, map<DegreeOfFreedom, std::set<BoundaryType> > > periodicDofAssociations;
/// This set of values must be interchanged between ranks when the mesh is
......
......@@ -145,15 +145,21 @@ namespace AMDiS {
{
FUNCNAME("ParallelDebug::testPeriodicBoundary()");
return;
for (unsigned int i = 0; i < pdb.feSpaces.size(); i++)
testPeriodicBoundary(pdb, pdb.feSpaces[i]);
}
TEST_EXIT(pdb.feSpaces.size() == 1)("Shoudl not happen!\n");
void ParallelDebug::testPeriodicBoundary(MeshDistributor &pdb,
const FiniteElemSpace *feSpace)
{
FUNCNAME("ParallelDebug::testPeriodicBoundary()");
// === 1. check: All periodic DOFs should have at least a correct number ===
// === of periodic associations. ===
for (map<int, std::set<BoundaryType> >::iterator it = pdb.periodicDofAssociations.begin();
it != pdb.periodicDofAssociations.end(); ++it) {
for (map<int, std::set<BoundaryType> >::iterator it = pdb.periodicDofAssociations[feSpace].begin();
it != pdb.periodicDofAssociations[feSpace].end(); ++it) {
WorldVector<double> c;
pdb.mesh->getDofIndexCoords(it->first, pdb.feSpaces[0], c);
int nAssoc = it->second.size();
......@@ -172,7 +178,7 @@ namespace AMDiS {
for (int i = 1; i < pdb.mpiSize; i++)
stdMpi.recv(i);
} else {
stdMpi.send(0, pdb.periodicDof);
stdMpi.send(0, pdb.periodicDofMap[feSpace]);
}
stdMpi.startCommunication();
......@@ -184,7 +190,7 @@ namespace AMDiS {
if (pdb.mpiRank == 0) {
// Stores to each rank the periodic DOF mappings of this rank.
map<int, PeriodicDofMap> rankToMaps;
PeriodicDofMap dofMap = pdb.periodicDof;
PeriodicDofMap dofMap = pdb.periodicDofMap[feSpace];
rankToMaps[0] = dofMap;
for (int i = 1; i < pdb.mpiSize; i++) {
......@@ -243,9 +249,10 @@ namespace AMDiS {
TEST_EXIT(foundError == 0)("Error found on at least on rank!\n");
// === 3. check: On all edge and face periodic DOFs, at least on coordinate of ===
// === each periodic DOF pair must be equal (at least as long we consider ===
// === periodic boundaries only on rectangulars and boxes. ===
// === 3. check: On all edge and face periodic DOFs, at least one ===
// === componant of coordinates of each periodic DOF pair must be equal ===
// === (at least as long we consider periodic boundaries only on ===
// === rectangulars and boxes. ===
RankToCoords sendCoords;
map<int, vector<BoundaryType> > rankToDofType;
......@@ -261,11 +268,11 @@ namespace AMDiS {
continue;
DofContainer dofs;
boundIt->rankObj.el->getAllDofs(pdb.feSpaces[0], boundIt->rankObj, dofs);
boundIt->rankObj.el->getAllDofs(feSpace, boundIt->rankObj, dofs);
for (unsigned int i = 0; i < dofs.size(); i++) {
WorldVector<double> c;
pdb.mesh->getDofIndexCoords(*(dofs[i]), pdb.feSpaces[0], c);
pdb.mesh->getDofIndexCoords(*(dofs[i]), feSpace, c);
sendCoords[it->first].push_back(c);
rankToDofType[it->first].push_back(boundIt->type);
}
......@@ -298,8 +305,7 @@ namespace AMDiS {
if (c0[j] == c1[j])
nEqual++;
if ((rankToDofType[it->first][i] >= -3 && nEqual < 2) ||
(rankToDofType[it->first][i] < -3 && nEqual == 0)) {
if (nEqual == 0) {
MSG("[DBG] %d-ith periodic DOF in boundary between ranks %d <-> %d is not correct!\n",
i, pdb.mpiRank, it->first);
MSG("[DBG] Coords on rank %d: %f %f %f\n",
......@@ -472,10 +478,14 @@ namespace AMDiS {
CoordsIndexMap coordsToIndex;
DOFIterator<WorldVector<double> > it(&coords, USED_DOFS);
for (it.reset(); !it.end(); ++it)
for (it.reset(); !it.end(); ++it) {
coordsToIndex[(*it)] =
pdb.dofFeData[feSpace].mapLocalGlobalDofs[it.getDOFIndex()];
// MSG(" CHECK FOR DOF %d AT COORDS %f %f %f\n",
// coordsToIndex[(*it)], (*it)[0], (*it)[1], (*it)[2]);
}
StdMpi<CoordsIndexMap> stdMpi(pdb.mpiComm, true);
for (DofComm::Iterator it(pdb.sendDofs, feSpace); !it.end(); it.nextRank())
stdMpi.send(it.getRank(), coordsToIndex);
......@@ -499,7 +509,7 @@ namespace AMDiS {
oss << coordsIt->first[i] << " ";
oss << " do not fit together on rank "
<< pdb.getMpiRank() << " (global index: "
<< coordsToIndex[coordsIt->first] << " and on rank "
<< coordsToIndex[coordsIt->first] << ") and on rank "
<< it.getRank() << " (global index: " << coordsIt->second << ")";
MSG("[DBG] %s\n", oss.str().c_str());
......@@ -676,8 +686,8 @@ namespace AMDiS {
if (rank == -1 || pdb.mpiRank == rank) {
cout << "====== DOF MAP PERIODIC ====== " << endl;
for (PeriodicDofMap::iterator it = pdb.periodicDof.begin();
it != pdb.periodicDof.end(); ++it) {
for (PeriodicDofMap::iterator it = pdb.periodicDofMap.begin();
it != pdb.periodicDofMap.end(); ++it) {
cout << "DOF MAP " << it->first << ": ";
for (std::set<DegreeOfFreedom>::iterator dofit = it->second.begin();
dofit != it->second.end(); ++dofit)
......
......@@ -52,6 +52,15 @@ namespace AMDiS {
*/
static void testPeriodicBoundary(MeshDistributor &pdb);
/** \brief
* Test if all periodic boundaries are set in a consistent way on all ranks.
*
* \param[in] pdb Parallel problem definition used for debugging.
* \oaram[in] feSpace FE space for which the DOFs are tested.