@@ -63,8 +63,8 @@ Epetra_Vector *Trilinos::ghostX;
6363// / Import ghostMap into blockMap to create ghost map
6464Epetra_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
6969Epetra_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 */
112115int 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+ }
0 commit comments