Skip to content

Commit c578375

Browse files
Fix bug with Trilinos and multiple resistance BCs (SimVascular#380)
* First pass fixing bug with Trilinos multiple coupled Neumann (resistance) boundary conditions * Clarifying comments * Bug fixes * Fix type for v_list * Pushback v to v_list, reset v to 0 for each face, make v_list a constant reference, * Adding iliac_artery_trilinos_gmres_ilut case * Small efficiency changes suggested by Dave and Copilot * Refactor trilinos_lhs_create function to use const ints and Vector types for improved performance and clarity * Add fluid trilinos test case to test_fluid.py * Remove t_max from trilinos test case
1 parent 52d3780 commit c578375

File tree

13 files changed

+234
-54
lines changed

13 files changed

+234
-54
lines changed

Code/Source/solver/trilinos_impl.cpp

Lines changed: 85 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ Epetra_Vector *Trilinos::ghostX;
6363
/// Import ghostMap into blockMap to create ghost map
6464
Epetra_Import *Trilinos::Importer;
6565

66-
/// Contribution from coupled neumann boundary conditions
67-
Epetra_FEVector *Trilinos::bdryVec;
66+
/// Contribution from coupled neumann boundary conditions. One vector for each coupled Neumann boundary
67+
std::vector<Epetra_FEVector*> Trilinos::bdryVec_list;
6868

6969
Epetra_FECrsGraph *Trilinos::K_graph;
7070

@@ -100,34 +100,41 @@ bool coupledBC;
100100

101101
// ----------------------------------------------------------------------------
102102
/**
103-
* Define the matrix vector multiplication operation to do at each iteration
104-
* (K + v*v') *x = K*x + v*(v'*x), v = bdryVec
103+
* Define the matrix vector multiplication operation to do at each iteration of
104+
* an iterative linear solver. This function is called by the AztecOO
105+
* (K + v1*v1' + v2*v2' + ...) *x = K*x + v1*(v1'*x) + v2*(v2'*x),
106+
* where [v1, v2, ...] = bdryVec_list
105107
*
106-
* uses efficient vectorized operation rather than explicitly forming
107-
* the rank 1 outer product matrix
108+
* For coupled Neumann boundary terms (v1*v1', v2*v2'), we use efficient an vectorized
109+
* operation rather than explicitly forming the rank 1 outer product matrix and
110+
* adding it to the global stiffness matrix K.
108111
*
109112
* \param x vector to be applied on the operator
110113
* \param y result of sprase matrix vector multiplication
111114
*/
112115
int TrilinosMatVec::Apply(const Epetra_MultiVector &x,
113116
Epetra_MultiVector &y) const
114117
{
115-
//store initial matrix vector product result in Y
118+
// Store initial matrix vector product result in y (y = K*x)
116119
Trilinos::K->Apply(x, y); //K*x
120+
121+
// Now add on the coupled Neumann boundary contribution y += v1*(v1'*x) + v2*(v2'*x) + ...
117122
if (coupledBC)
118123
{
119-
//now need to add on bdry term v*(v'*x)
120-
double *dot = new double[1]; //only 1 multivector to store result in it
121-
122-
//compute dot product (v'*x)
123-
Trilinos::bdryVec->Dot(x,dot);
124+
// Declare dot product v_i'*x
125+
double dot = 0.0;
124126

125-
//Y = 1*Y + dot*v daxpy operation
126-
y.Update(*dot, //scalar for v
127-
*Trilinos::bdryVec, //FE_Vector
128-
1.0); ///scalar for Y
127+
// Loop over all coupled Neumann boundary vectors
128+
for (auto bdryVec : Trilinos::bdryVec_list)
129+
{
130+
// Compute dot product dot = v_i'*x
131+
bdryVec->Dot(x, &dot);
129132

130-
delete[] dot;
133+
// y = 1*y + dot*v_i
134+
y.Update(dot,
135+
*bdryVec,
136+
1.0);
137+
}
131138
}
132139
return 0;
133140
}
@@ -149,15 +156,16 @@ int TrilinosMatVec::Apply(const Epetra_MultiVector &x,
149156
* \param rowPtr CSR row ptr of size numLocalNodes + 1 to block rows
150157
* \param colInd CSR column indices ptr (size nnz points) to block rows
151158
* \param Dof size of each block element to give dim of each block
159+
*
160+
* \param numCoupledNeumannBC number of coupled Neumann BCs
152161
153162
*/
154163

155-
void trilinos_lhs_create_(int &numGlobalNodes, int &numLocalNodes,
156-
int &numGhostAndLocalNodes, int &nnz, const int *ltgSorted,
157-
const int *ltgUnsorted, const int *rowPtr, const int *colInd, int &Dof,
158-
int& cpp_index, int& proc_id)
164+
void trilinos_lhs_create(const int numGlobalNodes, const int numLocalNodes,
165+
const int numGhostAndLocalNodes, const int nnz, const Vector<int>& ltgSorted,
166+
const Vector<int>& ltgUnsorted, const Vector<int>& rowPtr, const Vector<int>& colInd,
167+
const int Dof, const int cpp_index, const int proc_id, const int numCoupledNeumannBC)
159168
{
160-
161169
#ifdef debug_trilinos_lhs_create
162170
std::string msg_prefix;
163171
msg_prefix = std::string("[trilinos_lhs_create:") + std::to_string(proc_id) + "] ";
@@ -226,7 +234,7 @@ void trilinos_lhs_create_(int &numGlobalNodes, int &numLocalNodes,
226234
// solution vector at the end
227235
//
228236
int inc_ghost = -1; // since including ghost nodes sum will not equal total
229-
Epetra_BlockMap ghostMap(inc_ghost, numGhostAndLocalNodes, ltgSorted, dof,
237+
Epetra_BlockMap ghostMap(inc_ghost, numGhostAndLocalNodes, ltgSorted.data(), dof,
230238
indexBase, comm);
231239

232240
// Calculate nnzPerRow to pass into graph constructor
@@ -251,7 +259,6 @@ void trilinos_lhs_create_(int &numGlobalNodes, int &numLocalNodes,
251259
for (unsigned i = 0; i < nnz; ++i) {
252260
// Convert to global indexing subtract 1 for fortran vs C array indexing
253261
globalColInd.emplace_back(ltgUnsorted[colInd[i] - indexBase]);
254-
//globalColInd.emplace_back(ltgUnsorted[colInd[i] - 1]);
255262
}
256263
}
257264

@@ -302,7 +309,12 @@ void trilinos_lhs_create_(int &numGlobalNodes, int &numLocalNodes,
302309
Trilinos::K = new Epetra_FEVbrMatrix(Copy, *Trilinos::K_graph);
303310
//construct RHS force vector F topology
304311
Trilinos::F = new Epetra_FEVector(*Trilinos::blockMap);
305-
Trilinos::bdryVec = new Epetra_FEVector(*Trilinos::blockMap);
312+
// Construct a boundary vector for each coupled Neumann boundary condition
313+
Trilinos::bdryVec_list.clear();
314+
for (int i = 0; i < numCoupledNeumannBC; ++i)
315+
{
316+
Trilinos::bdryVec_list.push_back(new Epetra_FEVector(*Trilinos::blockMap));
317+
}
306318

307319
// Initialize solution vector which is unique and does not include the ghost
308320
// indices using the unique map
@@ -586,8 +598,8 @@ void trilinos_solve_(double *x, const double *dirW, double &resNorm,
586598
// problem with
587599
Trilinos::F->Norm2(&initNorm); //pass preconditioned norm W*F
588600

589-
// Define Epetra_Operator which is global stiffness with coupled boundary
590-
// conditions included
601+
// Define Epetra_Operator which is global stiffness with coupled Neumann BC
602+
// contributions included
591603
TrilinosMatVec K_bdry;
592604

593605
// Define linear problem if v is 0 does standard matvec product with K
@@ -670,7 +682,11 @@ void trilinos_solve_(double *x, const double *dirW, double &resNorm,
670682
//set to 0 for the next time iteration
671683
Trilinos::K->PutScalar(0.0);
672684
Trilinos::F->PutScalar(0.0);
673-
if (coupledBC) Trilinos::bdryVec->PutScalar(0.0);
685+
if (coupledBC) {
686+
for (auto bdryVec : Trilinos::bdryVec_list)
687+
bdryVec->PutScalar(0.0);
688+
689+
}
674690
//0 out initial guess for iteration
675691
Trilinos::X->PutScalar(0.0);
676692
// Free memory if MLPrec is invoked
@@ -920,16 +936,18 @@ void constructJacobiScaling(const double *dirW, Epetra_Vector &diagonal)
920936
Trilinos::K->RightScale(diagonal);
921937

922938
//Need to multiply v in vv' by diagonal
923-
if (coupledBC)
924-
Trilinos::bdryVec->Multiply(1.0, *Trilinos::bdryVec, diagonal, 0.0);
939+
if (coupledBC) {
940+
for (auto bdryVec : Trilinos::bdryVec_list)
941+
bdryVec->Multiply(1.0, *bdryVec, diagonal, 0.0);
942+
}
925943
} // void constructJacobiScaling()
926944

927945
// ----------------------------------------------------------------------------
928946
/**
929947
* \param v coupled boundary vector
930948
* \param isCoupledBC determines if coupled resistance BC is turned on
931949
*/
932-
void trilinos_bc_create_(const double *v, bool &isCoupledBC)
950+
void trilinos_bc_create_(const std::vector<Array<double>> &v_list, bool &isCoupledBC)
933951
{
934952
//store as global to determine which matvec multiply to use in solver
935953
coupledBC = isCoupledBC;
@@ -943,14 +961,22 @@ void trilinos_bc_create_(const double *v, bool &isCoupledBC)
943961
{
944962
//sum values into v fe case
945963
int num_global_rows = 1; //number of global block rows put in 1 at a time
946-
error = Trilinos::bdryVec->ReplaceGlobalValues (num_global_rows,
947-
&localToGlobalSorted[i], //global idx id-inputting sorted array
948-
&dof, //dof values per id pointer to dof
949-
&v[i*dof]); //values of size dof
950-
if (error != 0)
964+
965+
// Loop over all the coupled Neumann BCs
966+
for (int k = 0; k < v_list.size(); ++k)
951967
{
952-
std::cout << "ERROR: Setting boundary vector values!" << std::endl;
953-
exit(1);
968+
auto v = v_list[k].data();
969+
auto bdryVec = Trilinos::bdryVec_list[k];
970+
//set the coupled boundary vector
971+
error = bdryVec->ReplaceGlobalValues(
972+
num_global_rows,
973+
&localToGlobalSorted[i], //global idx id-inputting sorted array
974+
&dof, //dof values per id pointer to dof
975+
&v[i*dof]); //values of size dof
976+
if (error != 0)
977+
{
978+
throw std::runtime_error("Setting boundary vector values failed");
979+
}
954980
}
955981
}
956982
}
@@ -991,9 +1017,11 @@ void trilinos_lhs_free_()
9911017
delete Trilinos::Importer;
9921018
Trilinos::Importer = NULL;
9931019
}
994-
if (Trilinos::bdryVec) {
995-
delete Trilinos::bdryVec;
996-
Trilinos::bdryVec = NULL;
1020+
if (Trilinos::bdryVec_list.size() > 0)
1021+
{
1022+
for (auto bdryVec : Trilinos::bdryVec_list)
1023+
delete bdryVec;
1024+
Trilinos::bdryVec_list.clear();
9971025
}
9981026
if (Trilinos::K_graph) {
9991027
delete Trilinos::K_graph;
@@ -1139,8 +1167,8 @@ void TrilinosLinearAlgebra::TrilinosImpl::alloc(ComMod& com_mod, eqType& lEq)
11391167
int cpp_index = 1;
11401168
int task_id = com_mod.cm.idcm();
11411169

1142-
trilinos_lhs_create_(gtnNo, lhs.mynNo, tnNo, lhs.nnz, ltg_.data(), com_mod.ltg.data(), com_mod.rowPtr.data(),
1143-
com_mod.colPtr.data(), dof, cpp_index, task_id);
1170+
trilinos_lhs_create(gtnNo, lhs.mynNo, tnNo, lhs.nnz, ltg_, com_mod.ltg, com_mod.rowPtr,
1171+
com_mod.colPtr, dof, cpp_index, task_id, com_mod.lhs.nFaces);
11441172

11451173
}
11461174

@@ -1208,15 +1236,22 @@ void TrilinosLinearAlgebra::TrilinosImpl::init_dir_and_coup_neu(ComMod& com_mod,
12081236
}
12091237
}
12101238

1211-
Array<double> v(dof,tnNo);
1239+
std::vector<Array<double>> v_list;
12121240
bool isCoupledBC = false;
12131241

12141242
for (int faIn = 0; faIn < lhs.nFaces; faIn++) {
1215-
auto& face = lhs.face[faIn];
1243+
// Extract face
1244+
auto& face = lhs.face[faIn];
1245+
1246+
// Create a new array for each face and add it to the list
1247+
v_list.push_back(Array<double>(dof,tnNo));
1248+
auto& v = v_list.back();
1249+
12161250
if (face.coupledFlag) {
12171251
isCoupledBC = true;
12181252
int faDof = std::min(face.dof,dof);
12191253

1254+
// Compute the coupled Neumann BC vector and store it in v
12201255
for (int a = 0; a < face.nNo; a++) {
12211256
int Ac = face.glob(a);
12221257
for (int i = 0; i < faDof; i++) {
@@ -1226,7 +1261,10 @@ void TrilinosLinearAlgebra::TrilinosImpl::init_dir_and_coup_neu(ComMod& com_mod,
12261261
}
12271262
}
12281263

1229-
trilinos_bc_create_(v.data(), isCoupledBC);
1264+
// Add the v vectors to global bdryVec_list
1265+
trilinos_bc_create_(v_list, isCoupledBC);
1266+
1267+
12301268
}
12311269

12321270
/// @brief Initialze an array used for something.
@@ -1323,5 +1361,4 @@ void TrilinosLinearAlgebra::TrilinosImpl::solve_assembled(ComMod& com_mod, eqTyp
13231361
}
13241362
}
13251363

1326-
}
1327-
1364+
}

Code/Source/solver/trilinos_impl.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ struct Trilinos
9999
static Epetra_Vector *X;
100100
static Epetra_Vector *ghostX;
101101
static Epetra_Import *Importer;
102-
static Epetra_FEVector *bdryVec;
102+
static std::vector<Epetra_FEVector*> bdryVec_list;
103103
static Epetra_MpiComm *comm;
104104
static Epetra_FECrsGraph *K_graph;
105105
};
@@ -186,10 +186,10 @@ class TrilinosMatVec: public virtual Epetra_Operator
186186
{
187187
#endif
188188
/// Give function definitions which will be called through fortran
189-
void trilinos_lhs_create_(int& numGlobalNodes, int& numLocalNodes,
190-
int& numGhostAndLocalNodes, int& nnz, const int *ltgSorted,
191-
const int *ltgUnsorted, const int *rowPtr, const int *colInd,
192-
int &dof, int& cpp_index, int& proc_id);
189+
void trilinos_lhs_create(const int numGlobalNodes, const int numLocalNodes,
190+
const int numGhostAndLocalNodes, const int nnz, const Vector<int>& ltgSorted,
191+
const Vector<int>& ltgUnsorted, const Vector<int>& rowPtr, const Vector<int>& colInd,
192+
const int dof, const int cpp_index, const int proc_id, const int numCoupledNeumannBC);
193193
/*
194194
void trilinos_lhs_create_(unsigned &numGlobalNodes, unsigned &numLocalNodes,
195195
unsigned &numGhostAndLocalNodes, unsigned &nnz, const int *ltgSorted,
@@ -201,7 +201,7 @@ class TrilinosMatVec: public virtual Epetra_Operator
201201
* \param v coeff in the scalar product
202202
* \param isCoupledBC determines if coupled resistance BC is turned on
203203
*/
204-
void trilinos_bc_create_(const double *v, bool &isCoupledBC);
204+
void trilinos_bc_create_(const std::vector<Array<double>> &v_list, bool &isCoupledBC);
205205

206206
void trilinos_doassem_(int &numNodesPerElement, const int *eqN,
207207
const double *lK, double *lR);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:12d52092e40a59c65137802965aa8c1667be0b687202f335240b5b5519464069
3+
size 198504
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:a4560acb8b92b7fe3ec58e3a18277905c1ca3d52aee2d47f3585e45f8b4961f9
3+
size 1113338
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:f9806b6801f79d97d811ea25b7103856792b78cb5177bb48023f3ae28a5d5b0f
3+
size 6022
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:cf61c488b0095030ff5736693f3d1a10ce12d36869cd7cff8f5dd27c1be1ea61
3+
size 3544
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:4e2cd6eaed95d300d593a2e93b78b6ac88ab90a85929398e1e2e6c0eac130e8c
3+
size 3675
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:00c7fd6f592ba248974abdcaa54a7ebda638e829de963255af3abd782e2e4a0b
3+
size 139462
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:5d06cdda4db9fec1a081181ecc958caf78e2751db2e167edc747ea027c684675
3+
size 54016
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:5d0c64ecff7bf3519074de6246c5fb7ef4bccf35ee2a4f2e2a4de4b16128140b
3+
size 190365

0 commit comments

Comments
 (0)