Commit 430cb57b authored by Thomas Witkowski's avatar Thomas Witkowski
Browse files

Add more support for mixed finite element FETI-DP. Does not work yet.

parent 3f9bb6b2
...@@ -34,6 +34,13 @@ namespace AMDiS { ...@@ -34,6 +34,13 @@ namespace AMDiS {
class GlobalDofMap class GlobalDofMap
{ {
public: public:
/// This constructor exists only to create std::map of this class and make
/// use of the operator [] for read access. Should never be called.
GlobalDofMap()
{
ERROR_EXIT("Should not be called!\n");
}
GlobalDofMap(MPI::Intracomm* m) GlobalDofMap(MPI::Intracomm* m)
: mpiComm(m), : mpiComm(m),
nRankDofs(0), nRankDofs(0),
...@@ -103,7 +110,13 @@ namespace AMDiS { ...@@ -103,7 +110,13 @@ namespace AMDiS {
class FeSpaceData class FeSpaceData
{ {
public: public:
FeSpaceData() {} FeSpaceData()
: mpiComm(NULL),
feSpaces(0),
nRankDofs(-1),
nOverallDofs(-1),
rStartDofs(-1)
{}
void setMpiComm(MPI::Intracomm *m) void setMpiComm(MPI::Intracomm *m)
{ {
...@@ -129,17 +142,26 @@ namespace AMDiS { ...@@ -129,17 +142,26 @@ namespace AMDiS {
data.insert(make_pair(feSpace, T(mpiComm))); data.insert(make_pair(feSpace, T(mpiComm)));
} }
int getRankDofs(vector<const FiniteElemSpace*> &feSpaces) int getRankDofs(vector<const FiniteElemSpace*> &fe)
{ {
FUNCNAME("FeSpaceData::getRankDofs()");
int result = 0; int result = 0;
for (unsigned int i = 0; i < feSpaces.size(); i++) { for (unsigned int i = 0; i < fe.size(); i++) {
TEST_EXIT_DBG(data.count(feSpaces[i]))("Should not happen!\n"); TEST_EXIT_DBG(data.count(fe[i]))("Cannot find FE space: %p\n", fe[i]);
result += data.find(feSpaces[i])->second.nRankDofs; result += data[fe[i]].nRankDofs;
} }
return result; return result;
} }
inline int getRankDofs()
{
TEST_EXIT_DBG(nRankDofs >= 0)("Should not happen!\n");
return nRankDofs;
}
int getOverallDofs(vector<const FiniteElemSpace*> &feSpaces) int getOverallDofs(vector<const FiniteElemSpace*> &feSpaces)
{ {
int result = 0; int result = 0;
...@@ -151,6 +173,13 @@ namespace AMDiS { ...@@ -151,6 +173,13 @@ namespace AMDiS {
return result; return result;
} }
inline int getOverallDofs()
{
TEST_EXIT_DBG(nOverallDofs >= 0)("Should not happen!\n");
return nOverallDofs;
}
int getStartDofs(vector<const FiniteElemSpace*> &feSpaces) int getStartDofs(vector<const FiniteElemSpace*> &feSpaces)
{ {
int result = 0; int result = 0;
...@@ -162,10 +191,74 @@ namespace AMDiS { ...@@ -162,10 +191,74 @@ namespace AMDiS {
return result; return result;
} }
int getStartDofs()
{
TEST_EXIT_DBG(rStartDofs >= 0)("Should not happen!\n");
return rStartDofs;
}
void setFeSpaces(vector<const FiniteElemSpace*> &fe)
{
feSpaces = fe;
for (unsigned int i = 0; i < feSpaces.size(); i++)
addFeSpace(feSpaces[i]);
}
void update()
{
nRankDofs = getRankDofs(feSpaces);
nOverallDofs = getOverallDofs(feSpaces);
rStartDofs = getStartDofs(feSpaces);
}
inline int mapLocal(int index, int ithFeSpace)
{
int result = 0;
for (int i = 0; i < ithFeSpace; i++)
result += data[feSpaces[i]].nRankDofs;
result += data[feSpaces[ithFeSpace]][index];
return result;
}
inline int mapLocal(int index, const FiniteElemSpace *feSpace)
{
for (unsigned int i = 0; i < feSpaces.size(); i++)
if (feSpaces[i] == feSpace)
return mapLocal(index, feSpace, i);
return -1;
}
inline int mapGlobal(int index, int ithFeSpace)
{
int result = rStartDofs;
for (int i = 0; i < ithFeSpace; i++)
result += data[feSpaces[i]].nRankDofs;
result += data[feSpaces[ithFeSpace]][index];
return result;
}
inline int mapGlobal(int index, const FiniteElemSpace *feSpace)
{
for (unsigned int i = 0; i < feSpaces.size(); i++)
if (feSpaces[i] == feSpace)
return mapGlobal(index, feSpace, i);
return -1;
}
private: private:
MPI::Intracomm* mpiComm; MPI::Intracomm* mpiComm;
map<const FiniteElemSpace*, T> data; map<const FiniteElemSpace*, T> data;
vector<const FiniteElemSpace*> feSpaces;
int nRankDofs, nOverallDofs, rStartDofs;
}; };
} }
......
...@@ -248,7 +248,6 @@ namespace AMDiS { ...@@ -248,7 +248,6 @@ namespace AMDiS {
// === Calculate the number of primals that are owned by the rank and === // === Calculate the number of primals that are owned by the rank and ===
// === create local indices of the primals starting at zero. === // === create local indices of the primals starting at zero. ===
primalDofMap.addFeSpace(feSpace);
for (DofIndexSet::iterator it = primals.begin(); it != primals.end(); ++it) for (DofIndexSet::iterator it = primals.begin(); it != primals.end(); ++it)
if (meshDistributor->getIsRankDof(feSpace, *it)) if (meshDistributor->getIsRankDof(feSpace, *it))
primalDofMap[feSpace].insertRankDof(*it); primalDofMap[feSpace].insertRankDof(*it);
...@@ -372,8 +371,6 @@ namespace AMDiS { ...@@ -372,8 +371,6 @@ namespace AMDiS {
// === Create global index of the dual nodes on each rank. === // === Create global index of the dual nodes on each rank. ===
dualDofMap.addFeSpace(feSpace);
DofContainer allBoundaryDofs; DofContainer allBoundaryDofs;
meshDistributor->getAllBoundaryDofs(feSpace, allBoundaryDofs); meshDistributor->getAllBoundaryDofs(feSpace, allBoundaryDofs);
...@@ -397,8 +394,6 @@ namespace AMDiS { ...@@ -397,8 +394,6 @@ namespace AMDiS {
// === Reserve for each dual node, on the rank that owns this node, the === // === Reserve for each dual node, on the rank that owns this node, the ===
// === appropriate number of Lagrange constraints. === // === appropriate number of Lagrange constraints. ===
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) {
...@@ -463,7 +458,6 @@ namespace AMDiS { ...@@ -463,7 +458,6 @@ namespace AMDiS {
{ {
FUNCNAME("PetscSolverFeti::createIndexB()"); FUNCNAME("PetscSolverFeti::createIndexB()");
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 ===
...@@ -511,9 +505,9 @@ namespace AMDiS { ...@@ -511,9 +505,9 @@ namespace AMDiS {
MatCreateMPIAIJ(PETSC_COMM_WORLD, MatCreateMPIAIJ(PETSC_COMM_WORLD,
lagrangeMap.getRankDofs(feSpaces), lagrangeMap.getRankDofs(feSpaces),
localDofMap.getRankDofs(feSpaces), localDofMap.getRankDofs(),
lagrangeMap.getOverallDofs(feSpaces), lagrangeMap.getOverallDofs(feSpaces),
localDofMap.getOverallDofs(feSpaces), localDofMap.getOverallDofs(),
2, PETSC_NULL, 2, PETSC_NULL, 2, PETSC_NULL, 2, PETSC_NULL,
&mat_lagrange); &mat_lagrange);
...@@ -560,7 +554,7 @@ namespace AMDiS { ...@@ -560,7 +554,7 @@ namespace AMDiS {
} }
void PetscSolverFeti::createSchurPrimalKsp() void PetscSolverFeti::createSchurPrimalKsp(vector<const FiniteElemSpace*> &feSpaces)
{ {
FUNCNAME("PetscSolverFeti::createSchurPrimal()"); FUNCNAME("PetscSolverFeti::createSchurPrimal()");
...@@ -575,7 +569,7 @@ namespace AMDiS { ...@@ -575,7 +569,7 @@ namespace AMDiS {
schurPrimalData.fetiSolver = this; schurPrimalData.fetiSolver = this;
VecCreateMPI(PETSC_COMM_WORLD, VecCreateMPI(PETSC_COMM_WORLD,
localDofMap[feSpace].nRankDofs * nComponents, localDofMap[feSpace].nOverallDofs * nComponents, localDofMap.getRankDofs(), localDofMap.getOverallDofs(),
&(schurPrimalData.tmp_vec_b)); &(schurPrimalData.tmp_vec_b));
VecCreateMPI(PETSC_COMM_WORLD, VecCreateMPI(PETSC_COMM_WORLD,
primalDofMap[feSpace].nRankDofs * nComponents, primalDofMap[feSpace].nOverallDofs * nComponents, primalDofMap[feSpace].nRankDofs * nComponents, primalDofMap[feSpace].nOverallDofs * nComponents,
...@@ -602,8 +596,8 @@ namespace AMDiS { ...@@ -602,8 +596,8 @@ namespace AMDiS {
int nRowsRankPrimal = primalDofMap[feSpace].nRankDofs * nComponents; int nRowsRankPrimal = primalDofMap[feSpace].nRankDofs * nComponents;
int nRowsOverallPrimal = primalDofMap[feSpace].nOverallDofs * nComponents; int nRowsOverallPrimal = primalDofMap[feSpace].nOverallDofs * nComponents;
int nRowsRankB = localDofMap[feSpace].nRankDofs * nComponents; int nRowsRankB = localDofMap.getRankDofs();
int nRowsOverallB = localDofMap[feSpace].nOverallDofs * nComponents; int nRowsOverallB = localDofMap.getOverallDofs();
Mat matBPi; Mat matBPi;
MatCreateMPIAIJ(PETSC_COMM_WORLD, MatCreateMPIAIJ(PETSC_COMM_WORLD,
...@@ -618,8 +612,8 @@ namespace AMDiS { ...@@ -618,8 +612,8 @@ namespace AMDiS {
map<int, vector<pair<int, double> > > mat_b_primal_cols; map<int, vector<pair<int, double> > > mat_b_primal_cols;
for (int i = 0; i < localDofMap[feSpace].nRankDofs * nComponents; i++) { for (int i = 0; i < nRowsRankB; i++) {
PetscInt row = localDofMap[feSpace].rStartDofs * nComponents + i; PetscInt row = localDofMap.getStartDofs() + i;
MatGetRow(mat_b_primal, row, &nCols, &cols, &values); MatGetRow(mat_b_primal, row, &nCols, &cols, &values);
for (int j = 0; j < nCols; j++) for (int j = 0; j < nCols; j++)
...@@ -637,7 +631,7 @@ namespace AMDiS { ...@@ -637,7 +631,7 @@ namespace AMDiS {
for (map<int, vector<pair<int, double> > >::iterator it = mat_b_primal_cols.begin(); for (map<int, vector<pair<int, double> > >::iterator it = mat_b_primal_cols.begin();
it != mat_b_primal_cols.end(); ++it) { it != mat_b_primal_cols.end(); ++it) {
Vec tmpVec; Vec tmpVec;
VecCreateSeq(PETSC_COMM_SELF, localDofMap[feSpace].nRankDofs * nComponents, &tmpVec); VecCreateSeq(PETSC_COMM_SELF, nRowsRankB, &tmpVec);
for (unsigned int i = 0; i < it->second.size(); i++) for (unsigned int i = 0; i < it->second.size(); i++)
VecSetValue(tmpVec, VecSetValue(tmpVec,
...@@ -650,9 +644,9 @@ namespace AMDiS { ...@@ -650,9 +644,9 @@ namespace AMDiS {
PetscScalar *tmpValues; PetscScalar *tmpValues;
VecGetArray(tmpVec, &tmpValues); VecGetArray(tmpVec, &tmpValues);
for (int i = 0; i < localDofMap[feSpace].nRankDofs * nComponents; i++) for (int i = 0; i < nRowsRankB; i++)
MatSetValue(matBPi, MatSetValue(matBPi,
localDofMap[feSpace].rStartDofs * nComponents + i, localDofMap.getStartDofs() + i,
it->first, it->first,
tmpValues[i], tmpValues[i],
ADD_VALUES); ADD_VALUES);
...@@ -706,7 +700,7 @@ namespace AMDiS { ...@@ -706,7 +700,7 @@ namespace AMDiS {
} }
void PetscSolverFeti::createFetiKsp() void PetscSolverFeti::createFetiKsp(vector<const FiniteElemSpace*> &feSpaces)
{ {
FUNCNAME("PetscSolverFeti::createFetiKsp()"); FUNCNAME("PetscSolverFeti::createFetiKsp()");
...@@ -721,14 +715,15 @@ namespace AMDiS { ...@@ -721,14 +715,15 @@ namespace AMDiS {
fetiData.ksp_schur_primal = &ksp_schur_primal; fetiData.ksp_schur_primal = &ksp_schur_primal;
VecCreateMPI(PETSC_COMM_WORLD, VecCreateMPI(PETSC_COMM_WORLD,
localDofMap[feSpace].nRankDofs * nComponents, localDofMap[feSpace].nOverallDofs * nComponents, localDofMap.getRankDofs(), localDofMap.getOverallDofs(),
&(fetiData.tmp_vec_b)); &(fetiData.tmp_vec_b));
VecCreateMPI(PETSC_COMM_WORLD, VecCreateMPI(PETSC_COMM_WORLD,
lagrangeMap[feSpace].nRankDofs * nComponents, lagrangeMap[feSpace].nRankDofs * nComponents,
lagrangeMap[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,
...@@ -769,11 +764,14 @@ namespace AMDiS { ...@@ -769,11 +764,14 @@ namespace AMDiS {
fetiDirichletPreconData.ksp_interior = &ksp_interior; fetiDirichletPreconData.ksp_interior = &ksp_interior;
VecCreateMPI(PETSC_COMM_WORLD, VecCreateMPI(PETSC_COMM_WORLD,
localDofMap[feSpace].nRankDofs * nComponents, localDofMap[feSpace].nOverallDofs * nComponents, localDofMap.getRankDofs(),localDofMap.getOverallDofs(),
&(fetiDirichletPreconData.tmp_vec_b)); &(fetiDirichletPreconData.tmp_vec_b));
MatGetVecs(mat_duals_duals, PETSC_NULL, &(fetiDirichletPreconData.tmp_vec_duals0)); MatGetVecs(mat_duals_duals, PETSC_NULL,
MatGetVecs(mat_duals_duals, PETSC_NULL, &(fetiDirichletPreconData.tmp_vec_duals1)); &(fetiDirichletPreconData.tmp_vec_duals0));
MatGetVecs(mat_interior_interior, PETSC_NULL, &(fetiDirichletPreconData.tmp_vec_interior)); MatGetVecs(mat_duals_duals, PETSC_NULL,
&(fetiDirichletPreconData.tmp_vec_duals1));
MatGetVecs(mat_interior_interior, PETSC_NULL,
&(fetiDirichletPreconData.tmp_vec_interior));
KSPGetPC(ksp_feti, &precon_feti); KSPGetPC(ksp_feti, &precon_feti);
PCSetType(precon_feti, PCSHELL); PCSetType(precon_feti, PCSHELL);
...@@ -787,10 +785,13 @@ namespace AMDiS { ...@@ -787,10 +785,13 @@ namespace AMDiS {
fetiLumpedPreconData.mat_duals_duals = &mat_duals_duals; fetiLumpedPreconData.mat_duals_duals = &mat_duals_duals;
VecCreateMPI(PETSC_COMM_WORLD, VecCreateMPI(PETSC_COMM_WORLD,
localDofMap[feSpace].nRankDofs * nComponents, localDofMap[feSpace].nOverallDofs * nComponents, localDofMap.getRankDofs(),
localDofMap.getOverallDofs(),
&(fetiLumpedPreconData.tmp_vec_b)); &(fetiLumpedPreconData.tmp_vec_b));
MatGetVecs(mat_duals_duals, PETSC_NULL, &(fetiLumpedPreconData.tmp_vec_duals0)); MatGetVecs(mat_duals_duals, PETSC_NULL,
MatGetVecs(mat_duals_duals, PETSC_NULL, &(fetiLumpedPreconData.tmp_vec_duals1)); &(fetiLumpedPreconData.tmp_vec_duals0));
MatGetVecs(mat_duals_duals, PETSC_NULL,
&(fetiLumpedPreconData.tmp_vec_duals1));
KSPGetPC(ksp_feti, &precon_feti); KSPGetPC(ksp_feti, &precon_feti);
PCSetType(precon_feti, PCSHELL); PCSetType(precon_feti, PCSHELL);
...@@ -926,7 +927,13 @@ namespace AMDiS { ...@@ -926,7 +927,13 @@ namespace AMDiS {
for (DofMapping::iterator it = localDofMap[feSpace].getMap().begin(); for (DofMapping::iterator it = localDofMap[feSpace].getMap().begin();
it != localDofMap[feSpace].getMap().end(); ++it) { it != localDofMap[feSpace].getMap().end(); ++it) {
#if 1
int petscIndex = localDofMap.mapLocal(it->first, i);
#else
int petscIndex = it->second * nComponents + i; int petscIndex = it->second * nComponents + i;
#endif
dofVec[it->first] = localSolB[petscIndex]; dofVec[it->first] = localSolB[petscIndex];
} }
...@@ -959,18 +966,28 @@ namespace AMDiS { ...@@ -959,18 +966,28 @@ namespace AMDiS {
dualDofMap.setMpiComm(mpiComm); dualDofMap.setMpiComm(mpiComm);
lagrangeMap.setMpiComm(mpiComm); lagrangeMap.setMpiComm(mpiComm);
localDofMap.setMpiComm(mpiComm); localDofMap.setMpiComm(mpiComm);
primalDofMap.setFeSpaces(feSpaces);
dualDofMap.setFeSpaces(feSpaces);
lagrangeMap.setFeSpaces(feSpaces);
localDofMap.setFeSpaces(feSpaces);
updateDofData(); updateDofData();
primalDofMap.update();
dualDofMap.update();
lagrangeMap.update();
localDofMap.update();
// === Create matrices for the FETI-DP method. === // === Create matrices for the FETI-DP method. ===
int nRowsRankB = localDofMap.getRankDofs(feSpaces); int nRowsRankB = localDofMap.getRankDofs();
int nRowsOverallB = localDofMap.getOverallDofs(feSpaces); int nRowsOverallB = localDofMap.getOverallDofs();
int nRowsRankPrimal = primalDofMap.getRankDofs(feSpaces); int nRowsRankPrimal = primalDofMap.getRankDofs(feSpaces);
int nRowsOverallPrimal = primalDofMap.getOverallDofs(feSpaces); int nRowsOverallPrimal = primalDofMap.getOverallDofs(feSpaces);
int nRowsDual = dualDofMap.getRankDofs(feSpaces); int nRowsDual = dualDofMap.getRankDofs(feSpaces);
int nRowsInterior = nRowsRankB - nRowsDual; int nRowsInterior = nRowsRankB - nRowsDual;
MatCreateSeqAIJ(PETSC_COMM_SELF, nRowsRankB, nRowsRankB, 30, PETSC_NULL, MatCreateSeqAIJ(PETSC_COMM_SELF, nRowsRankB, nRowsRankB, 30, PETSC_NULL,
&mat_b_b); &mat_b_b);
...@@ -1071,36 +1088,24 @@ namespace AMDiS { ...@@ -1071,36 +1088,24 @@ namespace AMDiS {
bool colPrimal = primalDofMap[feSpace].isSet(col(*icursor)); bool colPrimal = primalDofMap[feSpace].isSet(col(*icursor));
if (colPrimal) { if (colPrimal) {
// Column is a primal variable.
int colIndex =
primalDofMap[feSpace][col(*icursor)] * nComponents + j;
if (rowPrimal) { if (rowPrimal) {
cols.push_back(colIndex); cols.push_back(col(*icursor));
values.push_back(value(*icursor)); values.push_back(value(*icursor));
} else { } else {
colsOther.push_back(colIndex); colsOther.push_back(col(*icursor));
valuesOther.push_back(value(*icursor)); valuesOther.push_back(value(*icursor));
} }
} else { } else {
// Column is not a primal variable.
int colIndex =
(localDofMap[feSpace][col(*icursor)] +
localDofMap[feSpace].rStartDofs) * nComponents + j;
if (rowPrimal) { if (rowPrimal) {
colsOther.push_back(colIndex); colsOther.push_back(col(*icursor));
valuesOther.push_back(value(*icursor)); valuesOther.push_back(value(*icursor));
} else { } else {
cols.push_back(colIndex); cols.push_back(col(*icursor));
values.push_back(value(*icursor)); values.push_back(value(*icursor));
} }
} }
// === For preconditioner === // === For preconditioner ===
if (!rowPrimal && !colPrimal) { if (!rowPrimal && !colPrimal) {
...@@ -1109,7 +1114,11 @@ namespace AMDiS { ...@@ -1109,7 +1114,11 @@ namespace AMDiS {
if (rowIndex < nLocalInterior) { if (rowIndex < nLocalInterior) {
if (colIndex < nLocalInterior) { if (colIndex < nLocalInterior) {
#if 1
int colIndex2 = localDofMap.mapLocal(col(*icursor), j);
#else
int colIndex2 = localDofMap[feSpace][col(*icursor)] * nComponents + j; int colIndex2 = localDofMap[feSpace][col(*icursor)] * nComponents + j;
#endif
colsLocal.push_back(colIndex2); colsLocal.push_back(colIndex2);
valuesLocal.push_back(value(*icursor)); valuesLocal.push_back(value(*icursor));
...@@ -1122,7 +1131,11 @@ namespace AMDiS { ...@@ -1122,7 +1131,11 @@ namespace AMDiS {
} }
} else { } else {
if (colIndex < nLocalInterior) { if (colIndex < nLocalInterior) {
#if 1
int colIndex2 = localDofMap.mapLocal(col(*icursor), j);
#else
int colIndex2 = localDofMap[feSpace][col(*icursor)] * nComponents + j; int colIndex2 = localDofMap[feSpace][col(*icursor)] * nComponents + j;
#endif
colsLocalOther.push_back(colIndex2); colsLocalOther.push_back(colIndex2);
valuesLocalOther.push_back(value(*icursor)); valuesLocalOther.push_back(value(*icursor));
...@@ -1139,31 +1152,67 @@ namespace AMDiS { ...@@ -1139,31 +1152,67 @@ namespace AMDiS {
} // for each nnz in row } // for each nnz in row
// === Set matrix values. ===
if (rowPrimal) { if (rowPrimal) {
int rowIndex = int rowIndex =
primalDofMap[feSpace][*cursor] * nComponents + i; primalDofMap[feSpace][*cursor] * nComponents + i;
for (unsigned int k = 0; k < cols.size(); k++)
cols[k] = primalDofMap[feSpace][cols[k]] * nComponents + j;
MatSetValues(mat_primal_primal, 1, &rowIndex, cols.size(), MatSetValues(mat_primal_primal, 1, &rowIndex, cols.size(),
&(cols[0]), &(values[0]), ADD_VALUES); &(cols[0]), &(values[0]), ADD_VALUES);
if (colsOther.size()) if (colsOther.size()) {
MatSetValues(mat_primal_b, 1, &rowIndex, colsOther.size(),