1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 By: Francois PELLEGRINI RE: Graph mapping 'strategy' string [ reply ]
27 2008-08-22 10:09 Strategy handling in Scotch is a bit tricky. In order
28 not to be confused, you must have a clear view of how they are built.
31 1- Strategies are made up of "methods" which are combined by means of
34 2- A method is of the form "m{param=value,param=value,...}", where "m"
35 is a single character (this is your first error: "f" is a method name,
36 not a parameter name).
38 3- There exist different sort of strategies : bipartitioning strategies,
39 mapping strategies, ordering strategies, which cannot be mixed. For
40 instance, you cannot build a bipartitioning strategy and feed it to a
41 mapping method (this is your second error).
43 To use the "mapCompute" routine, you must create a mapping strategy, not
44 a bipartitioning one, and so use stratGraphMap() and not
45 stratGraphBipart(). Your mapping strategy should however be based on the
46 "recursive bipartitioning" method ("b"). For instance, a simple (and
47 hence not very efficient) mapping strategy can be :
51 which computes mappings with the recursive bipartitioning method "b",
52 this latter using the Fiduccia-Mattheyses method "f" to compute its
55 If you want an exact partition (see your previous post), try
58 However, these strategies are not the most efficient, as they do not
59 make use of the multi-level framework.
61 To use the multi-level framework, try for instance:
63 "b{sep=m{vert=100,low=h,asc=f}x}"
65 The current default mapping strategy in Scotch can be seen by using the
66 "-vs" option of program gmap. It is, to date:
79 bnd=d{pass=40,dif=1,rem=1}f{move=80,pass=-1,bal=0.005},
80 org=f{move=80,pass=-1,bal=0.005},
83 low=h{pass=10}f{move=80,pass=-1,bal=0.0005},
92 bnd=d{pass=40,dif=1,rem=1}f{move=80,pass=-1,bal=0.005},
93 org=f{move=80,pass=-1,bal=0.005},
96 low=h{pass=10}f{move=80,pass=-1,bal=0.0005},
105 \*---------------------------------------------------------------------------*/
107 #include "scotchDecomp.H"
108 #include "addToRunTimeSelectionTable.H"
109 #include "floatScalar.H"
111 #include "cyclicPolyPatch.H"
112 #include "OFstream.H"
120 // Hack: scotch generates floating point errors so need to switch of error
122 #if defined(linux) || defined(linuxAMD64) || defined(linuxIA64)
126 #if defined(LINUX) && defined(__GNUC__)
138 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
142 defineTypeNameAndDebug(scotchDecomp, 0);
144 addToRunTimeSelectionTable
152 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
154 void Foam::scotchDecomp::check(const int retVal, const char* str)
158 FatalErrorIn("scotchDecomp::decompose(..)")
159 << "Call to scotch routine " << str << " failed."
165 // Call scotch with options from dictionary.
166 Foam::label Foam::scotchDecomp::decompose
168 const List<int>& adjncy,
169 const List<int>& xadj,
170 const scalarField& cWeights,
172 List<int>& finalDecomp
176 if (decompositionDict_.found("scotchCoeffs"))
178 const dictionary& scotchCoeffs =
179 decompositionDict_.subDict("scotchCoeffs");
181 if (scotchCoeffs.found("writeGraph"))
183 Switch writeGraph(scotchCoeffs.lookup("writeGraph"));
187 OFstream str(mesh_.time().path() / mesh_.name() + ".grf");
189 Info<< "Dumping Scotch graph file to " << str.name() << endl
190 << "Use this in combination with gpart." << endl;
193 str << version << nl;
195 str << xadj.size()-1 << ' ' << adjncy.size() << nl;
196 // Numbering starts from 0
199 label hasEdgeWeights = 0;
200 label hasVertexWeights = 0;
201 label numericflag = 10*hasEdgeWeights+hasVertexWeights;
202 str << baseval << ' ' << numericflag << nl;
203 for (label cellI = 0; cellI < xadj.size()-1; cellI++)
205 label start = xadj[cellI];
206 label end = xadj[cellI+1];
209 for (label i = start; i < end; i++)
211 str << ' ' << adjncy[i];
224 SCOTCH_Strat stradat;
225 check(SCOTCH_stratInit(&stradat), "SCOTCH_stratInit");
227 if (decompositionDict_.found("scotchCoeffs"))
229 const dictionary& scotchCoeffs =
230 decompositionDict_.subDict("scotchCoeffs");
234 if (scotchCoeffs.readIfPresent("strategy", strategy))
238 Info<< "scotchDecomp : Using strategy " << strategy << endl;
240 SCOTCH_stratGraphMap(&stradat, strategy.c_str());
241 //fprintf(stdout, "S\tStrat=");
242 //SCOTCH_stratSave(&stradat, stdout);
243 //fprintf(stdout, "\n");
254 // Check for externally provided cellweights and if so initialise weights
255 scalar minWeights = gMin(cWeights);
256 if (cWeights.size() > 0)
262 "scotchDecomp::decompose"
263 "(const pointField&, const scalarField&)"
264 ) << "Illegal minimum weight " << minWeights
268 if (cWeights.size() != xadj.size()-1)
272 "scotchDecomp::decompose"
273 "(const pointField&, const scalarField&)"
274 ) << "Number of cell weights " << cWeights.size()
275 << " does not equal number of cells " << xadj.size()-1
279 // Convert to integers.
280 velotab.setSize(cWeights.size());
283 velotab[i] = int(cWeights[i]/minWeights);
289 SCOTCH_Graph grafdat;
290 check(SCOTCH_graphInit(&grafdat), "SCOTCH_graphInit");
296 0, // baseval, c-style numbering
297 xadj.size()-1, // vertnbr, nCells
298 xadj.begin(), // verttab, start index per cell into adjncy
299 &xadj[1], // vendtab, end index ,,
300 velotab.begin(), // velotab, vertex weights
302 adjncy.size(), // edgenbr, number of arcs
303 adjncy.begin(), // edgetab
304 NULL // edlotab, edge weights
308 check(SCOTCH_graphCheck(&grafdat), "SCOTCH_graphCheck");
313 // (fully connected network topology since using switch)
316 check(SCOTCH_archInit(&archdat), "SCOTCH_archInit");
318 List<label> processorWeights;
319 if (decompositionDict_.found("scotchCoeffs"))
321 const dictionary& scotchCoeffs =
322 decompositionDict_.subDict("scotchCoeffs");
324 scotchCoeffs.readIfPresent("processorWeights", processorWeights);
326 if (processorWeights.size())
330 Info<< "scotchDecomp : Using procesor weights " << processorWeights
335 SCOTCH_archCmpltw(&archdat, nProcessors_, processorWeights.begin()),
343 SCOTCH_archCmplt(&archdat, nProcessors_),
349 //SCOTCH_Mapping mapdat;
350 //SCOTCH_graphMapInit(&grafdat, &mapdat, &archdat, NULL);
351 //SCOTCH_graphMapCompute(&grafdat, &mapdat, &stradat); /* Perform mapping */
352 //SCOTCH_graphMapExit(&grafdat, &mapdat);
355 // Hack:switch off fpu error trapping
357 int oldExcepts = fedisableexcept
365 finalDecomp.setSize(xadj.size()-1);
373 &stradat, // const SCOTCH_Strat *
374 finalDecomp.begin() // parttab
380 feenableexcept(oldExcepts);
385 //finalDecomp.setSize(xadj.size()-1);
391 // nProcessors_, // partnbr
392 // &stradat, // const SCOTCH_Strat *
393 // finalDecomp.begin() // parttab
395 // "SCOTCH_graphPart"
398 // Release storage for graph
399 SCOTCH_graphExit(&grafdat);
400 // Release storage for strategy
401 SCOTCH_stratExit(&stradat);
402 // Release storage for network topology
403 SCOTCH_archExit(&archdat);
409 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
411 Foam::scotchDecomp::scotchDecomp
413 const dictionary& decompositionDict,
417 decompositionMethod(decompositionDict),
422 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
424 Foam::labelList Foam::scotchDecomp::decompose
426 const pointField& points,
427 const scalarField& pointWeights
430 if (points.size() != mesh_.nCells())
434 "scotchDecomp::decompose(const pointField&, const scalarField&)"
436 << "Can use this decomposition method only for the whole mesh"
438 << "and supply one coordinate (cellCentre) for every cell." << endl
439 << "The number of coordinates " << points.size() << endl
440 << "The number of cells in the mesh " << mesh_.nCells()
444 // Make Metis CSR (Compressed Storage Format) storage
445 // adjncy : contains neighbours (= edges in graph)
446 // xadj(celli) : start of information in adjncy for celli
449 calcCSR(mesh_, adjncy, xadj);
451 // Decompose using default weights
452 List<int> finalDecomp;
453 decompose(adjncy, xadj, pointWeights, finalDecomp);
455 // Copy back to labelList
456 labelList decomp(finalDecomp.size());
459 decomp[i] = finalDecomp[i];
465 Foam::labelList Foam::scotchDecomp::decompose
467 const labelList& agglom,
468 const pointField& agglomPoints,
469 const scalarField& pointWeights
472 if (agglom.size() != mesh_.nCells())
476 "parMetisDecomp::decompose(const labelList&, const pointField&)"
477 ) << "Size of cell-to-coarse map " << agglom.size()
478 << " differs from number of cells in mesh " << mesh_.nCells()
482 // Make Metis CSR (Compressed Storage Format) storage
483 // adjncy : contains neighbours (= edges in graph)
484 // xadj(celli) : start of information in adjncy for celli
488 // Get cellCells on coarse mesh.
489 labelListList cellCells;
498 calcCSR(cellCells, adjncy, xadj);
501 // Decompose using weights
502 List<int> finalDecomp;
503 decompose(adjncy, xadj, pointWeights, finalDecomp);
505 // Rework back into decomposition for original mesh_
506 labelList fineDistribution(agglom.size());
508 forAll(fineDistribution, i)
510 fineDistribution[i] = finalDecomp[agglom[i]];
513 return fineDistribution;
517 Foam::labelList Foam::scotchDecomp::decompose
519 const labelListList& globalCellCells,
520 const pointField& cellCentres,
521 const scalarField& cWeights
524 if (cellCentres.size() != globalCellCells.size())
528 "scotchDecomp::decompose"
529 "(const labelListList&, const pointField&, const scalarField&)"
530 ) << "Inconsistent number of cells (" << globalCellCells.size()
531 << ") and number of cell centres (" << cellCentres.size()
532 << ")." << exit(FatalError);
536 // Make Metis CSR (Compressed Storage Format) storage
537 // adjncy : contains neighbours (= edges in graph)
538 // xadj(celli) : start of information in adjncy for celli
542 calcCSR(globalCellCells, adjncy, xadj);
544 // Decompose using weights
545 List<int> finalDecomp;
546 decompose(adjncy, xadj, cWeights, finalDecomp);
548 // Copy back to labelList
549 labelList decomp(finalDecomp.size());
552 decomp[i] = finalDecomp[i];
558 void Foam::scotchDecomp::calcCSR
560 const polyMesh& mesh,
565 // Make Metis CSR (Compressed Storage Format) storage
566 // adjncy : contains neighbours (= edges in graph)
567 // xadj(celli) : start of information in adjncy for celli
569 xadj.setSize(mesh.nCells()+1);
571 // Initialise the number of internal faces of the cells to twice the
572 // number of internal faces
573 label nInternalFaces = 2*mesh.nInternalFaces();
575 // Check the boundary for coupled patches and add to the number of
577 const polyBoundaryMesh& pbm = mesh.boundaryMesh();
581 if (isA<cyclicPolyPatch>(pbm[patchi]))
583 nInternalFaces += pbm[patchi].size();
587 // Create the adjncy array the size of the total number of internal and
589 adjncy.setSize(nInternalFaces);
595 for (label cellI = 0; cellI < mesh.nCells(); cellI++)
597 xadj[cellI] = freeAdj;
599 const labelList& cFaces = mesh.cells()[cellI];
603 label faceI = cFaces[i];
607 mesh.isInternalFace(faceI)
608 || isA<cyclicPolyPatch>(pbm[pbm.whichPatch(faceI)])
615 xadj[mesh.nCells()] = freeAdj;
621 labelList nFacesPerCell(mesh.nCells(), 0);
624 for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
626 label own = mesh.faceOwner()[faceI];
627 label nei = mesh.faceNeighbour()[faceI];
629 adjncy[xadj[own] + nFacesPerCell[own]++] = nei;
630 adjncy[xadj[nei] + nFacesPerCell[nei]++] = own;
633 // Coupled faces. Only cyclics done.
636 if (isA<cyclicPolyPatch>(pbm[patchi]))
638 const unallocLabelList& faceCells = pbm[patchi].faceCells();
640 label sizeby2 = faceCells.size()/2;
642 for (label facei=0; facei<sizeby2; facei++)
644 label own = faceCells[facei];
645 label nei = faceCells[facei + sizeby2];
647 adjncy[xadj[own] + nFacesPerCell[own]++] = nei;
648 adjncy[xadj[nei] + nFacesPerCell[nei]++] = own;
655 // From cell-cell connections to Metis format (like CompactListList)
656 void Foam::scotchDecomp::calcCSR
658 const labelListList& cellCells,
663 // Count number of internal faces
664 label nConnections = 0;
666 forAll(cellCells, coarseI)
668 nConnections += cellCells[coarseI].size();
671 // Create the adjncy array as twice the size of the total number of
673 adjncy.setSize(nConnections);
675 xadj.setSize(cellCells.size()+1);
682 forAll(cellCells, coarseI)
684 xadj[coarseI] = freeAdj;
686 const labelList& cCells = cellCells[coarseI];
690 adjncy[freeAdj++] = cCells[i];
693 xadj[cellCells.size()] = freeAdj;
698 // ************************************************************************* //