Teko  Version of the Day
 All Classes Files Functions Variables Pages
Teko_InterlacedEpetra.cpp
1 /*
2 // @HEADER
3 //
4 // ***********************************************************************
5 //
6 // Teko: A package for block and physics based preconditioning
7 // Copyright 2010 Sandia Corporation
8 //
9 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Eric C. Cyr (eccyr@sandia.gov)
40 //
41 // ***********************************************************************
42 //
43 // @HEADER
44 
45 */
46 
47 #include "Teko_InterlacedEpetra.hpp"
48 
49 #include <vector>
50 
51 using Teuchos::RCP;
52 using Teuchos::rcp;
53 
54 namespace Teko {
55 namespace Epetra {
56 namespace Strided {
57 
58 // this assumes that there are numGlobals with numVars each interlaced
59 // i.e. for numVars = 2 (u,v) then the vector is
60 // [u_0,v_0,u_1,v_1,u_2,v_2, ..., u_(numGlobals-1),v_(numGlobals-1)]
61 void buildSubMaps(int numGlobals, int numVars, const Epetra_Comm& comm,
62  std::vector<std::pair<int, RCP<Epetra_Map> > >& subMaps) {
63  std::vector<int> vars;
64 
65  // build vector describing the sub maps
66  for (int i = 0; i < numVars; i++) vars.push_back(1);
67 
68  // build all the submaps
69  buildSubMaps(numGlobals, vars, comm, subMaps);
70 }
71 
72 // build maps to make other conversions
73 void buildSubMaps(const Epetra_Map& globalMap, const std::vector<int>& vars,
74  const Epetra_Comm& comm,
75  std::vector<std::pair<int, Teuchos::RCP<Epetra_Map> > >& subMaps) {
76  buildSubMaps(globalMap.NumGlobalElements(), globalMap.NumMyElements(), globalMap.MinMyGID(), vars,
77  comm, subMaps);
78 }
79 
80 // build maps to make other conversions
81 void buildSubMaps(int numGlobals, const std::vector<int>& vars, const Epetra_Comm& comm,
82  std::vector<std::pair<int, Teuchos::RCP<Epetra_Map> > >& subMaps) {
83  std::vector<int>::const_iterator varItr;
84 
85  // compute total number of variables
86  int numGlobalVars = 0;
87  for (varItr = vars.begin(); varItr != vars.end(); ++varItr) numGlobalVars += *varItr;
88 
89  // must be an even number of globals
90  TEUCHOS_ASSERT((numGlobals % numGlobalVars) == 0);
91 
92  Epetra_Map sampleMap(numGlobals / numGlobalVars, 0, comm);
93 
94  buildSubMaps(numGlobals, numGlobalVars * sampleMap.NumMyElements(),
95  numGlobalVars * sampleMap.MinMyGID(), vars, comm, subMaps);
96 }
97 
98 // build maps to make other conversions
99 void buildSubMaps(int numGlobals, int numMyElements, int minMyGID, const std::vector<int>& vars,
100  const Epetra_Comm& comm,
101  std::vector<std::pair<int, Teuchos::RCP<Epetra_Map> > >& subMaps) {
102  std::vector<int>::const_iterator varItr;
103 
104  // compute total number of variables
105  int numGlobalVars = 0;
106  for (varItr = vars.begin(); varItr != vars.end(); ++varItr) numGlobalVars += *varItr;
107 
108  // must be an even number of globals
109  TEUCHOS_ASSERT((numGlobals % numGlobalVars) == 0);
110  TEUCHOS_ASSERT((numMyElements % numGlobalVars) == 0);
111  TEUCHOS_ASSERT((minMyGID % numGlobalVars) == 0);
112 
113  int numBlocks = numMyElements / numGlobalVars;
114  int minBlockID = minMyGID / numGlobalVars;
115 
116  subMaps.clear();
117 
118  // index into local block in strided map
119  int blockOffset = 0;
120  for (varItr = vars.begin(); varItr != vars.end(); ++varItr) {
121  int numLocalVars = *varItr;
122  int numAllElmts = numLocalVars * numGlobals / numGlobalVars;
123  int numMyElmts = numLocalVars * numBlocks;
124 
125  // create global arrays describing the as of yet uncreated maps
126  std::vector<int> subGlobals;
127  std::vector<int> contigGlobals; // the contiguous globals
128 
129  // loop over each block of variables
130  int count = 0;
131  for (int blockNum = 0; blockNum < numBlocks; blockNum++) {
132  // loop over each local variable in the block
133  for (int local = 0; local < numLocalVars; ++local) {
134  // global block number = minGID+blockNum
135  // block begin global id = numGlobalVars*(minGID+blockNum)
136  // global id block offset = blockOffset+local
137  subGlobals.push_back((minBlockID + blockNum) * numGlobalVars + blockOffset + local);
138 
139  // also build the contiguous IDs
140  contigGlobals.push_back(numLocalVars * minBlockID + count);
141  count++;
142  }
143  }
144 
145  // sanity check
146  assert((unsigned int)numMyElmts == subGlobals.size());
147 
148  // create the map with contiguous elements and the map with global elements
149  RCP<Epetra_Map> subMap = rcp(new Epetra_Map(numAllElmts, numMyElmts, &subGlobals[0], 0, comm));
150  RCP<Epetra_Map> contigMap =
151  rcp(new Epetra_Map(numAllElmts, numMyElmts, &contigGlobals[0], 0, comm));
152 
153  Teuchos::set_extra_data(contigMap, "contigMap", Teuchos::inOutArg(subMap));
154  subMaps.push_back(std::make_pair(numLocalVars, subMap));
155 
156  // update the block offset
157  blockOffset += numLocalVars;
158  }
159 }
160 
161 void buildExportImport(const Epetra_Map& baseMap,
162  const std::vector<std::pair<int, RCP<Epetra_Map> > >& subMaps,
163  std::vector<RCP<Epetra_Export> >& subExport,
164  std::vector<RCP<Epetra_Import> >& subImport) {
165  std::vector<std::pair<int, RCP<Epetra_Map> > >::const_iterator mapItr;
166 
167  // build importers and exporters
168  for (mapItr = subMaps.begin(); mapItr != subMaps.end(); ++mapItr) {
169  // exctract basic map
170  const Epetra_Map& map = *(mapItr->second);
171 
172  // add new elements to vectors
173  subImport.push_back(rcp(new Epetra_Import(map, baseMap)));
174  subExport.push_back(rcp(new Epetra_Export(map, baseMap)));
175  }
176 }
177 
178 void buildSubVectors(const std::vector<std::pair<int, RCP<Epetra_Map> > >& subMaps,
179  std::vector<RCP<Epetra_MultiVector> >& subVectors, int count) {
180  std::vector<std::pair<int, RCP<Epetra_Map> > >::const_iterator mapItr;
181 
182  // build vectors
183  for (mapItr = subMaps.begin(); mapItr != subMaps.end(); ++mapItr) {
184  // exctract basic map
185  const Epetra_Map& map =
186  *(Teuchos::get_extra_data<RCP<Epetra_Map> >(mapItr->second, "contigMap"));
187 
188  // add new elements to vectors
189  RCP<Epetra_MultiVector> mv = rcp(new Epetra_MultiVector(map, count));
190  Teuchos::set_extra_data(mapItr->second, "globalMap", Teuchos::inOutArg(mv));
191  subVectors.push_back(mv);
192  }
193 }
194 
195 void associateSubVectors(const std::vector<std::pair<int, RCP<Epetra_Map> > >& subMaps,
196  std::vector<RCP<const Epetra_MultiVector> >& subVectors) {
197  std::vector<std::pair<int, RCP<Epetra_Map> > >::const_iterator mapItr;
198  std::vector<RCP<const Epetra_MultiVector> >::iterator vecItr;
199 
200  TEUCHOS_ASSERT(subMaps.size() == subVectors.size());
201 
202  // associate the sub vectors with the subMaps
203  for (mapItr = subMaps.begin(), vecItr = subVectors.begin(); mapItr != subMaps.end();
204  ++mapItr, ++vecItr)
205  Teuchos::set_extra_data(mapItr->second, "globalMap", Teuchos::inOutArg(*vecItr));
206 }
207 
208 // build a single subblock Epetra_CrsMatrix
209 RCP<Epetra_CrsMatrix> buildSubBlock(int i, int j, const Epetra_CrsMatrix& A,
210  const std::vector<std::pair<int, RCP<Epetra_Map> > >& subMaps) {
211  // get the number of variables families
212  int numVarFamily = subMaps.size();
213 
214  TEUCHOS_ASSERT(i >= 0 && i < numVarFamily);
215  TEUCHOS_ASSERT(j >= 0 && j < numVarFamily);
216 
217  const Epetra_Map& gRowMap = *subMaps[i].second;
218  const Epetra_Map& rowMap =
219  *Teuchos::get_extra_data<RCP<Epetra_Map> >(subMaps[i].second, "contigMap");
220  const Epetra_Map& colMap =
221  *Teuchos::get_extra_data<RCP<Epetra_Map> >(subMaps[j].second, "contigMap");
222  int colFamilyCnt = subMaps[j].first;
223 
224  // compute the number of global variables
225  // and the row and column block offset
226  int numGlobalVars = 0;
227  int rowBlockOffset = 0;
228  int colBlockOffset = 0;
229  for (int k = 0; k < numVarFamily; k++) {
230  numGlobalVars += subMaps[k].first;
231 
232  // compute block offsets
233  if (k < i) rowBlockOffset += subMaps[k].first;
234  if (k < j) colBlockOffset += subMaps[k].first;
235  }
236 
237  // copy all global rows to here
238  Epetra_Import import(gRowMap, A.RowMap());
239  Epetra_CrsMatrix localA(Copy, gRowMap, 0);
240  localA.Import(A, import, Insert);
241 
242  RCP<Epetra_CrsMatrix> mat = rcp(new Epetra_CrsMatrix(Copy, rowMap, 0));
243 
244  // get entry information
245  int numMyRows = rowMap.NumMyElements();
246  int maxNumEntries = A.GlobalMaxNumEntries();
247 
248  // for extraction
249  std::vector<int> indices(maxNumEntries);
250  std::vector<double> values(maxNumEntries);
251 
252  // for insertion
253  std::vector<int> colIndices(maxNumEntries);
254  std::vector<double> colValues(maxNumEntries);
255 
256  // insert each row into subblock
257  // let FillComplete handle column distribution
258  for (int localRow = 0; localRow < numMyRows; localRow++) {
259  int numEntries = -1;
260  int globalRow = gRowMap.GID(localRow);
261  int contigRow = rowMap.GID(localRow);
262 
263  TEUCHOS_ASSERT(globalRow >= 0);
264  TEUCHOS_ASSERT(contigRow >= 0);
265 
266  // extract a global row copy
267  int err =
268  localA.ExtractGlobalRowCopy(globalRow, maxNumEntries, numEntries, &values[0], &indices[0]);
269  TEUCHOS_ASSERT(err == 0);
270 
271  int numOwnedCols = 0;
272  for (int localCol = 0; localCol < numEntries; localCol++) {
273  int globalCol = indices[localCol];
274 
275  // determinate which block this column ID is in
276  int block = globalCol / numGlobalVars;
277 
278  bool inFamily = true;
279 
280  // test the beginning of the block
281  inFamily &= (block * numGlobalVars + colBlockOffset <= globalCol);
282  inFamily &= ((block * numGlobalVars + colBlockOffset + colFamilyCnt) > globalCol);
283 
284  // is this column in the variable family
285  if (inFamily) {
286  int familyOffset = globalCol - (block * numGlobalVars + colBlockOffset);
287 
288  colIndices[numOwnedCols] = block * colFamilyCnt + familyOffset;
289  colValues[numOwnedCols] = values[localCol];
290 
291  numOwnedCols++;
292  }
293  }
294 
295  // insert it into the new matrix
296  mat->InsertGlobalValues(contigRow, numOwnedCols, &colValues[0], &colIndices[0]);
297  }
298 
299  // fill it and automagically optimize the storage
300  mat->FillComplete(colMap, rowMap);
301 
302  return mat;
303 }
304 
305 // rebuild a single subblock Epetra_CrsMatrix
306 void rebuildSubBlock(int i, int j, const Epetra_CrsMatrix& A,
307  const std::vector<std::pair<int, RCP<Epetra_Map> > >& subMaps,
308  Epetra_CrsMatrix& mat) {
309  // get the number of variables families
310  int numVarFamily = subMaps.size();
311 
312  TEUCHOS_ASSERT(i >= 0 && i < numVarFamily);
313  TEUCHOS_ASSERT(j >= 0 && j < numVarFamily);
314  TEUCHOS_ASSERT(mat.Filled());
315 
316  const Epetra_Map& gRowMap = *subMaps[i].second;
317  const Epetra_Map& rowMap =
318  *Teuchos::get_extra_data<RCP<Epetra_Map> >(subMaps[i].second, "contigMap");
319  int colFamilyCnt = subMaps[j].first;
320 
321  // compute the number of global variables
322  // and the row and column block offset
323  int numGlobalVars = 0;
324  int rowBlockOffset = 0;
325  int colBlockOffset = 0;
326  for (int k = 0; k < numVarFamily; k++) {
327  numGlobalVars += subMaps[k].first;
328 
329  // compute block offsets
330  if (k < i) rowBlockOffset += subMaps[k].first;
331  if (k < j) colBlockOffset += subMaps[k].first;
332  }
333 
334  // copy all global rows to here
335  Epetra_Import import(gRowMap, A.RowMap());
336  Epetra_CrsMatrix localA(Copy, gRowMap, 0);
337  localA.Import(A, import, Insert);
338 
339  // clear out the old matrix
340  mat.PutScalar(0.0);
341 
342  // get entry information
343  int numMyRows = rowMap.NumMyElements();
344  int maxNumEntries = A.GlobalMaxNumEntries();
345 
346  // for extraction
347  std::vector<int> indices(maxNumEntries);
348  std::vector<double> values(maxNumEntries);
349 
350  // for insertion
351  std::vector<int> colIndices(maxNumEntries);
352  std::vector<double> colValues(maxNumEntries);
353 
354  // insert each row into subblock
355  // let FillComplete handle column distribution
356  for (int localRow = 0; localRow < numMyRows; localRow++) {
357  int numEntries = -1;
358  int globalRow = gRowMap.GID(localRow);
359  int contigRow = rowMap.GID(localRow);
360 
361  TEUCHOS_ASSERT(globalRow >= 0);
362  TEUCHOS_ASSERT(contigRow >= 0);
363 
364  // extract a global row copy
365  int err =
366  localA.ExtractGlobalRowCopy(globalRow, maxNumEntries, numEntries, &values[0], &indices[0]);
367  TEUCHOS_ASSERT(err == 0);
368 
369  int numOwnedCols = 0;
370  for (int localCol = 0; localCol < numEntries; localCol++) {
371  int globalCol = indices[localCol];
372 
373  // determinate which block this column ID is in
374  int block = globalCol / numGlobalVars;
375 
376  bool inFamily = true;
377 
378  // test the beginning of the block
379  inFamily &= (block * numGlobalVars + colBlockOffset <= globalCol);
380  inFamily &= ((block * numGlobalVars + colBlockOffset + colFamilyCnt) > globalCol);
381 
382  // is this column in the variable family
383  if (inFamily) {
384  int familyOffset = globalCol - (block * numGlobalVars + colBlockOffset);
385 
386  colIndices[numOwnedCols] = block * colFamilyCnt + familyOffset;
387  colValues[numOwnedCols] = values[localCol];
388 
389  numOwnedCols++;
390  }
391  }
392 
393  // insert it into the new matrix
394  mat.SumIntoGlobalValues(contigRow, numOwnedCols, &colValues[0], &colIndices[0]);
395  }
396 }
397 
398 // collect subvectors into a single global vector
399 void many2one(Epetra_MultiVector& one, const std::vector<RCP<const Epetra_MultiVector> >& many,
400  const std::vector<RCP<Epetra_Export> >& subExport) {
401  // std::vector<RCP<const Epetra_Vector> >::const_iterator vecItr;
402  std::vector<RCP<const Epetra_MultiVector> >::const_iterator vecItr;
403  std::vector<RCP<Epetra_Export> >::const_iterator expItr;
404 
405  // using Exporters fill the empty vector from the sub-vectors
406  for (vecItr = many.begin(), expItr = subExport.begin(); vecItr != many.end();
407  ++vecItr, ++expItr) {
408  // for ease of access to the source
409  RCP<const Epetra_MultiVector> srcVec = *vecItr;
410 
411  // extract the map with global indicies from the current vector
412  const Epetra_Map& globalMap = *(Teuchos::get_extra_data<RCP<Epetra_Map> >(srcVec, "globalMap"));
413 
414  // build the export vector as a view of the destination
415  Epetra_MultiVector exportVector(View, globalMap, srcVec->Values(), srcVec->Stride(),
416  srcVec->NumVectors());
417  one.Export(exportVector, **expItr, Insert);
418  }
419 }
420 
421 // distribute one global vector into a many subvectors
422 void one2many(std::vector<RCP<Epetra_MultiVector> >& many, const Epetra_MultiVector& single,
423  const std::vector<RCP<Epetra_Import> >& subImport) {
424  // std::vector<RCP<Epetra_Vector> >::const_iterator vecItr;
425  std::vector<RCP<Epetra_MultiVector> >::const_iterator vecItr;
426  std::vector<RCP<Epetra_Import> >::const_iterator impItr;
427 
428  // using Importers fill the sub vectors from the mama vector
429  for (vecItr = many.begin(), impItr = subImport.begin(); vecItr != many.end();
430  ++vecItr, ++impItr) {
431  // for ease of access to the destination
432  RCP<Epetra_MultiVector> destVec = *vecItr;
433 
434  // extract the map with global indicies from the current vector
435  const Epetra_Map& globalMap =
436  *(Teuchos::get_extra_data<RCP<Epetra_Map> >(destVec, "globalMap"));
437 
438  // build the import vector as a view on the destination
439  Epetra_MultiVector importVector(View, globalMap, destVec->Values(), destVec->Stride(),
440  destVec->NumVectors());
441 
442  // perform the import
443  importVector.Import(single, **impItr, Insert);
444  }
445 }
446 
447 } // namespace Strided
448 } // end namespace Epetra
449 } // end namespace Teko