DAColoring.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2 
3  DAFoam : Discrete Adjoint with OpenFOAM
4  Version : v3
5 
6 \*---------------------------------------------------------------------------*/
7 
8 #include "DAColoring.H"
9 
10 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
11 
12 namespace Foam
13 {
14 
15 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
16 
17 DAColoring::DAColoring(
18  const fvMesh& mesh,
19  const DAOption& daOption,
20  const DAModel& daModel,
21  const DAIndex& daIndex)
22  : mesh_(mesh),
23  daOption_(daOption),
24  daIndex_(daIndex)
25 {
26 }
27 
28 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
29 
30 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
31 
33  const Mat conMat,
34  Vec colors,
35  label& nColors) const
36 {
37  /*
38  Description:
39  A general function to compute coloring for a Jacobian matrix using a
40  paralel heuristic distance 2 algorithm
41 
42  Input:
43  conMat: a Petsc matrix that have the connectivity pattern (value one for
44  all nonzero elements)
45 
46  Output:
47  colors: the coloring vector to store the coloring indices, starting with 0
48 
49  nColors: the number of colors
50 
51  Example:
52  If the conMat reads,
53 
54  color0 color1
55  | |
56  1 0 0 0
57  conMat = 0 1 1 0
58  0 0 1 0
59  0 0 0 1
60  | |
61  color0 color0
62 
63  Then, calling this function gives colors = {0, 0, 1, 0}.
64  This can be done for parallel conMat
65  */
66 
67  // if we end up having more than 10000 colors, something must be wrong
68  label maxColors = 10000;
69 
70  PetscInt nCols, nCols2;
71  const PetscInt* cols;
72  const PetscScalar* vals;
73  const PetscScalar* vals2;
74 
75  PetscInt colorStart, colorEnd;
76  VecScatter colorScatter;
77 
78  label Istart, Iend;
79  label currColor;
80  label notColored = 1;
81  IS globalIS;
82  label maxCols = 750;
83  scalar allNonZeros;
84  Vec globalVec;
85  PetscInt nRowG, nColG;
86 
87  Info << "Parallel Distance 2 Graph Coloring...." << endl;
88 
89  // initialize the number of colors to zero
90  nColors = 0;
91 
92  // get the range of colors owned by the local prock
93  VecGetOwnershipRange(colors, &colorStart, &colorEnd);
94 
95  // Set the entire color vector to -1
96  VecSet(colors, -1);
97 
98  // Determine which rows are on the current processor
99  MatGetOwnershipRange(conMat, &Istart, &Iend);
100 
101  //then get the global number of rows and columns
102  MatGetSize(conMat, &nRowG, &nColG);
103  label nRowL = Iend - Istart;
104  label nColL = colorEnd - colorStart;
105 
106  /*
107  Start by looping over the rows to determine the largest
108  number of non-zeros per row. This will determine maxCols
109  and the minumum bound for the number of colors.
110  */
111  this->getMatNonZeros(conMat, maxCols, allNonZeros);
112  Info << "MaxCols: " << maxCols << endl;
113  Info << "AllNonZeros: " << allNonZeros << endl;
114 
115  // Create a local sparse matrix with a single row to use as a sparse vector
116  Mat localCols;
117  MatCreateSeqAIJ(
118  PETSC_COMM_SELF,
119  1,
122  NULL,
123  &localCols);
124  MatSetOption(localCols, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);
125  MatSetUp(localCols);
126  MatZeroEntries(localCols);
127 
128  //Now loop over the owned rows and set the value in any occupied col to 1.
129  PetscInt idxI = 0;
130  PetscScalar v = 1;
131  for (label i = Istart; i < Iend; i++)
132  {
133  MatGetRow(conMat, i, &nCols, &cols, &vals);
134  // set any columns that have a nonzero entry into localCols
135  for (label j = 0; j < nCols; j++)
136  {
137  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
138  {
139  PetscInt idx = cols[j];
140  MatSetValues(localCols, 1, &idxI, 1, &idx, &v, INSERT_VALUES);
141  }
142  }
143  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
144  }
145  MatAssemblyBegin(localCols, MAT_FINAL_ASSEMBLY);
146  MatAssemblyEnd(localCols, MAT_FINAL_ASSEMBLY);
147 
148  // now localCols contains the unique set of local columns on each processor
149  label nUniqueCols = 0;
150  MatGetRow(localCols, 0, &nCols, &cols, &vals);
151  for (label j = 0; j < nCols; j++)
152  {
153  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
154  {
155  nUniqueCols++;
156  }
157  }
158  Info << "nUniqueCols: " << nUniqueCols << endl;
159 
160  //Loop over the local vectors and set nonzero entries in a global vector
161  // This lets us determine which columns are strictly local and which have
162  // interproccessor overlap.
163  VecCreate(PETSC_COMM_WORLD, &globalVec);
164  VecSetSizes(globalVec, nColL, PETSC_DECIDE);
165  VecSetFromOptions(globalVec);
166  VecSet(globalVec, 0);
167 
168  for (label j = 0; j < nCols; j++)
169  {
170  PetscInt idx = cols[j];
171  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
172  {
173  VecSetValue(globalVec, idx, vals[j], ADD_VALUES);
174  }
175  }
176  VecAssemblyBegin(globalVec);
177  VecAssemblyEnd(globalVec);
178 
179  MatRestoreRow(localCols, 0, &nCols, &cols, &vals);
180 
181  // now create an index set of the strictly local columns
182  label* localColumnStat = new label[nUniqueCols];
183  label* globalIndexList = new label[nUniqueCols];
184 
185  PetscScalar* globalVecArray;
186  VecGetArray(globalVec, &globalVecArray);
187 
188  label colCounter = 0;
189  MatGetRow(localCols, 0, &nCols, &cols, &vals);
190  for (label j = 0; j < nCols; j++)
191  {
192  label col = cols[j];
193  if (DAUtility::isValueCloseToRef(vals[j], 1.0))
194  {
195  globalIndexList[colCounter] = col;
196  localColumnStat[colCounter] = 1;
197  if (col >= colorStart && col < colorEnd)
198  {
199  if (DAUtility::isValueCloseToRef(globalVecArray[col - colorStart], 1.0))
200  {
201  localColumnStat[colCounter] = 2; // 2: strictly local
202  }
203  }
204  colCounter++;
205  }
206  }
207  MatRestoreRow(localCols, 0, &nCols, &cols, &vals);
208  MatDestroy(&localCols);
209 
210  // create a list of the rows that have any of the strictly local columns included
211 
212  label* localRowList = new label[nRowL];
213  for (label i = Istart; i < Iend; i++)
214  {
215  label idx = i - Istart;
216  MatGetRow(conMat, i, &nCols, &cols, &vals);
217  //check if this row has any strictly local columns
218 
219  /*we know that our global index lists are stored sequentially, so we
220  don't need to start every index search at zero, we can start at the
221  last entry found in this row */
222  label kLast = -1;
223  for (label j = 0; j < nCols; j++)
224  {
225  label matCol = cols[j];
226  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
227  {
228  //Info<<"j: "<<j<<vals[j]<<endl;
229  kLast = this->find_index(matCol, kLast + 1, nUniqueCols, globalIndexList);
230 
231  if (kLast >= 0)
232  {
233  //k was found
234  label localVal = localColumnStat[kLast];
235  if (localVal == 2)
236  {
237  localRowList[idx] = 1;
238  break;
239  }
240  else
241  {
242  localRowList[idx] = 0;
243  }
244  }
245  else
246  {
247  localRowList[idx] = 0;
248  }
249  }
250  }
251  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
252  }
253  VecRestoreArray(globalVec, &globalVecArray);
254 
255  /* Create the scatter context for the remainder of the function */
256  Vec colorsLocal;
257  // create a scatter context for these colors
258  VecCreateSeq(PETSC_COMM_SELF, nUniqueCols, &colorsLocal);
259  VecSet(colorsLocal, -1);
260 
261  // now create the Index sets
262  ISCreateGeneral(PETSC_COMM_WORLD, nUniqueCols, globalIndexList, PETSC_COPY_VALUES, &globalIS);
263  // Create the scatter
264  VecScatterCreate(colors, globalIS, colorsLocal, NULL, &colorScatter);
265 
266  /* Create the conflict resolution scheme*/
267  // create tiebreakers locally
268  Vec globalTiebreaker;
269  VecDuplicate(globalVec, &globalTiebreaker);
270  for (label i = colorStart; i < colorEnd; i++)
271  {
272  srand(i);
273  PetscScalar val = rand() % nColG;
274  VecSetValue(globalTiebreaker, i, val, INSERT_VALUES);
275  }
276 
277  // and scatter the random values
278  Vec localTiebreaker;
279  VecDuplicate(colorsLocal, &localTiebreaker);
280  VecScatterBegin(colorScatter, globalTiebreaker, localTiebreaker, INSERT_VALUES, SCATTER_FORWARD);
281  VecScatterEnd(colorScatter, globalTiebreaker, localTiebreaker, INSERT_VALUES, SCATTER_FORWARD);
282 
283  //initialize conflict columns
284  label* conflictCols = new label[maxCols];
285  label* conflictLocalColIdx = new label[maxCols];
286  for (label j = 0; j < maxCols; j++)
287  {
288  conflictCols[j] = -1;
289  conflictLocalColIdx[j] = -1;
290  }
291 
292  // Create a global distrbuted vector of the only the local portion of
293  // localcolumnsstatus
294  Vec globalColumnStat;
295  VecDuplicate(colors, &globalColumnStat);
296  VecSet(globalColumnStat, 0.0);
297  for (label k = 0; k < nUniqueCols; k++)
298  {
299  label localCol = globalIndexList[k];
300  PetscScalar localVal = localColumnStat[k];
301  if (localCol >= colorStart && localCol < colorEnd)
302  {
303  VecSetValue(globalColumnStat, localCol, localVal, INSERT_VALUES);
304  }
305  }
306  VecAssemblyBegin(globalColumnStat);
307  VecAssemblyEnd(globalColumnStat);
308 
309  /*
310  create a duplicate matrix for conMat that contains its index into the
311  local arrays
312  */
313  Mat conIndMat;
314  MatDuplicate(conMat, MAT_SHARE_NONZERO_PATTERN, &conIndMat);
315 
316  // now loop over conMat locally, find the index in the local array
317  // and store that value in conIndMat
318  for (label i = Istart; i < Iend; i++)
319  {
320  MatGetRow(conMat, i, &nCols, &cols, &vals);
321  label kLast = -1;
322  for (label j = 0; j < nCols; j++)
323  {
324  label matCol = cols[j];
325  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
326  {
327  kLast = this->find_index(matCol, kLast + 1, nUniqueCols, globalIndexList);
328  PetscScalar val = kLast;
329  MatSetValue(conIndMat, i, matCol, val, INSERT_VALUES);
330  }
331  }
332  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
333  }
334  MatAssemblyBegin(conIndMat, MAT_FINAL_ASSEMBLY);
335  MatAssemblyEnd(conIndMat, MAT_FINAL_ASSEMBLY);
336 
337  /*Now color the locally independent columns using the only the rows
338  that contain entries from those columns.*/
339 
340  // Retrieve the local portion of the color vector
341  PetscScalar *colColor, *tbkrLocal, *tbkrGlobal, *globalStat;
342  VecGetArray(colors, &colColor);
343  VecGetArray(localTiebreaker, &tbkrLocal);
344  VecGetArray(globalTiebreaker, &tbkrGlobal);
345  VecGetArray(globalColumnStat, &globalStat);
346 
347  // Loop over the maximum number of colors
348  label printInterval = daOption_.getOption<label>("printInterval");
349  for (label n = 0; n < maxColors; n++)
350  {
351  if (n % printInterval == 0)
352  {
353  Info << "ColorSweep: " << n << " " << mesh_.time().elapsedClockTime() << " s" << endl;
354  }
355 
356  /* Set all entries for strictly local columns that are currently -1
357  to the current color */
358  for (label k = 0; k < nUniqueCols; k++)
359  {
360  label localCol = globalIndexList[k];
361  label localVal = localColumnStat[k];
362  if (localCol >= colorStart && localCol < colorEnd && localVal == 2)
363  {
364  // this is a strictly local column;
365  label idx = localCol - colorStart;
366  if (DAUtility::isValueCloseToRef(colColor[idx], -1.0))
367  {
368  colColor[idx] = n;
369  }
370  }
371  }
372 
373  //Now loop over the rows and resolve conflicts
374  for (label i = Istart; i < Iend; i++)
375  {
376 
377  // Get the row local row index
378  label idx = i - Istart;
379 
380  //create the variables for later sorting
381  label smallest = nColG;
382  label idxKeep = -1;
383 
384  //First check if this is a row that contains strictly local columns
385  if (localRowList[idx] > 0)
386  {
387 
388  /* this is a row that contains strictly local columns,get the
389  row information */
390  MatGetRow(conMat, i, &nCols, &cols, &vals);
391 
392  // set any columns with the current color into conflictCols
393  for (label j = 0; j < nCols; j++)
394  {
395  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
396  {
397  label colIdx = cols[j];
398 
399  // Check that this is a local column
400  if (colIdx >= colorStart && colIdx < colorEnd)
401  {
402  //now check if it is a strictly local column
403  label localVal = globalStat[colIdx - colorStart];
404  if (localVal == 2)
405  {
406  // check if the color in this column is from the
407  // current set
408  if (DAUtility::isValueCloseToRef(colColor[colIdx - colorStart], n * 1.0))
409  {
410  /* This is a potentially conflicting column
411  store it */
412  conflictCols[j] = colIdx;
413 
414  // now check whether this is the one we keep
415  label tbkr = tbkrGlobal[colIdx - colorStart];
416  if (tbkr < smallest)
417  {
418  smallest = tbkr;
419  idxKeep = colIdx;
420  }
421  }
422  }
423  }
424  }
425  }
426 
427  // Now reset all columns but the one that wins the tiebreak
428  for (label j = 0; j < nCols; j++)
429  {
430 
431  //check if this is a conflicting column
432  label colIdx = conflictCols[j];
433  if (colIdx >= 0)
434  {
435  // Check that this is also a local column
436  if (colIdx >= colorStart && colIdx < colorEnd)
437  {
438  // and now if it is a strictly local column
439  label localVal = globalStat[colIdx - colorStart];
440  if (localVal == 2)
441  {
442  // now reset the column
443  if (colIdx >= 0 && (colIdx != idxKeep))
444  {
445  colColor[colIdx - colorStart] = -1;
446  }
447  }
448  }
449  }
450  }
451  // reset the changed values in conflictCols
452  for (label j = 0; j < nCols; j++)
453  {
454  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
455  {
456  //reset all values related to this row in conflictCols
457  conflictCols[j] = -1;
458  }
459  }
460  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
461  }
462  }
463 
464  // now we want to check the coloring on the strictly local columns
465  notColored = 0;
466 
467  //loop over the columns and check if there are any uncolored rows
468  label colorCounter = 0;
469  for (label k = 0; k < nUniqueCols; k++)
470  {
471  // get the column info
472  label localVal = localColumnStat[k];
473  label localCol = globalIndexList[k];
474  // check if it is strictly local, if so it should be colored
475  if (localVal == 2)
476  {
477  // confirm that it is a local column (is this redundant?
478  if (localCol >= colorStart && localCol < colorEnd)
479  {
480  label idx = localCol - colorStart;
481  label color = colColor[idx];
482  // now check that it has been colored
483  if (not(color >= 0))
484  {
485  // this column is not colored and coloring is not complete
486  notColored = 1;
487  colorCounter++;
488  //break;
489  }
490  }
491  }
492  }
493 
494  // reduce the logical so that we know that all of the processors are
495  // ok
496  reduce(notColored, sumOp<label>());
497  reduce(colorCounter, sumOp<label>());
498 
499  if (n % printInterval == 0)
500  {
501  Info << "number of uncolored: " << colorCounter << " " << notColored << endl;
502  }
503 
504  if (notColored == 0)
505  {
506  Info << "ColorSweep: " << n << " " << mesh_.time().elapsedClockTime() << " s" << endl;
507  Info << "number of uncolored: " << colorCounter << " " << notColored << endl;
508  break;
509  }
510  }
511  VecRestoreArray(colors, &colColor);
512  /***** end of local coloring ******/
513 
514  // now redo the local row list to handle the global columns
515  // create a list of the rows that have any of the global columns included
516 
517  for (label i = Istart; i < Iend; i++)
518  {
519  label idx = i - Istart;
520  // get the row information
521  MatGetRow(conMat, i, &nCols, &cols, &vals);
522 
523  //check if this row has any non-local columns
524 
525  /* We know that our localColumnStat is stored sequentially, so we don't
526  need to start every index search at zero, we can start at the last
527  entry found in this row.*/
528  label kLast = -1;
529 
530  for (label j = 0; j < nCols; j++)
531  {
532  // get the column of interest
533  label matCol = cols[j];
534  // confirm that it has an entry
535  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
536  {
537  // find the index into the local arrays for this column
538  kLast = this->find_index(matCol, kLast + 1, nUniqueCols, globalIndexList);
539  // if this column is present (should always be true?) process the row
540  if (kLast >= 0)
541  {
542  // get the local column type
543  label localVal = localColumnStat[kLast];
544  /* If this is a global column, add the row and move to the next
545  row, otherwise check the next column in the row */
546  if (localVal == 1)
547  {
548  localRowList[idx] = 1;
549  break;
550  }
551  else
552  {
553  localRowList[idx] = 0;
554  }
555  }
556  else
557  {
558  // if this column wasn't found, move to the next column
559  localRowList[idx] = 0;
560  }
561  }
562  }
563  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
564  }
565 
566  // now that we know the set of global rows, complete the coloring
567 
568  // Loop over the maximum number of colors
569  for (label n = 0; n < maxColors; n++)
570  {
571  if (n % printInterval == 0)
572  {
573  Info << "Global ColorSweep: " << n << " " << mesh_.time().elapsedClockTime() << " s" << endl;
574  }
575 
576  // Retrieve the local portion of the color vector
577  // and set all entries that are currently -1 to the current color
578  PetscScalar* colColor;
579  VecGetArray(colors, &colColor);
580 
581  for (label i = colorStart; i < colorEnd; i++)
582  {
583  label idx = i - colorStart;
584  if (DAUtility::isValueCloseToRef(colColor[idx], -1.0))
585  {
586  colColor[idx] = n;
587  }
588  }
589  VecRestoreArray(colors, &colColor);
590 
591  /* We will do the confilct resolution in two passes. On the first pass
592  we will keep the value with the smallest random index on the local
593  column set. We will not touch the off processor columns. On the second
594  pass we will keep the value with the smallest random index, regardless
595  of processor. This is to prevent deadlocks in the conflict resolution.*/
596  for (label conPass = 0; conPass < 2; conPass++)
597  {
598 
599  // Scatter the global colors to each processor
600  VecScatterBegin(colorScatter, colors, colorsLocal, INSERT_VALUES, SCATTER_FORWARD);
601  VecScatterEnd(colorScatter, colors, colorsLocal, INSERT_VALUES, SCATTER_FORWARD);
602 
603  // compute the number of local rows
604  //int nRows = Iend_-Istart_;
605 
606  //Allocate a Scalar array to recieve colColors.
607  PetscScalar* colColorLocal;
608  VecGetArray(colorsLocal, &colColorLocal);
609  VecGetArray(colors, &colColor);
610 
611  // set the iteration limits based on conPass
612  label start, end;
613  if (conPass == 0)
614  {
615  start = colorStart;
616  end = colorEnd;
617  }
618  else
619  {
620  start = 0;
621  end = nColG;
622  }
623 
624  //Now loop over the rows and resolve conflicts
625  for (label i = Istart; i < Iend; i++)
626  {
627  label idx = i - Istart;
628  if (localRowList[idx] == 1) //this row includes at least 1 global col.
629  {
630  /* Get the connectivity row as well as its index into the
631  local indices. */
632  MatGetRow(conMat, i, &nCols, &cols, &vals);
633  MatGetRow(conIndMat, i, &nCols2, NULL, &vals2);
634 
635  // initialize the sorting variables
636  label smallest = nColG;
637  label idxKeep = -1;
638 
639  //int localColIdx;
640  // set any columns with the current color into conflictCols
641  for (label j = 0; j < nCols; j++)
642  {
643  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
644  {
645  label colIdx = cols[j];
646  label localColIdx = round(vals2[j]);
647 
648  // check if the color in this column is from the
649  // current set
650  if (DAUtility::isValueCloseToRef(colColorLocal[localColIdx], n * 1.0))
651  {
652  /* This matches the current color, so set as a
653  potential conflict */
654  conflictCols[j] = colIdx;
655  conflictLocalColIdx[j] = localColIdx;
656  /* this is one of the conflicting columns.
657  If this is a strictly local column, keep it.
658  Otherwise, compare its random number to the
659  current smallest one, keep the smaller one and
660  its index find the index of the smallest
661  tiebreaker. On the first pass this is only
662  for the the local columns. On pass two it is
663  for all columns.*/
664  if (localColumnStat[localColIdx] == 2)
665  {
666  smallest = -1;
667  idxKeep = colIdx;
668  }
669  else if (tbkrLocal[localColIdx] < smallest and colIdx >= start and colIdx < end)
670  {
671  smallest = tbkrLocal[localColIdx];
672  idxKeep = cols[j];
673  }
674  }
675  }
676  }
677 
678  // Now reset all the conflicting rows
679  for (label j = 0; j < nCols; j++)
680  {
681  label colIdx = conflictCols[j];
682  label localColIdx = conflictLocalColIdx[j];
683  // check that the column is in the range for this conPass.
684  if (colIdx >= start && colIdx < end)
685  {
686  /*this column is local. If this isn't the
687  smallest, reset it.*/
688  if (colIdx != idxKeep)
689  {
690  if (localColIdx >= 0)
691  {
692  if (localColumnStat[localColIdx] == 2)
693  {
694  Pout << "local Array Index: " << colIdx << endl;
695  Info << "Error, setting a local column!" << endl;
696  return;
697  }
698  PetscScalar valIn = -1;
699  VecSetValue(colors, colIdx, valIn, INSERT_VALUES);
700  colColorLocal[localColIdx] = -1;
701  }
702  }
703  }
704  }
705 
706  /* reset any columns that have been changed in conflictCols
707  and conflictLocalColIdx */
708  for (label j = 0; j < nCols; j++)
709  {
710  if (!DAUtility::isValueCloseToRef(vals[j], 0.0))
711  {
712  //reset all values related to this row in conflictCols
713  conflictCols[j] = -1;
714  conflictLocalColIdx[j] = -1;
715  }
716  }
717 
718  // Restore the row information
719  MatRestoreRow(conIndMat, i, &nCols2, NULL, &vals2);
720  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
721  }
722  }
723 
724  VecRestoreArray(colors, &colColor);
725  VecRestoreArray(colorsLocal, &colColorLocal);
726  VecAssemblyBegin(colors);
727  VecAssemblyEnd(colors);
728  }
729 
730  //check the coloring for completeness
731  label colorCounter = 0;
732  this->coloringComplete(colors, colorCounter, notColored);
733  if (n % printInterval == 0)
734  {
735  Info << "Number of Uncolored: " << colorCounter << " " << notColored << endl;
736  }
737  if (notColored == 0)
738  {
739  Info << "Global ColorSweep: " << n << " " << mesh_.time().elapsedClockTime() << " s" << endl;
740  Info << "Number of Uncolored: " << colorCounter << " " << notColored << endl;
741  break;
742  }
743  }
744  VecRestoreArray(globalTiebreaker, &tbkrGlobal);
745  VecRestoreArray(globalColumnStat, &globalStat);
746 
747  // count the current colors and aggregate
748  currColor = 0;
749  PetscScalar color;
750  for (label i = colorStart; i < colorEnd; i++)
751  {
752  VecGetValues(colors, 1, &i, &color);
753  //Pout<<"Color: "<<i<<" "<<color<<endl;
754  if (color > currColor)
755  {
756  currColor = color;
757  }
758  }
759 
760  reduce(currColor, maxOp<label>());
761 
762  nColors = currColor + 1;
763 
764  Info << "Ncolors: " << nColors << endl;
765 
766  //check the initial coloring for completeness
767  //this->coloringComplete(colors, colorCounter, notColored);
768 
769  // clean up the unused memory
770  VecRestoreArray(localTiebreaker, &tbkrLocal);
771  delete[] conflictCols;
772  delete[] conflictLocalColIdx;
773  delete[] globalIndexList;
774  delete[] localColumnStat;
775  ISDestroy(&globalIS);
776  VecScatterDestroy(&colorScatter);
777  VecDestroy(&colorsLocal);
778  VecDestroy(&globalTiebreaker);
779  VecDestroy(&globalColumnStat);
780  VecDestroy(&localTiebreaker);
781  delete[] localRowList;
782  VecDestroy(&globalVec);
783  MatDestroy(&conIndMat);
784 }
785 
787  const Mat conMat,
788  label& maxCols,
789  scalar& allNonZeros) const
790 {
791  /*
792  Description:
793  Get the max nonzeros per row, and all the nonzeros for this matrix
794  This will be used in computing coloring
795 
796  Input:
797  conMat: the matrix to compute nonzeros
798 
799  Output:
800  maxCols: max nonzeros per row among all rows
801 
802  allNonZeros: all non zero elements in conMat
803  */
804 
805  PetscInt nCols;
806  const PetscInt* cols;
807  const PetscScalar* vals;
808 
809  label Istart, Iend;
810 
811  // set the counter
812  maxCols = 0;
813  allNonZeros = 0.0;
814 
815  // Determine which rows are on the current processor
816  MatGetOwnershipRange(conMat, &Istart, &Iend);
817 
818  // loop over the matrix and find the largest number of cols
819  for (label i = Istart; i < Iend; i++)
820  {
821  MatGetRow(conMat, i, &nCols, &cols, &vals);
822  if (nCols < 0)
823  {
824  std::cout << "Warning! procI: " << Pstream::myProcNo() << " nCols <0 at rowI: " << i << std::endl;
825  std::cout << "Set nCols to zero " << std::endl;
826  nCols = 0;
827  }
828  if (nCols > maxCols) // perhaps actually check vals?
829  {
830  maxCols = nCols;
831  }
832  allNonZeros += nCols;
833  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
834  }
835 
836  //reduce the maxcols value so that all procs have the same size
837  reduce(maxCols, maxOp<label>());
838 
839  reduce(allNonZeros, sumOp<scalar>());
840 
841  return;
842 }
843 
845  const label target,
846  const label start,
847  const label size,
848  const label* valArray) const
849 {
850  /*
851  Description:
852  Find the index of a value in an array
853 
854  Input:
855  target: the target value to find
856 
857  start: the start index in valArray
858 
859  size: the size of valArray array
860 
861  valArray: the array to check the target value
862 
863  Output:
864  k: the index of the value in the array, if the value is
865  not found, return -1
866  */
867 
868  // loop over the valArray from start until target is found
869  for (label k = start; k < size; k++)
870  {
871  if (valArray[k] == target)
872  {
873  //Info<<"Start: "<<start<<" "<<k<<endl;
874  //this is the k of interest
875  return k;
876  }
877  }
878  return -1;
879 }
880 
882  const Vec colors,
883  label& colorCounter,
884  label& notColored) const
885 {
886  /*
887  Description:
888  Check if the coloring process is finished and return
889  the number of uncolored columns
890 
891  Input:
892  colors: the current coloring vector
893 
894  Output:
895  notColored: the number of uncolored columns
896 
897  */
898 
899  PetscScalar color;
900  PetscInt colorStart, colorEnd;
901 
902  notColored = 0;
903  // get the range of colors owned by the local prock
904  VecGetOwnershipRange(colors, &colorStart, &colorEnd);
905  //loop over the columns and check if there are any uncolored rows
906  const PetscScalar* colColor;
907  VecGetArrayRead(colors, &colColor);
908  colorCounter = 0;
909  for (label i = colorStart; i < colorEnd; i++)
910  {
911  color = colColor[i - colorStart];
912  //VecGetValues(colors,1,&i,&color);
913  if (not(color >= 0))
914  {
915  // this columns not colored and coloring is not complete
916  //Pout<<"coloring incomplete...: "<<color<<" "<<i<<endl;
917  //VecView(colors,PETSC_VIEWER_STDOUT_WORLD);
918  notColored = 1;
919  colorCounter++;
920  //break;
921  }
922  }
923  VecRestoreArrayRead(colors, &colColor);
924  // reduce the logical so that we know that all of the processors are
925  // ok
926  //Pout<<"local number of uncolored: "<<colorCounter<<" "<<notColored<<endl;
927  reduce(notColored, sumOp<label>());
928  reduce(colorCounter, sumOp<label>());
929 }
930 
932  Mat conMat,
933  Vec colors) const
934 {
935  /*
936  Description:
937  Loop over the rows and verify that no row has two columns with the same color
938 
939  Input:
940  conMat: connectivity mat for check coloring
941 
942  colors: the coloring vector
943 
944  Example:
945  If the conMat reads, its coloring for each column can be
946 
947  color0 color1
948  | |
949  1 0 0 0
950  conMat = 0 1 1 0
951  0 0 1 0
952  0 0 0 1
953  | |
954  color0 color0
955 
956  Then, if colors = {0, 0, 1, 0}-> no coloring conflict
957  if colors = {0, 1, 0, 0}-> coloring conclict
958  */
959 
960  Info << "Validating Coloring..." << endl;
961 
962  PetscInt nCols;
963  const PetscInt* cols;
964  const PetscScalar* vals;
965 
966  label Istart, Iend;
967 
968  // scatter colors to local array for all procs
969  Vec vout;
970  VecScatter ctx;
971  VecScatterCreateToAll(colors, &ctx, &vout);
972  VecScatterBegin(ctx, colors, vout, INSERT_VALUES, SCATTER_FORWARD);
973  VecScatterEnd(ctx, colors, vout, INSERT_VALUES, SCATTER_FORWARD);
974 
975  PetscScalar* colorsArray;
976  VecGetArray(vout, &colorsArray);
977 
978  // Determine which rows are on the current processor
979  MatGetOwnershipRange(conMat, &Istart, &Iend);
980 
981  // first calc the largest nCols in conMat
982  label colMax = 0;
983  for (label i = Istart; i < Iend; i++)
984  {
985  MatGetRow(conMat, i, &nCols, &cols, &vals);
986  if (nCols > colMax)
987  {
988  colMax = nCols;
989  }
990  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
991  }
992 
993  // now check if conMat has conflicting rows
994  labelList rowColors(colMax);
995  for (label i = Istart; i < Iend; i++)
996  {
997  MatGetRow(conMat, i, &nCols, &cols, &vals);
998 
999  // initialize rowColors with -1
1000  for (label nn = 0; nn < colMax; nn++)
1001  {
1002  rowColors[nn] = -1;
1003  }
1004 
1005  // set rowColors for this row
1006  for (label j = 0; j < nCols; j++)
1007  {
1008  if (DAUtility::isValueCloseToRef(vals[j], 1.0))
1009  {
1010  rowColors[j] = round(colorsArray[cols[j]]);
1011  }
1012  }
1013 
1014  // check if rowColors has duplicated colors
1015  for (label nn = 0; nn < nCols; nn++)
1016  {
1017  for (label mm = nn + 1; mm < nCols; mm++)
1018  {
1019  if (rowColors[nn] != -1 && rowColors[nn] == rowColors[mm])
1020  {
1021  FatalErrorIn("Conflicting Colors Found!")
1022  << " row: " << i << " col1: " << cols[nn] << " col2: " << cols[mm]
1023  << " color: " << rowColors[nn] << abort(FatalError);
1024  }
1025  }
1026  }
1027 
1028  MatRestoreRow(conMat, i, &nCols, &cols, &vals);
1029  }
1030 
1031  VecRestoreArray(vout, &colorsArray);
1032  VecScatterDestroy(&ctx);
1033  VecDestroy(&vout);
1034 
1035  Info << "No Conflicting Colors Found!" << endl;
1036 
1037  return;
1038 }
1039 } // End namespace Foam
1040 
1041 // ************************************************************************* //
Foam::DAColoring::daIndex_
const DAIndex & daIndex_
DAIndex object.
Definition: DAColoring.H:51
Foam::DAColoring::daOption_
const DAOption & daOption_
DAOption object.
Definition: DAColoring.H:48
Foam::DAColoring::find_index
label find_index(const label target, const label start, const label size, const label *valArray) const
find the index of a prescribed value in an array
Definition: DAColoring.C:844
Foam::DAOption
Definition: DAOption.H:29
Foam::DAColoring::mesh_
const fvMesh & mesh_
fvMesh object
Definition: DAColoring.H:45
daOption
DAOption daOption(mesh, pyOptions_)
Foam::DAColoring::validateColoring
void validateColoring(Mat conMat, Vec colors) const
validate if there is coloring conflict
Definition: DAColoring.C:931
Foam::DAColoring::parallelD2Coloring
void parallelD2Coloring(const Mat conMat, Vec colors, label &nColors) const
a parallel distance-2 graph coloring function
Definition: DAColoring.C:32
Foam::DAColoring::getMatNonZeros
void getMatNonZeros(const Mat conMat, label &maxCols, scalar &allNonZeros) const
number of non-zero elements in a matrix
Definition: DAColoring.C:786
Foam::DAOption::getOption
classType getOption(const word key) const
get an option from subDict and key
Definition: DAOption.H:92
DAColoring.H
Foam::DAColoring::coloringComplete
void coloringComplete(const Vec colors, label &colorCounter, label &notColored) const
check if there is non-colored columns
Definition: DAColoring.C:881
Foam::DAUtility::isValueCloseToRef
static label isValueCloseToRef(const scalar val, const scalar refVal, const scalar tol=1.0e-6)
check whether a value is close to a reference value by a tolerance
Definition: DAUtility.C:651
mesh
fvMesh & mesh
Definition: createRefsHeatTransfer.H:4
Foam::DAIndex
Definition: DAIndex.H:32
dafoam_plot3dtransform.vals
vals
Definition: dafoam_plot3dtransform.py:39
Foam::DAModel
Definition: DAModel.H:59
k
dimensionedScalar & k
Definition: createRefsHeatTransfer.H:6
Foam
Definition: multiFreqScalarFvPatchField.C:144
daModel
DAModel daModel(mesh, daOption)
daIndex
DAIndex daIndex(mesh, daOption, daModel)
Foam::DAIndex::nGlobalAdjointStates
label nGlobalAdjointStates
number of global adjoint states (including all cells and faces)
Definition: DAIndex.H:148
Foam::DAIndex::nLocalAdjointStates
label nLocalAdjointStates
number of local adjoint states (including all cells and faces)
Definition: DAIndex.H:145