Commit 3056a9f6 authored by Thomas Witkowski's avatar Thomas Witkowski

Fixed problem for repartitioning with periodic boundary conditions.

parent df31712a
......@@ -90,13 +90,13 @@ namespace AMDiS {
/** \brief
* This class is a database of element objects. An element object is either a
* vertex, edge or the face of a specific element. This database is used to store
* all objects of all elements of a mesh. The information is stored in a way that
* makes it possible to identify all elements, which have a given vertex, edge or
* face in common. If is is known which element is owned by which rank in parallel
* computations, it is thus possible to get all interior boundaries on object
* level. This is required, because two elements may share a common vertex without
* beging neighbours in the definition of AMDiS.
* vertex, edge or the face of a specific element. This database is used to
* store all objects of all elements of a mesh. The information is stored in a
* way that makes it possible to identify all elements, which have a given
* vertex, edge or face in common. If is is known which element is owned by
* which rank in parallel computations, it is thus possible to get all interior
* boundaries on object level. This is required, because two elements may share
* a common vertex without beging neighbours in the definition of AMDiS.
*/
class ElementObjects {
public:
......@@ -114,9 +114,9 @@ namespace AMDiS {
/** \brief
* Adds an element to the object database. If the element is part of a periodic
* boundary, all information about subobjects of the element on this boundary
* are collected.
* Adds an element to the object database. If the element is part of a
* periodic boundary, all information about subobjects of the element on
* this boundary are collected.
*
* \param[in] elInfo ElInfo object of the element.
*/
......@@ -136,15 +136,16 @@ namespace AMDiS {
/** \brief
* Create for a filled object database the membership information for all element
* objects. An object is owned by a rank, if the rank has the heighest rank
* number of all ranks where the object is part of.
* Create for a filled object database the membership information for all
* element objects. An object is owned by a rank, if the rank has the
* heighest rank number of all ranks where the object is part of.
*
* \param[in] macroElementRankMap Maps to each macro element of the mesh the
* rank that owns this macro element.
* \param[in] macroElementRankMap Maps to each macro element of the mesh
* the rank that owns this macro element.
*/
void createRankData(map<int, int>& macroElementRankMap);
/** \brief
* Creates on all boundaries the reverse mode flag.
*
......@@ -162,12 +163,12 @@ namespace AMDiS {
/** \brief
* Iterates over all elements for one geometrical index, i.e., over all vertices,
* edges or faces in the mesh. The function returns true, if the result is valid.
* Otherwise the iterator is at the end position.
* Iterates over all elements for one geometrical index, i.e., over all
* vertices, edges or faces in the mesh. The function returns true, if the
* result is valid. Otherwise the iterator is at the end position.
*
* \param[in] pos Must be either VERTEX, EDGE or FACE and defines the elements
* that should be traversed.
* \param[in] pos Must be either VERTEX, EDGE or FACE and defines the
* elements that should be traversed.
*/
bool iterate(GeoIndex pos)
{
......@@ -419,7 +420,8 @@ namespace AMDiS {
return periodicFaces;
}
inline bool getEdgeReverseMode(ElementObjectData &obj0, ElementObjectData &obj1)
inline bool getEdgeReverseMode(ElementObjectData &obj0,
ElementObjectData &obj1)
{
if (mesh->getDim() == 2)
return true;
......@@ -430,7 +432,8 @@ namespace AMDiS {
return edgeReverseMode[make_pair(obj0, obj1)];
}
inline bool getFaceReverseMode(ElementObjectData &obj0, ElementObjectData &obj1)
inline bool getFaceReverseMode(ElementObjectData &obj0,
ElementObjectData &obj1)
{
TEST_EXIT_DBG(faceReverseMode.count(make_pair(obj0, obj1)))
("Should not happen!\n");
......@@ -540,12 +543,12 @@ namespace AMDiS {
/// objects that have this vertex DOF in common.
map<DegreeOfFreedom, map<int, ElementObjectData> > vertexInRank;
/// Defines to each edge a map that maps to each rank number the element objects
/// that have this edge in common.
/// Defines to each edge a map that maps to each rank number the element
/// objects that have this edge in common.
map<DofEdge, map<int, ElementObjectData> > edgeInRank;
/// Defines to each face a map that maps to each rank number the element objects
/// that have this face in common.
/// Defines to each face a map that maps to each rank number the element
/// objects that have this face in common.
map<DofFace, map<int, ElementObjectData> > faceInRank;
......
......@@ -94,16 +94,10 @@ namespace AMDiS {
mpiSize = MPI::COMM_WORLD.Get_size();
mpiComm = MPI::COMM_WORLD;
int tmp = 0;
Parameters::get(name + "->repartitioning", tmp);
repartitioningAllowed = (tmp > 0);
Parameters::get(name + "->repartitioning", repartitioningAllowed);
Parameters::get(name + "->debug output dir", debugOutputDir);
Parameters::get(name + "->repartition ith change", repartitionIthChange);
tmp = 0;
Parameters::get(name + "->log main rank", tmp);
Msg::outputMainRank = (tmp > 0);
Parameters::get(name + "->log main rank", Msg::outputMainRank);
string partStr = "parmetis";
Parameters::get(name + "->partitioner", partStr);
......@@ -125,7 +119,7 @@ namespace AMDiS {
if (partStr == "simple")
partitioner = new SimplePartitioner(&mpiComm);
tmp = 0;
int tmp = 0;
Parameters::get(name + "->box partitioning", tmp);
partitioner->setBoxPartitioning(static_cast<bool>(tmp));
......@@ -874,7 +868,7 @@ namespace AMDiS {
repartitionMesh();
nMeshChangesAfterLastRepartitioning = 0;
} else {
MSG_DBG("Repartitioning not tried because tryRepartitioning = %d reparttitioningAllowed = %d nMeshChange =%d repartitionIthChange = %d\n",
MSG_DBG("Repartitioning not tried because tryRepartitioning = %d repartitioningAllowed = %d nMeshChange = %d repartitionIthChange = %d\n",
tryRepartition, repartitioningAllowed,
nMeshChangesAfterLastRepartitioning, repartitionIthChange);
}
......@@ -896,15 +890,18 @@ namespace AMDiS {
if (mpiRank == 0) {
int nOverallDofs = 0;
int maxDofs = numeric_limits<int>::min();
int minDofs = numeric_limits<int>::max();
for (int i = 0; i < mpiSize; i++) {
nOverallDofs += nDofsInRank[i];
maxDofs = std::max(maxDofs, nDofsInRank[i]);
minDofs = std::min(minDofs, nDofsInRank[i]);
}
int avrgDofs = nOverallDofs / mpiSize;
double imbalance =
(static_cast<double>(maxDofs - avrgDofs) / avrgDofs) * 100.0;
// int avrgDofs = nOverallDofs / mpiSize;
// double imbalance0 =
// (static_cast<double>(maxDofs - avrgDofs) / avrgDofs) * 100.0;
double imbalance1 = (static_cast<double>(maxDofs) / minDofs - 1.0) * 100.0;
MSG("Imbalancing factor: %.1f\%\n", imbalance);
MSG("Imbalancing factor: %.1f\%\n", imbalance1);
}
}
......@@ -1157,12 +1154,18 @@ namespace AMDiS {
// === Run mesh partitioner to calculate a new mesh partitioning. ===
partitioner->setLocalGlobalDofMap(&(dofFeData[feSpaces[0]].mapDofToGlobal));
bool partitioningSucceed = partitioner->partition(elemWeights, ADAPTIVE_REPART);
bool partitioningSucceed =
partitioner->partition(elemWeights, ADAPTIVE_REPART);
if (!partitioningSucceed) {
MSG("Mesh partitioner created empty partition!\n");
return;
}
// In the case the partitioner does not create a new mesh partition, return
// without and changes.
if (!partitioner->meshChanged())
return;
// === Create map that maps macro element indices to pointers to the ===
// === macro elements. ===
......@@ -2023,13 +2026,17 @@ namespace AMDiS {
{
FUNCNAME("MeshDistributor::createPeriodicMap()");
if (periodicBoundary.boundary.size() == 0)
return;
// Clear all periodic DOF mappings calculated before. We do it from scratch.
periodicDofs.clear();
periodicMap.clear();
// If there are no periodic boundaries, return. Note that periodicDofs and
// periodicMap must be still cleared before: if we do repartitioning and
// there were periodic boundaries in subdomain before and after repartitioning
// there are no more periodic boundaries.
if (periodicBoundary.boundary.size() == 0)
return;
for (unsigned int i = 0; i < feSpaces.size(); i++)
createPeriodicMap(feSpaces[i]);
}
......
......@@ -29,13 +29,13 @@
#include "AMDiS_fwd.h"
#include "Mesh.h"
#include "parallel/MpiHelper.h"
namespace AMDiS {
namespace AMDiS {
using namespace std;
enum PartitionMode {
INITIAL = 0, // initial partitioning of a unpartitioned mesh
ADAPTIVE_REPART = 1, // repartitioning of a adaptively refined mesh
......@@ -130,6 +130,16 @@ namespace AMDiS {
{
return sendElements;
}
/// After mesh repartition this function returns true if the mesh must be
/// redistributed on at least one rank.
bool meshChanged()
{
int nChanges = recvElements.size() + sendElements.size();
mpi::globalAdd(nChanges);
return static_cast<bool>(nChanges);
}
protected:
/// Pointer to the MPI communicator the mesh partitioner should make use of.
......@@ -170,6 +180,8 @@ namespace AMDiS {
/// partitiong mode) the rank number the element belongs to.
map<int, int> partitionMap;
/// After mesh repartitioning these maps stores which elements are communicated
/// from this rank to other ranks.
map<int, vector<int> > recvElements, sendElements;
};
}
......
......@@ -398,6 +398,8 @@ namespace AMDiS {
MSG("nRankDuals = %d nOverallDuals = %d\n",
dualDofMap[feSpace].nRankDofs,
dualDofMap[feSpace].nOverallDofs);
nLocalDuals = dualDofMap[feSpace].size();
}
......@@ -409,26 +411,26 @@ namespace AMDiS {
// === appropriate number of Lagrange constraints. ===
const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(0);
dofFirstLagrange.addFeSpace(feSpace);
lagrangeMap.addFeSpace(feSpace);
int nRankLagrange = 0;
DofMapping& dualMap = dualDofMap[feSpace].getMap();
for (DofMapping::iterator it = dualMap.begin(); it != dualMap.end(); ++it) {
if (meshDistributor->getIsRankDof(feSpace, it->first)) {
dofFirstLagrange[feSpace].insert(it->first, nRankLagrange);
lagrangeMap[feSpace].insert(it->first, nRankLagrange);
int degree = boundaryDofRanks[it->first].size();
nRankLagrange += (degree * (degree - 1)) / 2;
}
}
dofFirstLagrange[feSpace].nRankDofs = nRankLagrange;
dofFirstLagrange[feSpace].update();
lagrangeMap[feSpace].nRankDofs = nRankLagrange;
lagrangeMap[feSpace].update();
MSG("nRankLagrange = %d nOverallLagrange = %d\n",
dofFirstLagrange[feSpace].nRankDofs,
dofFirstLagrange[feSpace].nOverallDofs);
lagrangeMap[feSpace].nRankDofs,
lagrangeMap[feSpace].nOverallDofs);
// === Communicate dofFirstLagrange to all other ranks. ===
// === Communicate lagrangeMap to all other ranks. ===
StdMpi<vector<int> > stdMpi(meshDistributor->getMpiComm());
......@@ -436,9 +438,7 @@ namespace AMDiS {
!it.end(); it.nextRank()) {
for (; !it.endDofIter(); it.nextDof())
if (primalDofMap[feSpace].isSet(it.getDofIndex()) == false) {
TEST_EXIT_DBG(dofFirstLagrange[feSpace].isSet(it.getDofIndex()))
("Should not happen!\n");
DegreeOfFreedom d = dofFirstLagrange[feSpace][it.getDofIndex()];
DegreeOfFreedom d = lagrangeMap[feSpace][it.getDofIndex()];
stdMpi.getSendData(it.getRank()).push_back(d);
}
}
......@@ -466,7 +466,7 @@ namespace AMDiS {
for (; !it.endDofIter(); it.nextDof()) {
if (primalDofMap[feSpace].isSet(it.getDofIndex()) == false) {
DegreeOfFreedom d = stdMpi.getRecvData(it.getRank())[counter++];
dofFirstLagrange[feSpace].insert(it.getDofIndex(), d);
lagrangeMap[feSpace].insert(it.getDofIndex(), d);
}
}
}
......@@ -475,36 +475,29 @@ namespace AMDiS {
void PetscSolverFeti::createIndexB()
{
FUNCNAME("PetscSolverFeti::createIndeB()");
FUNCNAME("PetscSolverFeti::createIndexB()");
const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(0);
localIndexB.clear();
localDofMap.addFeSpace(feSpace);
DOFAdmin* admin = feSpace->getAdmin();
// === To ensure that all interior node on each rank are listen first in ===
// === the global index of all B nodes, insert all interior nodes first, ===
// === without defining a correct index. ===
for (int i = 0; i < admin->getUsedSize(); i++)
nLocalInterior = 0;
for (int i = 0; i < admin->getUsedSize(); i++) {
if (admin->isDofFree(i) == false &&
primalDofMap[feSpace].isSet(i) == false &&
dualDofMap[feSpace].isSet(i) == false)
localIndexB[i] = -1;
// === Get correct index for all interior nodes. ===
nLocalInterior = 0;
for (DofMapping::iterator it = localIndexB.begin();
it != localIndexB.end(); ++it) {
it->second = nLocalInterior;
nLocalInterior++;
dualDofMap[feSpace].isSet(i) == false) {
localDofMap[feSpace].insertRankDof(i);
nLocalInterior++;
}
}
nLocalDuals = dualDofMap[feSpace].size();
TEST_EXIT_DBG(nLocalInterior +
primalDofMap[feSpace].size() +
dualDofMap[feSpace].size() ==
nLocalDuals ==
static_cast<unsigned int>(admin->getUsedDofs()))
("Should not happen!\n");
......@@ -513,7 +506,8 @@ namespace AMDiS {
for (DofMapping::iterator it = dualDofMap[feSpace].getMap().begin();
it != dualDofMap[feSpace].getMap().end(); ++it)
localIndexB[it->first] = it->second - rStartB;
localDofMap[feSpace].insert(it->first, it->second - rStartB);
// localDofMap[feSpace].insertRankDof(it->first);
}
......@@ -526,9 +520,9 @@ namespace AMDiS {
// === Create distributed matrix for Lagrange constraints. ===
MatCreateMPIAIJ(PETSC_COMM_WORLD,
dofFirstLagrange[feSpace].nRankDofs * nComponents,
lagrangeMap[feSpace].nRankDofs * nComponents,
nRankB * nComponents,
dofFirstLagrange[feSpace].nOverallDofs * nComponents,
lagrangeMap[feSpace].nOverallDofs * nComponents,
nOverallB * nComponents,
2, PETSC_NULL, 2, PETSC_NULL,
&mat_lagrange);
......@@ -542,13 +536,11 @@ namespace AMDiS {
DofMapping &dualMap = dualDofMap[feSpace].getMap();
for (DofMapping::iterator it = dualMap.begin(); it != dualMap.end(); ++it) {
TEST_EXIT_DBG(dofFirstLagrange[feSpace].isSet(it->first))
("Should not happen!\n");
TEST_EXIT_DBG(boundaryDofRanks.count(it->first))
("Should not happen!\n");
// Global index of the first Lagrange constriant for this node.
int index = dofFirstLagrange[feSpace][it->first];
int index = lagrangeMap[feSpace][it->first];
// Copy set of all ranks that contain this dual node.
vector<int> W(boundaryDofRanks[it->first].begin(),
boundaryDofRanks[it->first].end());
......@@ -742,18 +734,18 @@ namespace AMDiS {
nRankB * nComponents, nOverallB * nComponents,
&(fetiData.tmp_vec_b));
VecCreateMPI(PETSC_COMM_WORLD,
dofFirstLagrange[feSpace].nRankDofs * nComponents,
dofFirstLagrange[feSpace].nOverallDofs * nComponents,
lagrangeMap[feSpace].nRankDofs * nComponents,
lagrangeMap[feSpace].nOverallDofs * nComponents,
&(fetiData.tmp_vec_lagrange));
VecCreateMPI(PETSC_COMM_WORLD,
primalDofMap[feSpace].nRankDofs * nComponents, primalDofMap[feSpace].nOverallDofs * nComponents,
&(fetiData.tmp_vec_primal));
MatCreateShell(PETSC_COMM_WORLD,
dofFirstLagrange[feSpace].nRankDofs * nComponents,
dofFirstLagrange[feSpace].nRankDofs * nComponents,
dofFirstLagrange[feSpace].nOverallDofs * nComponents,
dofFirstLagrange[feSpace].nOverallDofs * nComponents,
lagrangeMap[feSpace].nRankDofs * nComponents,
lagrangeMap[feSpace].nRankDofs * nComponents,
lagrangeMap[feSpace].nOverallDofs * nComponents,
lagrangeMap[feSpace].nOverallDofs * nComponents,
&fetiData, &mat_feti);
MatShellSetOperation(mat_feti, MATOP_MULT, (void(*)(void))petscMultMatFeti);
......@@ -942,8 +934,8 @@ namespace AMDiS {
for (int i = 0; i < nComponents; i++) {
DOFVector<double>& dofVec = *(vec.getDOFVector(i));
for (DofMapping::iterator it = localIndexB.begin();
it != localIndexB.end(); ++it) {
for (DofMapping::iterator it = localDofMap[feSpace].getMap().begin();
it != localDofMap[feSpace].getMap().end(); ++it) {
int petscIndex = it->second * nComponents + i;
dofVec[it->first] = localSolB[petscIndex];
}
......@@ -973,7 +965,8 @@ namespace AMDiS {
primalDofMap.setMpiComm(mpiComm);
dualDofMap.setMpiComm(mpiComm);
dofFirstLagrange.setMpiComm(mpiComm);
lagrangeMap.setMpiComm(mpiComm);
localDofMap.setMpiComm(mpiComm);
updateDofData();
// === Create matrices for the FETI-DP method. ===
......@@ -1100,11 +1093,8 @@ namespace AMDiS {
} else {
// Column is not a primal variable.
TEST_EXIT_DBG(localIndexB.count(col(*icursor)))
("No global B index for DOF %d!\n", col(*icursor));
int colIndex =
(localIndexB[col(*icursor)] + rStartB) * nComponents + j;
(localDofMap[feSpace][col(*icursor)] + rStartB) * nComponents + j;
if (rowPrimal) {
colsOther.push_back(colIndex);
......@@ -1120,17 +1110,17 @@ namespace AMDiS {
// === For preconditioner ===
if (!rowPrimal && !colPrimal) {
int rowIndex = localIndexB[*cursor];
int colIndex = localIndexB[col(*icursor)];
int rowIndex = localDofMap[feSpace][*cursor];
int colIndex = localDofMap[feSpace][col(*icursor)];
if (rowIndex < nLocalInterior) {
if (colIndex < nLocalInterior) {
int colIndex2 = localIndexB[col(*icursor)] * nComponents + j;
int colIndex2 = localDofMap[feSpace][col(*icursor)] * nComponents + j;
colsLocal.push_back(colIndex2);
valuesLocal.push_back(value(*icursor));
} else {
int colIndex2 = (localIndexB[col(*icursor)] - nLocalInterior) *
int colIndex2 = (localDofMap[feSpace][col(*icursor)] - nLocalInterior) *
nComponents + j;
colsLocalOther.push_back(colIndex2);
......@@ -1138,12 +1128,12 @@ namespace AMDiS {
}
} else {
if (colIndex < nLocalInterior) {
int colIndex2 = localIndexB[col(*icursor)] * nComponents + j;
int colIndex2 = localDofMap[feSpace][col(*icursor)] * nComponents + j;
colsLocalOther.push_back(colIndex2);
valuesLocalOther.push_back(value(*icursor));
} else {
int colIndex2 = (localIndexB[col(*icursor)] - nLocalInterior) *
int colIndex2 = (localDofMap[feSpace][col(*icursor)] - nLocalInterior) *
nComponents + j;
colsLocal.push_back(colIndex2);
......@@ -1165,10 +1155,7 @@ namespace AMDiS {
MatSetValues(mat_primal_b, 1, &rowIndex, colsOther.size(),
&(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
} else {
TEST_EXIT_DBG(localIndexB.count(*cursor))
("Should not happen!\n");
int localRowIndex = localIndexB[*cursor] * nComponents + i;
int localRowIndex = localDofMap[feSpace][*cursor] * nComponents + i;
for (unsigned int k = 0; k < cols.size(); k++)
cols[k] -= rStartB * nComponents;
MatSetValues(mat_b_b, 1, &localRowIndex, cols.size(),
......@@ -1176,7 +1163,7 @@ namespace AMDiS {
if (colsOther.size()) {
int globalRowIndex =
(localIndexB[*cursor] + rStartB) * nComponents + i;
(localDofMap[feSpace][*cursor] + rStartB) * nComponents + i;
MatSetValues(mat_b_primal, 1, &globalRowIndex, colsOther.size(),
&(colsOther[0]), &(valuesOther[0]), ADD_VALUES);
}
......@@ -1188,10 +1175,10 @@ namespace AMDiS {
switch (fetiPreconditioner) {
case FETI_DIRICHLET:
{
int rowIndex = localIndexB[*cursor];
int rowIndex = localDofMap[feSpace][*cursor];
if (rowIndex < nLocalInterior) {
int rowIndex2 = localIndexB[*cursor] * nComponents + i;
int rowIndex2 = localDofMap[feSpace][*cursor] * nComponents + i;
MatSetValues(mat_interior_interior, 1, &rowIndex2, colsLocal.size(),
&(colsLocal[0]), &(valuesLocal[0]), INSERT_VALUES);
......@@ -1201,7 +1188,7 @@ namespace AMDiS {
&(colsLocalOther[0]), &(valuesLocalOther[0]), INSERT_VALUES);
} else {
int rowIndex2 =
(localIndexB[*cursor] - nLocalInterior) * nComponents + i;
(localDofMap[feSpace][*cursor] - nLocalInterior) * nComponents + i;
MatSetValues(mat_duals_duals, 1, &rowIndex2, colsLocal.size(),
&(colsLocal[0]), &(valuesLocal[0]), INSERT_VALUES);
......@@ -1216,11 +1203,11 @@ namespace AMDiS {
case FETI_LUMPED:
{
int rowIndex = localIndexB[*cursor];
int rowIndex = localDofMap[feSpace][*cursor];
if (rowIndex >= nLocalInterior) {
int rowIndex2 =
(localIndexB[*cursor] - nLocalInterior) * nComponents + i;
(localDofMap[feSpace][*cursor] - nLocalInterior) * nComponents + i;
MatSetValues(mat_duals_duals, 1, &rowIndex2, colsLocal.size(),
&(colsLocal[0]), &(valuesLocal[0]), INSERT_VALUES);
......@@ -1316,10 +1303,7 @@ namespace AMDiS {
double value = *dofIt;
VecSetValues(f_primal, 1, &index, &value, ADD_VALUES);
} else {
TEST_EXIT_DBG(localIndexB.count(index))
("Should not happen!\n");
index = (localIndexB[index] + rStartB) * nComponents + i;
index = (localDofMap[feSpace][index] + rStartB) * nComponents + i;
VecSetValue(f_b, index, *dofIt, INSERT_VALUES);
}
}
......@@ -1376,7 +1360,7 @@ namespace AMDiS {
int nOverallNest =
(nOverallB +
primalDofMap[feSpace].nOverallDofs +
dofFirstLagrange[feSpace].nOverallDofs) * nComponents;
lagrangeMap[feSpace].nOverallDofs) * nComponents;
Mat mat_lagrange_transpose;
MatTranspose(mat_lagrange, MAT_INITIAL_MATRIX, &mat_lagrange_transpose);
......@@ -1460,8 +1444,8 @@ namespace AMDiS {
// === mat_lagrange ===
for (int i = 0; i < dofFirstLagrange[feSpace].nRankDofs * nComponents; i++) {
int rowIndex = dofFirstLagrange[feSpace].rStartDofs * nComponents + i;
for (int i = 0; i < lagrangeMap[feSpace].nRankDofs * nComponents; i++) {
int rowIndex = lagrangeMap[feSpace].rStartDofs * nComponents + i;
MatGetRow(mat_lagrange, rowIndex, &nCols, &cols, &vals);
int rowIndexA = (nOverallB + primalDofMap[feSpace].nOverallDofs) * nComponents + rowIndex;
......
......@@ -156,19 +156,19 @@ namespace AMDiS {
/// Stores to each dual DOF index the index of the first Lagrange
/// constraint that is assigned to this DOF.
FeSpaceData<GlobalDofMap> dofFirstLagrange;
/// Stores to each dual boundary DOF the set of ranks in which the DOF
/// is contained in.
DofIndexToPartitions boundaryDofRanks;
FeSpaceData<GlobalDofMap> lagrangeMap;
/// Index for each non primal variables to the global index of
/// B variables.
DofMapping globalIndexB, localIndexB;
FeSpaceData<GlobalDofMap> localDofMap;
/// Number of non primal, thus B, variables on rank and globally.
int nRankB, nOverallB, rStartB;
/// Stores to each dual boundary DOF the set of ranks in which the DOF
/// is contained in.
DofIndexToPartitions boundaryDofRanks;
/// Global PETSc matrix of non primal variables.
Mat mat_b_b;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment