MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_CoupledAggregationCommHelper_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_COUPLEDAGGREGATIONCOMMHELPER_DEF_HPP
47 #define MUELU_COUPLEDAGGREGATIONCOMMHELPER_DEF_HPP
48 
49 #include <Xpetra_MapFactory.hpp>
51 #include <Xpetra_BlockedVector.hpp>
52 #include <Xpetra_VectorFactory.hpp>
54 #include <Xpetra_ImportFactory.hpp>
55 #include <Xpetra_ExportFactory.hpp>
56 
58 
59 #include "MueLu_Utilities.hpp" // MueLu_maxAll
60 
61 namespace MueLu {
62 
63  template <class LocalOrdinal, class GlobalOrdinal, class Node>
65  import_ = ImportFactory::Build(uniqueMap, nonUniqueMap);
66  tempVec_ = VectorFactory::Build(uniqueMap,false); //zeroed out before use
67  numMyWinners_ = 0;
68  numCalls_ = 0;
69  myPID_ = uniqueMap->getComm()->getRank();
70  }
71 
72  template <class LocalOrdinal, class GlobalOrdinal, class Node>
73  void CoupledAggregationCommHelper<LocalOrdinal, GlobalOrdinal, Node>::ArbitrateAndCommunicate(Vector &weight_, LOVector &procWinner_, LOMultiVector *companion, const bool perturb) const {
74  const RCP<const Map> weightMap = weight_.getMap();
75  const size_t nodeNumElements = weightMap->getNodeNumElements();
76  const RCP<const Teuchos::Comm<int> > & comm = weightMap->getComm();
77  int MyPid = comm->getRank(); // TODO:remove the getMap() step
78  ++numCalls_;
79 
80  //short-circuit if only one process
81  if (comm->getSize() == 1) {
82  ArrayRCP<SC> serialWeight = weight_.getDataNonConst(0);
83  ArrayRCP<LO> serialProcWinner = procWinner_.getDataNonConst(0);
84  for (size_t i=0; i < nodeNumElements; ++i) {
85  if (serialWeight[i] > 0) {
86  serialWeight[i] = 0;
87  serialProcWinner[i] = MyPid;
88  }
89  }
90  //companion doesn't change
91  return;
92  }
93 
94 #ifdef COMPARE_IN_OUT_VECTORS
95  RCP<Vector> in_weight_ = VectorFactory::Build(weight_.getMap());
96  {
97  ArrayRCP<SC> in_weight = in_weight_->getDataNonConst(0);
98  ArrayRCP<SC> weight = weight_.getDataNonConst(0);
99  for (size_t i=0; i < nodeNumElements; ++i) in_weight[i] = weight[i];
100  }
101  RCP<LOVector> in_procWinner_ = LOVectorFactory::Build(procWinner_.getMap());
102  {
103  ArrayRCP<LO> in_procWinner = in_procWinner_->getDataNonConst(0);
104  ArrayRCP<LO> procWinner = procWinner_.getDataNonConst(0);
105  for (size_t i=0; i < nodeNumElements; ++i) in_procWinner[i] = procWinner[i];
106  }
107  RCP<LOMultiVector> in_companion;
108  {
109  if (companion != NULL) {
110  in_companion = LOMultiVectorFactory::Build(companion->getMap(), companion->getNumVectors());
111  ArrayRCP<LO> in_comp = in_companion->getDataNonConst(0);
112  ArrayRCP<LO> comp = companion->getDataNonConst(0);
113  for (size_t i=0; i < nodeNumElements; ++i) in_comp[i] = comp[i];
114  }
115  }
116 #endif
117 
118  typedef Teuchos::ScalarTraits<SC> ST;
119 
120  if (perturb) {
121  if (perturbWt_ == Teuchos::null || !perturbWt_->getMap()->isSameAs(*weightMap)) {
122  perturbWt_ = VectorFactory::Build(weightMap,false); //no need to zero out because this will be randomized
123 
124  // Modify seed of the random algorithm used by perturbWt_->randomize()
125  {
126  ST::seedrandom( Teuchos::as<unsigned int>(MyPid*47) );
127  for (int i = 0; i < 10; ++i) ST::random();
128  }
129  //Note that we must not use perturbWt_->randomize(). This produces the same
130  //local random vector on each processor. The whole point of the weights
131  //is to provide tie-breaking that isn't based on the highest PID.
132  ArrayRCP<SC> lperturbWt = perturbWt_->getDataNonConst(0);
133  for (size_t i=0; i < nodeNumElements; ++i)
134  lperturbWt[i] = 1e-7*fabs(ST::random()); //FIXME this won't work for general SC
135 #ifdef COMPARE_IN_OUT_VECTORS
136  ArrayRCP<SC> locperturbWt = perturbWt_->getDataNonConst(0);
137  for (size_t i=0; i < nodeNumElements; ++i)
138  printf("perturbWt[%d] = %15.10e\n",i,locperturbWt[i]);
139 #endif
140  } //if (perturbWt_ == Teuchos::null || ...
141 
142  ArrayRCP<SC> weight = weight_.getDataNonConst(0); // TODO: const?
143  ArrayRCP<SC> perturbWt = perturbWt_->getDataNonConst(0);
144 
145  // Note: maxValue() not available for Tpetra
146  //SC largestGlobalWeight = weight_.maxValue();
147  SC largestGlobalWeight = weight_.normInf();
148  for (size_t i=0; i < nodeNumElements; ++i) {
149  if (weight[i] != 0.) {
150  weight[i] += largestGlobalWeight*perturbWt[i];
151  }
152  }
153  //TODO is it necessary to return the *perturbed* weights?
154  } //if (perturb)
155 
156  // Communicate weights and store results in PostComm (which will be copied
157  // back into weights later. When multiple processors have different weights
158  // for the same GID, we take the largest weight. After this fragment every
159  // processor should have the same value for PostComm[] even when multiple
160  // copies of the same Gid are involved.
161 
162  if (postComm_ == Teuchos::null || !postComm_->getMap()->isSameAs(*weightMap) )
163  postComm_ = VectorFactory::Build(weightMap);
164 
165  //note: postComm_ is zeroed either in build above, or in loop below upon last touch.
166 
167  NonUnique2NonUnique(weight_, *postComm_, Xpetra::ABSMAX);
168 
169  // Let every processor know who is the procWinner. For nonunique
170  // copies of the same Gid, this corresponds to the processor with
171  // the highest Wt[]. When several processors have the same positive value
172  // for weight[] (which is also the maximum value), the highest proc id
173  // is declared the procWinner.
174  //
175  // Note:This is accomplished by filling a vector with MyPid+1 if weight[k] is
176  // nonzero and PostComm[k]==weight[k]. NonUnique2NonUnique(...,AbsMax)
177  // is invoked to let everyone know the procWinner.
178  // One is then subtracted so that procWinner[i] indicates the
179  // Pid of the winning processor.
180  // When all weight's for a GID are zero, the associated procWinner's
181  // are left untouched.
182 
183  if (candidateWinners_ == Teuchos::null || !candidateWinners_->getMap()->isSameAs(*weightMap) )
184  candidateWinners_ = VectorFactory::Build(weightMap,false);
185  //note: candidateWinners_ is initialized below
186 
187  ArrayRCP<SC> weight = weight_.getDataNonConst(0);
188 
189  {
190  ArrayRCP<SC> candidateWinners = candidateWinners_->getDataNonConst(0);
191  ArrayRCP<SC> postComm = postComm_->getDataNonConst(0);
192  for (size_t i=0; i < nodeNumElements; ++i) {
193  if (postComm[i] == weight[i]) candidateWinners[i] = (SC) MyPid+1;
194  else candidateWinners[i] = 0;
195  weight[i]=postComm[i];
196  }
197  }
198  NonUnique2NonUnique(*candidateWinners_, *postComm_, Xpetra::ABSMAX);
199 
200  // Note:
201  // associated CandidateWinners[]
202  // weight[i]!=0 ==> on some proc is equal to its ==> postComm[i]!=0
203  // MyPid+1.
204  //
205  int numMyWinners = 0;
206  ArrayRCP<LO> procWinner = procWinner_.getDataNonConst(0);
207  {
208  ArrayRCP<SC> postComm = postComm_->getDataNonConst(0);
209  for (size_t i=0; i < nodeNumElements; ++i) {
210  if ( weight[i] != 0.) procWinner[i] = ((int) (postComm[i])) - 1;
211  weight[i] = 0.; //we are done with weight
212  postComm[i] = 0.; //avoids having to initialize postComm_ on next call to ArbitrateAndCommunicate
213  if (procWinner[i] == MyPid) ++numMyWinners;
214  }
215  }
216 
217  weight = Teuchos::null; //TODO why do we do this?
218 
219  if (companion != NULL) {
220  // Now build a new Map, WinnerMap which just consists of procWinners.
221  // This is done by extracting the Gids for Wt, and shoving
222  // the subset that correspond to procWinners in MyWinners.
223  // WinnerMap is then constructed using MyWinners.
224  //
225  // In order to avoid regenerating winnerMap_, the following are checked:
226  // 1) Do the local number of entries in MyWinners differ? If so, regenerate/repopulate MyWinners and regenerate winnerMap_.
227  // 2) If the local number of entries in MyWinners are the same, do any entries differ? If so, repopulate MyWinners and
228  // regenerate winnerMap_.
229 
230  ArrayView<const GO> myGids = weightMap->getNodeElementList(); //== weightMap->MyGlobalElements(myGids);
231  bool realloc=false;
232  if (numMyWinners != numMyWinners_ || winnerMap_ == Teuchos::null) {
233  // The local number of entries in MyWinners_ have changed since the last invocation, so reallocate myWinners_.
234  myWinners_ = ArrayRCP<GO>(numMyWinners);
235  realloc=true;
236  //std::cout << MyPid << ": numMyWinners has changed : (old) " << numMyWinners_ << ", (new) " << numMyWinners << std::endl;
237  numMyWinners_ = numMyWinners;
238  }
239 
240 #ifdef JG_DEBUG
241  procWinner = Teuchos::null;
242  std::cout << MyPid << ": nodeNumElements=" << nodeNumElements << std::endl;
243  std::cout << MyPid << ": procWinner=" << procWinner_ << std::endl;
244  procWinner = procWinner_.getDataNonConst(0);
245 #endif
246 
247  if (realloc==true) {
248  // The local number of entries in MyWinners have changed since the last invocation, so repopulate MyWinners_.
249  numMyWinners = 0;
250  for (size_t i = 0; i < nodeNumElements; ++i) {
251  if (procWinner[i] == MyPid) {
252  myWinners_[numMyWinners++] = myGids[i];
253  }
254  }
255  } else {
256  // The local number of entries in MyWinners are the same as the last invocation, but
257  // we still must check if any entries differ from the last invocation.
258  bool entryMismatch=false;
259  numMyWinners = 0;
260  for (size_t i = 0; i < nodeNumElements; ++i) {
261  if (procWinner[i] == MyPid) {
262  if (myWinners_[numMyWinners++] != myGids[i]) {
263  entryMismatch=true;
264  break;
265  }
266  }
267  }
268 
269  if (entryMismatch == true) {
270  // Entries differ from last invocation, so repopulate myWinners_.
271  realloc=true;
272  numMyWinners = 0;
273  for (size_t i = 0; i < nodeNumElements; ++i) {
274  if (procWinner[i] == MyPid) {
275  myWinners_[numMyWinners++] = myGids[i];
276  }
277  }
278  }
279  } //if (realloc==true) ... else
280 
281  procWinner = Teuchos::null;
282 
283 #ifdef JG_DEBUG
284  std::cout << MyPid << ": numMyWinners=" << numMyWinners << std::endl;
285  std::cout << MyPid << ": myWinners_" << myWinners_ << std::endl;
286  for(int i=0;i<numMyWinners; i++)
287  std::cout << MyPid << ": myWinners_[locId=" << i << "] = " << myWinners_[i] << std::endl;
288 
289 #endif
290 
291 #ifdef HAVE_MPI
292  //See whether any process has determined that winnerMap_ must be regenerated.
293  int irealloc,orealloc;
294  if (realloc) irealloc=1;
295  else irealloc=0;
296  MueLu_maxAll(comm,irealloc,orealloc);
297  if (orealloc == 1) realloc=true;
298  else realloc=false;
299 #endif
300 
301  if (realloc) {
302  // Either the number of entries or the value have changed since the last invocation, so reallocation the map.
304  winnerMap_ = MapFactory::Build(weightMap->lib(), GSTI, myWinners_(), 0, weightMap->getComm());
305  }
306 
307  // Pull the Winners out of companion
308  // JustWinners <-- companion[Winners];
309 
310  RCP<LOMultiVector> justWinners = LOMultiVectorFactory::Build(winnerMap_, companion->getNumVectors());
311 
312 #ifdef JG_DEBUG
313  RCP<Teuchos::FancyOStream> out = rcp(new Teuchos::FancyOStream(rcp(&std::cout,false)));
314  std::cout << MyPid << ": justWinners(Vector in)=" << *justWinners << std::endl;
315  justWinners->describe(*out, Teuchos::VERB_EXTREME);
316 #endif
317 
318  if ( winnerImport_ == Teuchos::null
319  || !winnerImport_->getSourceMap()->isSameAs(*weightMap)
320  || !winnerImport_->getTargetMap()->isSameAs(*winnerMap_) )
321  winnerImport_ = ImportFactory::Build(weightMap, winnerMap_);
322  RCP<const Import> winnerImport = winnerImport_;
323  try
324  {
325  justWinners->doImport(*companion, *winnerImport, Xpetra::INSERT);
326  }
327  catch(std::exception& e)
328  {
329  std::cout << MyPid << ": ERR2: An exception occurred." << std::endl;
330  throw e;
331  }
332 
333  // Put the JustWinner values back into companion so that
334  // all nonunique copies of the same Gid have the procWinner's
335  // version of the companion.
336  //#define JG_DEBUG
337 #ifdef JG_DEBUG
338  RCP<Teuchos::FancyOStream> fos = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
339  fos->setOutputToRootOnly(-1);
340  if (!weightMap->getComm()->getRank())
341  std::cout << "------ winnerMap_ ------" << std::endl;
342  winnerMap_->describe(*fos,Teuchos::VERB_EXTREME);
343  if (!weightMap->getComm()->getRank())
344  std::cout << "------ weightMap ------" << std::endl;
345  weightMap->getComm()->barrier();
346  weightMap->describe(*fos,Teuchos::VERB_EXTREME);
347  //std::cout << *winnerMap_ << std::endl;
348  //std::cout << *weightMap << std::endl;
349  sleep(5);
350  exit(1);
351 #endif
352 #ifdef JG_DEBUG
353 #undef JG_DEBUG
354 #endif
355 
356  if ( pushWinners_ == Teuchos::null
357  || !pushWinners_->getSourceMap()->isSameAs(*winnerMap_)
358  || !pushWinners_->getTargetMap()->isSameAs(*weightMap) )
359  pushWinners_ = ImportFactory::Build(winnerMap_,weightMap);
360  RCP<Import> pushWinners = pushWinners_;
361  //RCP<Import> pushWinners = ImportFactory::Build(winnerMap_, weightMap); // VERSION1
362  //RCP<Export> pushWinners = ExportFactory::Build(winnerMap_, weightMap); // VERSION4
363  try
364  {
365  companion->doImport(*justWinners, *pushWinners, Xpetra::INSERT); // VERSION1 Slow
366  //companion->doExport(*justWinners, *winnerImport_, Xpetra::INSERT); // JJH this should work... but exception
367  // if (weightMap->lib() == Xpetra::UseEpetra)
368  // justWinners->doExport(*companion, *winnerImport, Xpetra::INSERT); // VERSION2 Tpetra doc is wrong
369  // else if (weightMap->lib() == Xpetra::UseTpetra)
370  // companion->doExport(*justWinners, *winnerImport, Xpetra::INSERT); // VERSION3 - TODO: will certainly not work with Epetra? (change Xpetra?)
371  //companion->doExport(*justWinners, *pushWinners, Xpetra::INSERT); // VERSION4
372  // else throw "lib()";
373  }
374  catch(std::exception& e)
375  {
376  throw e;
377  }
378  //#define JG_DEBUG
379 #ifdef JG_DEBUG
380  // RCP<Teuchos::FancyOStream> out = rcp(new Teuchos::FancyOStream(rcp(&std::cout,false)));
381  //->describe(*out, Teuchos::VERB_EXTREME);
382 
383  // std::cout << MyPid << ": ERR3: An exception occurred." << std::endl;
384 
385  std::cout << MyPid << ": numMyWinners=" << numMyWinners << std::endl;
386 
387  std::cout << MyPid << ": justWinners(Vector in)=" << std::endl;
388  justWinners->describe(*out, Teuchos::VERB_EXTREME);
389 
390  std::cout << MyPid << ": companion(Vector out)=" << std::endl;
391  companion->describe(*out, Teuchos::VERB_EXTREME);
392 
393  // std::cout << MyPid << ": pushWinners(Import(winnerMap_, weight_.Map))=" << *pushWinners << std::endl;
394  std::cout << MyPid << ": winnerMap_=" << *winnerMap_ << std::endl;
395  std::cout << MyPid << ": weight_.Map=" << *weightMap << std::endl;
396 #endif
397  // throw e;
398  // throw 1;
399  }
400 
401 #ifdef COMPARE_IN_OUT_VECTORS
402  if (MyPid == 0) {
403  std::cout << "==============" << std::endl;
404  std::cout << "call #" << numCalls << " (1-based)" << std::endl;
405  std::cout << "==============" << std::endl;
406  }
407  /*
408  bool sameWeight=true;
409  bool sameWinner=true;
410  bool sameComp=true;
411  */
412  std::string sameOrDiff;
413  {
414  ArrayRCP<SC> in_weight = in_weight_->getDataNonConst(0);
415  ArrayRCP<SC> weight = weight_.getDataNonConst(0);
416  if (MyPid == 0) std::cout << "==============\nweight\n==============\n" << std::endl;
417  for (size_t i=0; i < weight_.getLocalLength(); ++i) {
418  if (in_weight[i] - weight[i] != 0) sameOrDiff = " <<<<";
419  else sameOrDiff = " ";
420  std::cout << std::setw(3) << i<<": " << in_weight[i] << " " << weight[i] << sameOrDiff << in_weight[i] - weight[i] << std::endl;
421  /*
422  if (in_weight[i] != weight[i]) {
423  sameWeight=false;
424  std::cout << "\n\nin and out weight DIFFER\n\n" << std::endl;
425  std::cout << "i="<<i<<", in=" << in_weight[i] << " , out=" << weight[i] << std::endl;
426  break;
427  }
428  */
429  }
430  }
431 
432  {
433  ArrayRCP<LO> in_procWinner = in_procWinner_->getDataNonConst(0);
434  ArrayRCP<LO> procWinner = procWinner_.getDataNonConst(0);
435  if (MyPid == 0) std::cout << "==============\nprocWinner\n==============\n" << std::endl;
436  for (size_t i=0; i < procWinner_.getLocalLength(); ++i) {
437  if (in_procWinner[i] != procWinner[i]) sameOrDiff = " <<<<";
438  else sameOrDiff = " ";
439  std::cout << std::setw(3) << i<<": " << in_procWinner[i] << " " << procWinner[i] << sameOrDiff << std::endl;
440  /*
441  if (in_procWinner[i] != procWinner[i]) {
442  sameWinner=false;
443  std::cout << "\n\nin and out procWinner DIFFER\n\n" << std::endl;
444  std::cout << "i="<<i<<", in=" << in_procWinner[i] << ", out=" << procWinner[i] << std::endl;
445  break;
446  }
447  */
448  }
449  }
450 
451  {
452  if (companion != NULL) {
453  ArrayRCP<LO> in_comp = in_companion->getDataNonConst(0);
454  ArrayRCP<LO> comp = companion->getDataNonConst(0);
455  if (MyPid == 0) std::cout << "==============\ncompanion\n==============\n" << std::endl;
456  for (size_t i=0; i < companion->getLocalLength(); ++i) {
457  if (in_comp[i] != comp[i]) sameOrDiff = " <<<<";
458  else sameOrDiff = " ";
459  std::cout << std::setw(3) << i<<": " << in_comp[i] << " " << comp[i] << sameOrDiff << std::endl;
460  /*
461  if (in_comp[i] != comp[i]) {
462  sameComp=false;
463  std::cout << "\n\nin and out companion DIFFER\n\n" << std::endl;
464  std::cout << "i="<<i<<", in=" << in_comp[i] << ", out=" << comp[i] << std::endl;
465  break;
466  }
467  */
468  }
469  }
470  }
471 #endif
472  } //ArbitrateAndCommunicate(Vector&, LOVector &, LOVector *, const bool) const
473 
474  template <class LocalOrdinal, class GlobalOrdinal, class Node>
476  tempVec_->putScalar(0.);
477 
478  try
479  {
480  tempVec_->doExport(source, *import_, what);
481  dest.doImport(*tempVec_, *import_, Xpetra::INSERT);
482  }
483  catch(std::exception& e)
484  {
485  int MyPid = tempVec_->getMap()->getComm()->getRank();
486  std::cout << MyPid << ": ERR1: An exception occurred." << std::endl;
487  throw e;
488  }
489  }
490 
491 }
492 
493 #endif // MUELU_COUPLEDAGGREGATIONCOMMHELPER_DEF_HPP
494 
#define MueLu_maxAll(rcpComm, in, out)
void NonUnique2NonUnique(const Vector &source, Vector &dest, const Xpetra::CombineMode what) const
Redistribute data in source to dest where both source and dest might have multiple copies of the same...
void ArbitrateAndCommunicate(Vector &weights, Aggregates &aggregates, const bool perturb) const
This method assigns unknowns to aggregates.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
size_t global_size_t
CoupledAggregationCommHelper(const RCP< const Map > &uniqueMap, const RCP< const Map > &nonUniqueMap)
Constructor.
Scalar SC
void realloc(DynRankView< T, P...> &v, const size_t n0=KOKKOS_INVALID_INDEX, const size_t n1=KOKKOS_INVALID_INDEX, const size_t n2=KOKKOS_INVALID_INDEX, const size_t n3=KOKKOS_INVALID_INDEX, const size_t n4=KOKKOS_INVALID_INDEX, const size_t n5=KOKKOS_INVALID_INDEX, const size_t n6=KOKKOS_INVALID_INDEX, const size_t n7=KOKKOS_INVALID_INDEX)