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

Fixed problem for repartitioning with periodic boundary conditions.

parent df31712a
...@@ -90,13 +90,13 @@ namespace AMDiS { ...@@ -90,13 +90,13 @@ namespace AMDiS {
/** \brief /** \brief
* This class is a database of element objects. An element object is either a * 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 * vertex, edge or the face of a specific element. This database is used to
* all objects of all elements of a mesh. The information is stored in a way that * store all objects of all elements of a mesh. The information is stored in a
* makes it possible to identify all elements, which have a given vertex, edge or * way that makes it possible to identify all elements, which have a given
* face in common. If is is known which element is owned by which rank in parallel * vertex, edge or face in common. If is is known which element is owned by
* computations, it is thus possible to get all interior boundaries on object * which rank in parallel computations, it is thus possible to get all interior
* level. This is required, because two elements may share a common vertex without * boundaries on object level. This is required, because two elements may share
* beging neighbours in the definition of AMDiS. * a common vertex without beging neighbours in the definition of AMDiS.
*/ */
class ElementObjects { class ElementObjects {
public: public:
...@@ -114,9 +114,9 @@ namespace AMDiS { ...@@ -114,9 +114,9 @@ namespace AMDiS {
/** \brief /** \brief
* Adds an element to the object database. If the element is part of a periodic * Adds an element to the object database. If the element is part of a
* boundary, all information about subobjects of the element on this boundary * periodic boundary, all information about subobjects of the element on
* are collected. * this boundary are collected.
* *
* \param[in] elInfo ElInfo object of the element. * \param[in] elInfo ElInfo object of the element.
*/ */
...@@ -136,15 +136,16 @@ namespace AMDiS { ...@@ -136,15 +136,16 @@ namespace AMDiS {
/** \brief /** \brief
* Create for a filled object database the membership information for all element * Create for a filled object database the membership information for all
* objects. An object is owned by a rank, if the rank has the heighest rank * element objects. An object is owned by a rank, if the rank has the
* number of all ranks where the object is part of. * heighest rank number of all ranks where the object is part of.
* *
* \param[in] macroElementRankMap Maps to each macro element of the mesh the * \param[in] macroElementRankMap Maps to each macro element of the mesh
* rank that owns this macro element. * the rank that owns this macro element.
*/ */
void createRankData(map<int, int>& macroElementRankMap); void createRankData(map<int, int>& macroElementRankMap);
/** \brief /** \brief
* Creates on all boundaries the reverse mode flag. * Creates on all boundaries the reverse mode flag.
* *
...@@ -162,12 +163,12 @@ namespace AMDiS { ...@@ -162,12 +163,12 @@ namespace AMDiS {
/** \brief /** \brief
* Iterates over all elements for one geometrical index, i.e., over all vertices, * Iterates over all elements for one geometrical index, i.e., over all
* edges or faces in the mesh. The function returns true, if the result is valid. * vertices, edges or faces in the mesh. The function returns true, if the
* Otherwise the iterator is at the end position. * 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 * \param[in] pos Must be either VERTEX, EDGE or FACE and defines the
* that should be traversed. * elements that should be traversed.
*/ */
bool iterate(GeoIndex pos) bool iterate(GeoIndex pos)
{ {
...@@ -419,7 +420,8 @@ namespace AMDiS { ...@@ -419,7 +420,8 @@ namespace AMDiS {
return periodicFaces; return periodicFaces;
} }
inline bool getEdgeReverseMode(ElementObjectData &obj0, ElementObjectData &obj1) inline bool getEdgeReverseMode(ElementObjectData &obj0,
ElementObjectData &obj1)
{ {
if (mesh->getDim() == 2) if (mesh->getDim() == 2)
return true; return true;
...@@ -430,7 +432,8 @@ namespace AMDiS { ...@@ -430,7 +432,8 @@ namespace AMDiS {
return edgeReverseMode[make_pair(obj0, obj1)]; 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))) TEST_EXIT_DBG(faceReverseMode.count(make_pair(obj0, obj1)))
("Should not happen!\n"); ("Should not happen!\n");
...@@ -540,12 +543,12 @@ namespace AMDiS { ...@@ -540,12 +543,12 @@ namespace AMDiS {
/// objects that have this vertex DOF in common. /// objects that have this vertex DOF in common.
map<DegreeOfFreedom, map<int, ElementObjectData> > vertexInRank; map<DegreeOfFreedom, map<int, ElementObjectData> > vertexInRank;
/// Defines to each edge a map that maps to each rank number the element objects /// Defines to each edge a map that maps to each rank number the element
/// that have this edge in common. /// objects that have this edge in common.
map<DofEdge, map<int, ElementObjectData> > edgeInRank; map<DofEdge, map<int, ElementObjectData> > edgeInRank;
/// Defines to each face a map that maps to each rank number the element objects /// Defines to each face a map that maps to each rank number the element
/// that have this face in common. /// objects that have this face in common.
map<DofFace, map<int, ElementObjectData> > faceInRank; map<DofFace, map<int, ElementObjectData> > faceInRank;
......
...@@ -94,16 +94,10 @@ namespace AMDiS { ...@@ -94,16 +94,10 @@ namespace AMDiS {
mpiSize = MPI::COMM_WORLD.Get_size(); mpiSize = MPI::COMM_WORLD.Get_size();
mpiComm = MPI::COMM_WORLD; mpiComm = MPI::COMM_WORLD;
int tmp = 0; Parameters::get(name + "->repartitioning", repartitioningAllowed);
Parameters::get(name + "->repartitioning", tmp);
repartitioningAllowed = (tmp > 0);
Parameters::get(name + "->debug output dir", debugOutputDir); Parameters::get(name + "->debug output dir", debugOutputDir);
Parameters::get(name + "->repartition ith change", repartitionIthChange); Parameters::get(name + "->repartition ith change", repartitionIthChange);
Parameters::get(name + "->log main rank", Msg::outputMainRank);
tmp = 0;
Parameters::get(name + "->log main rank", tmp);
Msg::outputMainRank = (tmp > 0);
string partStr = "parmetis"; string partStr = "parmetis";
Parameters::get(name + "->partitioner", partStr); Parameters::get(name + "->partitioner", partStr);
...@@ -125,7 +119,7 @@ namespace AMDiS { ...@@ -125,7 +119,7 @@ namespace AMDiS {
if (partStr == "simple") if (partStr == "simple")
partitioner = new SimplePartitioner(&mpiComm); partitioner = new SimplePartitioner(&mpiComm);
tmp = 0; int tmp = 0;
Parameters::get(name + "->box partitioning", tmp); Parameters::get(name + "->box partitioning", tmp);
partitioner->setBoxPartitioning(static_cast<bool>(tmp)); partitioner->setBoxPartitioning(static_cast<bool>(tmp));
...@@ -874,7 +868,7 @@ namespace AMDiS { ...@@ -874,7 +868,7 @@ namespace AMDiS {
repartitionMesh(); repartitionMesh();
nMeshChangesAfterLastRepartitioning = 0; nMeshChangesAfterLastRepartitioning = 0;
} else { } 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, tryRepartition, repartitioningAllowed,
nMeshChangesAfterLastRepartitioning, repartitionIthChange); nMeshChangesAfterLastRepartitioning, repartitionIthChange);
} }
...@@ -896,15 +890,18 @@ namespace AMDiS { ...@@ -896,15 +890,18 @@ namespace AMDiS {
if (mpiRank == 0) { if (mpiRank == 0) {
int nOverallDofs = 0; int nOverallDofs = 0;
int maxDofs = numeric_limits<int>::min(); int maxDofs = numeric_limits<int>::min();
int minDofs = numeric_limits<int>::max();
for (int i = 0; i < mpiSize; i++) { for (int i = 0; i < mpiSize; i++) {
nOverallDofs += nDofsInRank[i]; nOverallDofs += nDofsInRank[i];
maxDofs = std::max(maxDofs, nDofsInRank[i]); maxDofs = std::max(maxDofs, nDofsInRank[i]);
minDofs = std::min(minDofs, nDofsInRank[i]);
} }
int avrgDofs = nOverallDofs / mpiSize; // int avrgDofs = nOverallDofs / mpiSize;
double imbalance = // double imbalance0 =
(static_cast<double>(maxDofs - avrgDofs) / avrgDofs) * 100.0; // (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 { ...@@ -1157,12 +1154,18 @@ namespace AMDiS {
// === Run mesh partitioner to calculate a new mesh partitioning. === // === Run mesh partitioner to calculate a new mesh partitioning. ===
partitioner->setLocalGlobalDofMap(&(dofFeData[feSpaces[0]].mapDofToGlobal)); partitioner->setLocalGlobalDofMap(&(dofFeData[feSpaces[0]].mapDofToGlobal));
bool partitioningSucceed = partitioner->partition(elemWeights, ADAPTIVE_REPART); bool partitioningSucceed =
partitioner->partition(elemWeights, ADAPTIVE_REPART);
if (!partitioningSucceed) { if (!partitioningSucceed) {
MSG("Mesh partitioner created empty partition!\n"); MSG("Mesh partitioner created empty partition!\n");
return; 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 === // === Create map that maps macro element indices to pointers to the ===
// === macro elements. === // === macro elements. ===
...@@ -2023,13 +2026,17 @@ namespace AMDiS { ...@@ -2023,13 +2026,17 @@ namespace AMDiS {
{ {
FUNCNAME("MeshDistributor::createPeriodicMap()"); FUNCNAME("MeshDistributor::createPeriodicMap()");
if (periodicBoundary.boundary.size() == 0)
return;
// Clear all periodic DOF mappings calculated before. We do it from scratch. // Clear all periodic DOF mappings calculated before. We do it from scratch.
periodicDofs.clear(); periodicDofs.clear();
periodicMap.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++) for (unsigned int i = 0; i < feSpaces.size(); i++)
createPeriodicMap(feSpaces[i]); createPeriodicMap(feSpaces[i]);
} }
......
...@@ -29,13 +29,13 @@ ...@@ -29,13 +29,13 @@
#include "AMDiS_fwd.h" #include "AMDiS_fwd.h"
#include "Mesh.h" #include "Mesh.h"
#include "parallel/MpiHelper.h"
namespace AMDiS {
namespace AMDiS {
using namespace std; using namespace std;
enum PartitionMode { enum PartitionMode {
INITIAL = 0, // initial partitioning of a unpartitioned mesh INITIAL = 0, // initial partitioning of a unpartitioned mesh
ADAPTIVE_REPART = 1, // repartitioning of a adaptively refined mesh ADAPTIVE_REPART = 1, // repartitioning of a adaptively refined mesh
...@@ -131,6 +131,16 @@ namespace AMDiS { ...@@ -131,6 +131,16 @@ namespace AMDiS {
return sendElements; 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: protected:
/// Pointer to the MPI communicator the mesh partitioner should make use of. /// Pointer to the MPI communicator the mesh partitioner should make use of.
MPI::Intracomm *mpiComm; MPI::Intracomm *mpiComm;
...@@ -170,6 +180,8 @@ namespace AMDiS { ...@@ -170,6 +180,8 @@ namespace AMDiS {
/// partitiong mode) the rank number the element belongs to. /// partitiong mode) the rank number the element belongs to.
map<int, int> partitionMap; 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; map<int, vector<int> > recvElements, sendElements;
}; };
} }
......
...@@ -398,6 +398,8 @@ namespace AMDiS { ...@@ -398,6 +398,8 @@ namespace AMDiS {
MSG("nRankDuals = %d nOverallDuals = %d\n", MSG("nRankDuals = %d nOverallDuals = %d\n",
dualDofMap[feSpace].nRankDofs, dualDofMap[feSpace].nRankDofs,
dualDofMap[feSpace].nOverallDofs); dualDofMap[feSpace].nOverallDofs);
nLocalDuals = dualDofMap[feSpace].size();
} }
...@@ -409,26 +411,26 @@ namespace AMDiS { ...@@ -409,26 +411,26 @@ namespace AMDiS {
// === appropriate number of Lagrange constraints. === // === appropriate number of Lagrange constraints. ===
const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(0); const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(0);
dofFirstLagrange.addFeSpace(feSpace); lagrangeMap.addFeSpace(feSpace);
int nRankLagrange = 0; int nRankLagrange = 0;
DofMapping& dualMap = dualDofMap[feSpace].getMap(); DofMapping& dualMap = dualDofMap[feSpace].getMap();
for (DofMapping::iterator it = dualMap.begin(); it != dualMap.end(); ++it) { for (DofMapping::iterator it = dualMap.begin(); it != dualMap.end(); ++it) {
if (meshDistributor->getIsRankDof(feSpace, it->first)) { if (meshDistributor->getIsRankDof(feSpace, it->first)) {
dofFirstLagrange[feSpace].insert(it->first, nRankLagrange); lagrangeMap[feSpace].insert(it->first, nRankLagrange);
int degree = boundaryDofRanks[it->first].size(); int degree = boundaryDofRanks[it->first].size();
nRankLagrange += (degree * (degree - 1)) / 2; nRankLagrange += (degree * (degree - 1)) / 2;
} }
} }
dofFirstLagrange[feSpace].nRankDofs = nRankLagrange; lagrangeMap[feSpace].nRankDofs = nRankLagrange;
dofFirstLagrange[feSpace].update(); lagrangeMap[feSpace].update();
MSG("nRankLagrange = %d nOverallLagrange = %d\n", MSG("nRankLagrange = %d nOverallLagrange = %d\n",
dofFirstLagrange[feSpace].nRankDofs, lagrangeMap[feSpace].nRankDofs,
dofFirstLagrange[feSpace].nOverallDofs); lagrangeMap[feSpace].nOverallDofs);
// === Communicate dofFirstLagrange to all other ranks. === // === Communicate lagrangeMap to all other ranks. ===
StdMpi<vector<int> > stdMpi(meshDistributor->getMpiComm()); StdMpi<vector<int> > stdMpi(meshDistributor->getMpiComm());
...@@ -436,9 +438,7 @@ namespace AMDiS { ...@@ -436,9 +438,7 @@ namespace AMDiS {
!it.end(); it.nextRank()) { !it.end(); it.nextRank()) {
for (; !it.endDofIter(); it.nextDof()) for (; !it.endDofIter(); it.nextDof())
if (primalDofMap[feSpace].isSet(it.getDofIndex()) == false) { if (primalDofMap[feSpace].isSet(it.getDofIndex()) == false) {
TEST_EXIT_DBG(dofFirstLagrange[feSpace].isSet(it.getDofIndex())) DegreeOfFreedom d = lagrangeMap[feSpace][it.getDofIndex()];
("Should not happen!\n");
DegreeOfFreedom d = dofFirstLagrange[feSpace][it.getDofIndex()];
stdMpi.getSendData(it.getRank()).push_back(d); stdMpi.getSendData(it.getRank()).push_back(d);
} }
} }
...@@ -466,7 +466,7 @@ namespace AMDiS { ...@@ -466,7 +466,7 @@ namespace AMDiS {
for (; !it.endDofIter(); it.nextDof()) { for (; !it.endDofIter(); it.nextDof()) {
if (primalDofMap[feSpace].isSet(it.getDofIndex()) == false) { if (primalDofMap[feSpace].isSet(it.getDofIndex()) == false) {
DegreeOfFreedom d = stdMpi.getRecvData(it.getRank())[counter++]; 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 { ...@@ -475,36 +475,29 @@ namespace AMDiS {
void PetscSolverFeti::createIndexB() void PetscSolverFeti::createIndexB()
{ {
FUNCNAME("PetscSolverFeti::createIndeB()"); FUNCNAME("PetscSolverFeti::createIndexB()");
const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(0); const FiniteElemSpace *feSpace = meshDistributor->getFeSpace(0);
localIndexB.clear(); localDofMap.addFeSpace(feSpace);
DOFAdmin* admin = feSpace->getAdmin(); DOFAdmin* admin = feSpace->getAdmin();
// === To ensure that all interior node on each rank are listen first in === // === 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, === // === the global index of all B nodes, insert all interior nodes first, ===
// === without defining a correct index. === // === 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 && if (admin->isDofFree(i) == false &&
primalDofMap[feSpace].isSet(i) == false && primalDofMap[feSpace].isSet(i) == false &&
dualDofMap[feSpace].isSet(i) == false) dualDofMap[feSpace].isSet(i) == false) {
localIndexB[i] = -1; localDofMap[feSpace].insertRankDof(i);
// === Get correct index for all interior nodes. ===
nLocalInterior = 0;
for (DofMapping::iterator it = localIndexB.begin();
it != localIndexB.end(); ++it) {
it->second = nLocalInterior;
nLocalInterior++; nLocalInterior++;
} }
nLocalDuals = dualDofMap[feSpace].size(); }
TEST_EXIT_DBG(nLocalInterior + TEST_EXIT_DBG(nLocalInterior +
primalDofMap[feSpace].size() + primalDofMap[feSpace].size() +
dualDofMap[feSpace].size() == nLocalDuals ==
static_cast<unsigned int>(admin->getUsedDofs())) static_cast<unsigned int>(admin->getUsedDofs()))
("Should not happen!\n"); ("Should not happen!\n");
...@@ -513,7 +506,8 @@ namespace AMDiS { ...@@ -513,7 +506,8 @@ namespace AMDiS {
for (DofMapping::iterator it = dualDofMap[feSpace].getMap().begin(); for (DofMapping::iterator it = dualDofMap[feSpace].getMap().begin();
it != dualDofMap[feSpace].getMap().end(); ++it) 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 { ...@@ -526,9 +520,9 @@ namespace AMDiS {
// === Create distributed matrix for Lagrange constraints. === // === Create distributed matrix for Lagrange constraints. ===
MatCreateMPIAIJ(PETSC_COMM_WORLD, MatCreateMPIAIJ(PETSC_COMM_WORLD,
dofFirstLagrange[feSpace].nRankDofs * nComponents, lagrangeMap[feSpace].nRankDofs * nComponents,
nRankB * nComponents, nRankB * nComponents,
dofFirstLagrange[feSpace].nOverallDofs * nComponents, lagrangeMap[feSpace].nOverallDofs * nComponents,
nOverallB * nComponents, nOverallB * nComponents,
2, PETSC_NULL, 2, PETSC_NULL, 2, PETSC_NULL, 2, PETSC_NULL,
&mat_lagrange); &mat_lagrange);
...@@ -542,13 +536,11 @@ namespace AMDiS { ...@@ -542,13 +536,11 @@ namespace AMDiS {
DofMapping &dualMap = dualDofMap[feSpace].getMap(); DofMapping &dualMap = dualDofMap[feSpace].getMap();
for (DofMapping::iterator it = dualMap.begin(); it != dualMap.end(); ++it) { 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)) TEST_EXIT_DBG(boundaryDofRanks.count(it->first))
("Should not happen!\n"); ("Should not happen!\n");
// Global index of the first Lagrange constriant for this node. // 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. // Copy set of all ranks that contain this dual node.
vector<int> W(boundaryDofRanks[it->first].begin(), vector<int> W(boundaryDofRanks[it->first].begin(),
boundaryDofRanks[it->first].end()); boundaryDofRanks[it->first].end());
...@@ -742,18 +734,18 @@ namespace AMDiS { ...@@ -742,18 +734,18 @@ namespace AMDiS {
nRankB * nComponents, nOverallB * nComponents, nRankB * nComponents, nOverallB * nComponents,
&(fetiData.tmp_vec_b)); &(fetiData.tmp_vec_b));
VecCreateMPI(PETSC_COMM_WORLD, VecCreateMPI(PETSC_COMM_WORLD,
dofFirstLagrange[feSpace].nRankDofs * nComponents, lagrangeMap[feSpace].nRankDofs * nComponents,
dofFirstLagrange[feSpace].nOverallDofs * nComponents, lagrangeMap[feSpace].nOverallDofs * nComponents,
&(fetiData.tmp_vec_lagrange)); &(fetiData.tmp_vec_lagrange));
VecCreateMPI(PETSC_COMM_WORLD, VecCreateMPI(PETSC_COMM_WORLD,
primalDofMap[feSpace].nRankDofs * nComponents, primalDofMap[feSpace].nOverallDofs * nComponents, primalDofMap[feSpace].nRankDofs * nComponents, primalDofMap[feSpace].nOverallDofs * nComponents,
&(fetiData.tmp_vec_primal)); &(fetiData.tmp_vec_primal));
MatCreateShell(PETSC_COMM_WORLD, MatCreateShell(PETSC_COMM_WORLD,
dofFirstLagrange[feSpace].nRankDofs * nComponents, lagrangeMap[feSpace].nRankDofs * nComponents,
dofFirstLagrange[feSpace].nRankDofs * nComponents, lagrangeMap[feSpace].nRankDofs * nComponents,
dofFirstLagrange[feSpace].nOverallDofs * nComponents, lagrangeMap[feSpace].nOverallDofs * nComponents,
dofFirstLagrange[feSpace].nOverallDofs * nComponents, lagrangeMap[feSpace].nOverallDofs * nComponents,
&fetiData, &mat_feti); &fetiData, &mat_feti);
MatShellSetOperation(mat_feti, MATOP_MULT, (void(*)(void))petscMultMatFeti); MatShellSetOperation(mat_feti, MATOP_MULT, (void(*)(void))petscMultMatFeti);
...@@ -942,8 +934,8 @@ namespace AMDiS { ...@@ -942,8 +934,8 @@ namespace AMDiS {
for (int i = 0; i < nComponents; i++) { for (int i = 0; i < nComponents; i++) {
DOFVector<double>& dofVec = *(vec.getDOFVector(i)); DOFVector<double>& dofVec = *(vec.getDOFVector(i));
for (DofMapping::iterator it = localIndexB.begin(); for (DofMapping::iterator it = localDofMap[feSpace].getMap().begin();
it != localIndexB.end(); ++it) { it != localDofMap[feSpace].getMap().end(); ++it) {
int petscIndex = it->second * nComponents + i; int petscIndex = it->second * nComponents + i;
dofVec[it->first] = localSolB[petscIndex]; dofVec[it->first] = localSolB[petscIndex];
} }
...@@ -973,7 +965,8 @@ namespace AMDiS { ...@@ -973,7 +965,8 @@ namespace AMDiS {
primalDofMap.setMpiComm(mpiComm); primalDofMap.setMpiComm(mpiComm);
dualDofMap.setMpiComm(mpiComm);