OpenFOAM logo
The Open Source CFD Toolbox
  Source Guide OpenCFD Solutions Contact OpenFOAM

distributedTriSurfaceMesh.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software; you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by the
00013     Free Software Foundation; either version 2 of the License, or (at your
00014     option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM; if not, write to the Free Software Foundation,
00023     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00024 
00025 \*---------------------------------------------------------------------------*/
00026 
00027 #include "distributedTriSurfaceMesh.H"
00028 #include "mapDistribute.H"
00029 #include "Random.H"
00030 #include "addToRunTimeSelectionTable.H"
00031 #include "triangleFuncs.H"
00032 #include "matchPoints.H"
00033 #include "globalIndex.H"
00034 #include "Time.H"
00035 
00036 #include "IFstream.H"
00037 #include "decompositionMethod.H"
00038 #include "vectorList.H"
00039 
00040 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00041 
00042 namespace Foam
00043 {
00044 
00045 defineTypeNameAndDebug(distributedTriSurfaceMesh, 0);
00046 addToRunTimeSelectionTable(searchableSurface, distributedTriSurfaceMesh, dict);
00047 
00048 }
00049 
00050 
00051 template<>
00052 const char*
00053 Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>::names[] =
00054 {
00055     "follow",
00056     "independent",
00057     "frozen"
00058 };
00059 
00060 const Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>
00061     Foam::distributedTriSurfaceMesh::distributionTypeNames_;
00062 
00063 
00064 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00065 
00066 // Read my additional data from the dictionary
00067 bool Foam::distributedTriSurfaceMesh::read()
00068 {
00069     // Get bb of all domains.
00070     procBb_.setSize(Pstream::nProcs());
00071 
00072     procBb_[Pstream::myProcNo()] = List<treeBoundBox>(dict_.lookup("bounds"));
00073     Pstream::gatherList(procBb_);
00074     Pstream::scatterList(procBb_);
00075 
00076     // Distribution type
00077     distType_ = distributionTypeNames_.read(dict_.lookup("distributionType"));
00078 
00079     // Merge distance
00080     mergeDist_ = readScalar(dict_.lookup("mergeDistance"));
00081 
00082     return true;
00083 }
00084 
00085 
00086 // Is segment fully local?
00087 bool Foam::distributedTriSurfaceMesh::isLocal
00088 (
00089     const List<treeBoundBox>& myBbs,
00090     const point& start,
00091     const point& end
00092 )
00093 {
00094     forAll(myBbs, bbI)
00095     {
00096         if (myBbs[bbI].contains(start) && myBbs[bbI].contains(end))
00097         {
00098             return true;
00099         }
00100     }
00101     return false;
00102 }
00103 
00104 
00105 //void Foam::distributedTriSurfaceMesh::splitSegment
00106 //(
00107 //    const label segmentI,
00108 //    const point& start,
00109 //    const point& end,
00110 //    const treeBoundBox& bb,
00111 //
00112 //    DynamicList<segment>& allSegments,
00113 //    DynamicList<label>& allSegmentMap,
00114 //    DynamicList<label> sendMap
00115 //) const
00116 //{
00117 //    // Work points
00118 //    point clipPt0, clipPt1;
00119 //
00120 //    if (bb.contains(start))
00121 //    {
00122 //        // start within, trim end to bb
00123 //        bool clipped = bb.intersects(end, start, clipPt0);
00124 //
00125 //        if (clipped)
00126 //        {
00127 //            // segment from start to clippedStart passes
00128 //            // through proc.
00129 //            sendMap[procI].append(allSegments.size());
00130 //            allSegmentMap.append(segmentI);
00131 //            allSegments.append(segment(start, clipPt0));
00132 //        }
00133 //    }
00134 //    else if (bb.contains(end))
00135 //    {
00136 //        // end within, trim start to bb
00137 //        bool clipped = bb.intersects(start, end, clipPt0);
00138 //
00139 //        if (clipped)
00140 //        {
00141 //            sendMap[procI].append(allSegments.size());
00142 //            allSegmentMap.append(segmentI);
00143 //            allSegments.append(segment(clipPt0, end));
00144 //        }
00145 //    }
00146 //    else
00147 //    {
00148 //        // trim both
00149 //        bool clippedStart = bb.intersects(start, end, clipPt0);
00150 //
00151 //        if (clippedStart)
00152 //        {
00153 //            bool clippedEnd = bb.intersects(end, clipPt0, clipPt1);
00154 //
00155 //            if (clippedEnd)
00156 //            {
00157 //                // middle part of segment passes through proc.
00158 //                sendMap[procI].append(allSegments.size());
00159 //                allSegmentMap.append(segmentI);
00160 //                allSegments.append(segment(clipPt0, clipPt1));
00161 //            }
00162 //        }
00163 //    }
00164 //}
00165 
00166 
00167 void Foam::distributedTriSurfaceMesh::distributeSegment
00168 (
00169     const label segmentI,
00170     const point& start,
00171     const point& end,
00172 
00173     DynamicList<segment>& allSegments,
00174     DynamicList<label>& allSegmentMap,
00175     List<DynamicList<label> >& sendMap
00176 ) const
00177 {
00178     // Work points
00179     point clipPt;
00180 
00181 
00182     // 1. Fully local already handled outside. Note: retest is cheap.
00183     if (isLocal(procBb_[Pstream::myProcNo()], start, end))
00184     {
00185         return;
00186     }
00187 
00188 
00189     // 2. If fully inside one other processor, then only need to send
00190     // to that one processor even if it intersects another. Rare occurrence
00191     // but cheap to test.
00192     forAll(procBb_, procI)
00193     {
00194         if (procI != Pstream::myProcNo())
00195         {
00196             const List<treeBoundBox>& bbs = procBb_[procI];
00197 
00198             if (isLocal(bbs, start, end))
00199             {
00200                 sendMap[procI].append(allSegments.size());
00201                 allSegmentMap.append(segmentI);
00202                 allSegments.append(segment(start, end));
00203                 return;
00204             }
00205         }
00206     }
00207 
00208 
00209     // 3. If not contained in single processor send to all intersecting
00210     // processors.
00211     forAll(procBb_, procI)
00212     {
00213         const List<treeBoundBox>& bbs = procBb_[procI];
00214 
00215         forAll(bbs, bbI)
00216         {
00217             const treeBoundBox& bb = bbs[bbI];
00218 
00219             // Scheme a: any processor that intersects the segment gets
00220             // the segment.
00221 
00222             if (bb.intersects(start, end, clipPt))
00223             {
00224                 sendMap[procI].append(allSegments.size());
00225                 allSegmentMap.append(segmentI);
00226                 allSegments.append(segment(start, end));
00227             }
00228 
00229             // Alternative: any processor only gets clipped bit of
00230             // segment. This gives small problems with additional
00231             // truncation errors.
00232             //splitSegment
00233             //(
00234             //    segmentI,
00235             //    start,
00236             //    end,
00237             //    bb,
00238             //
00239             //    allSegments,
00240             //    allSegmentMap,
00241             //   sendMap[procI]
00242             //);
00243         }
00244     }
00245 }
00246 
00247 
00248 Foam::autoPtr<Foam::mapDistribute>
00249 Foam::distributedTriSurfaceMesh::distributeSegments
00250 (
00251     const pointField& start,
00252     const pointField& end,
00253 
00254     List<segment>& allSegments,
00255     labelList& allSegmentMap
00256 ) const
00257 {
00258     // Determine send map
00259     // ~~~~~~~~~~~~~~~~~~
00260 
00261     labelListList sendMap(Pstream::nProcs());
00262 
00263     {
00264         // Since intersection test is quite expensive compared to memory
00265         // allocation we use DynamicList to immediately store the segment
00266         // in the correct bin.
00267 
00268         // Segments to test
00269         DynamicList<segment> dynAllSegments(start.size());
00270         // Original index of segment
00271         DynamicList<label> dynAllSegmentMap(start.size());
00272         // Per processor indices into allSegments to send
00273         List<DynamicList<label> > dynSendMap(Pstream::nProcs());
00274 
00275         forAll(start, segmentI)
00276         {
00277             distributeSegment
00278             (
00279                 segmentI,
00280                 start[segmentI],
00281                 end[segmentI],
00282 
00283                 dynAllSegments,
00284                 dynAllSegmentMap,
00285                 dynSendMap
00286             );
00287         }
00288 
00289         // Convert dynamicList to labelList
00290         sendMap.setSize(Pstream::nProcs());
00291         forAll(sendMap, procI)
00292         {
00293             dynSendMap[procI].shrink();
00294             sendMap[procI].transfer(dynSendMap[procI]);
00295         }
00296 
00297         allSegments.transfer(dynAllSegments.shrink());
00298         allSegmentMap.transfer(dynAllSegmentMap.shrink());
00299     }
00300 
00301 
00302     // Send over how many I need to receive.
00303     labelListList sendSizes(Pstream::nProcs());
00304     sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
00305     forAll(sendMap, procI)
00306     {
00307         sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
00308     }
00309     Pstream::gatherList(sendSizes);
00310     Pstream::scatterList(sendSizes);
00311 
00312 
00313     // Determine order of receiving
00314     labelListList constructMap(Pstream::nProcs());
00315 
00316     // My local segments first
00317     constructMap[Pstream::myProcNo()] = identity
00318     (
00319         sendMap[Pstream::myProcNo()].size()
00320     );
00321 
00322     label segmentI = constructMap[Pstream::myProcNo()].size();
00323     forAll(constructMap, procI)
00324     {
00325         if (procI != Pstream::myProcNo())
00326         {
00327             // What I need to receive is what other processor is sending to me.
00328             label nRecv = sendSizes[procI][Pstream::myProcNo()];
00329             constructMap[procI].setSize(nRecv);
00330 
00331             for (label i = 0; i < nRecv; i++)
00332             {
00333                 constructMap[procI][i] = segmentI++;
00334             }
00335         }
00336     }
00337 
00338     return autoPtr<mapDistribute>
00339     (
00340         new mapDistribute
00341         (
00342             segmentI,       // size after construction
00343             sendMap,
00344             constructMap,
00345             true            // reuse storage
00346         )
00347     );
00348 }
00349 
00350 
00351 void Foam::distributedTriSurfaceMesh::findLine
00352 (
00353     const bool nearestIntersection,
00354     const pointField& start,
00355     const pointField& end,
00356     List<pointIndexHit>& info
00357 ) const
00358 {
00359     const indexedOctree<treeDataTriSurface>& octree = tree();
00360 
00361     // Important:force synchronised construction of indexing
00362     const globalIndex& triIndexer = globalTris();
00363 
00364     // Initialise
00365     info.setSize(start.size());
00366     forAll(info, i)
00367     {
00368         info[i].setMiss();
00369     }
00370 
00371 
00372     // Do any local queries
00373     // ~~~~~~~~~~~~~~~~~~~~
00374 
00375     label nLocal = 0;
00376 
00377     forAll(start, i)
00378     {
00379         if (isLocal(procBb_[Pstream::myProcNo()], start[i], end[i]))
00380         {
00381             if (nearestIntersection)
00382             {
00383                 info[i] = octree.findLine(start[i], end[i]);
00384             }
00385             else
00386             {
00387                 info[i] = octree.findLineAny(start[i], end[i]);
00388             }
00389 
00390             if (info[i].hit())
00391             {
00392                 info[i].setIndex(triIndexer.toGlobal(info[i].index()));
00393             }
00394             nLocal++;
00395         }
00396     }
00397 
00398 
00399     if
00400     (
00401         Pstream::parRun()
00402      && (
00403             returnReduce(nLocal, sumOp<label>())
00404           < returnReduce(start.size(), sumOp<label>())
00405         )
00406     )
00407     {
00408         // Not all can be resolved locally. Build segments and map, send over
00409         // segments, do intersections, send back and merge.
00410 
00411 
00412         // Construct queries (segments)
00413         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00414 
00415         // Segments to test
00416         List<segment> allSegments(start.size());
00417         // Original index of segment
00418         labelList allSegmentMap(start.size());
00419 
00420         const autoPtr<mapDistribute> mapPtr
00421         (
00422             distributeSegments
00423             (
00424                 start,
00425                 end,
00426                 allSegments,
00427                 allSegmentMap
00428             )
00429         );
00430         const mapDistribute& map = mapPtr();
00431 
00432         label nOldAllSegments = allSegments.size();
00433 
00434 
00435         // Exchange the segments
00436         // ~~~~~~~~~~~~~~~~~~~~~
00437 
00438         map.distribute
00439         (
00440             Pstream::nonBlocking,   //Pstream::scheduled,
00441             List<labelPair>(0),     //map.schedule(),
00442             map.constructSize(),
00443             map.subMap(),           // what to send
00444             map.constructMap(),     // what to receive
00445             allSegments
00446         );
00447 
00448 
00449         // Do tests I need to do
00450         // ~~~~~~~~~~~~~~~~~~~~~
00451 
00452         // Intersections
00453         List<pointIndexHit> intersections(allSegments.size());
00454 
00455         forAll(allSegments, i)
00456         {
00457             if (nearestIntersection)
00458             {
00459                 intersections[i] = octree.findLine
00460                 (
00461                     allSegments[i].first(),
00462                     allSegments[i].second()
00463                 );
00464             }
00465             else
00466             {
00467                 intersections[i] = octree.findLineAny
00468                 (
00469                     allSegments[i].first(),
00470                     allSegments[i].second()
00471                 );
00472             }
00473 
00474             // Convert triangle index to global numbering
00475             if (intersections[i].hit())
00476             {
00477                 intersections[i].setIndex
00478                 (
00479                     triIndexer.toGlobal(intersections[i].index())
00480                 );
00481             }
00482         }
00483 
00484 
00485         // Exchange the intersections (opposite to segments)
00486         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00487 
00488         map.distribute
00489         (
00490             //Pstream::scheduled,
00491             //map.schedule            // Note reverse schedule
00492             //(
00493             //    map.constructMap(),
00494             //    map.subMap()
00495             //),
00496             Pstream::nonBlocking,
00497             List<labelPair>(0),
00498             nOldAllSegments,
00499             map.constructMap(),     // what to send
00500             map.subMap(),           // what to receive
00501             intersections
00502         );
00503 
00504 
00505         // Extract the hits
00506         // ~~~~~~~~~~~~~~~~
00507 
00508         forAll(intersections, i)
00509         {
00510             const pointIndexHit& allInfo = intersections[i];
00511             label segmentI = allSegmentMap[i];
00512             pointIndexHit& hitInfo = info[segmentI];
00513 
00514             if (allInfo.hit())
00515             {
00516                 if (!hitInfo.hit())
00517                 {
00518                     // No intersection yet so take this one
00519                     hitInfo = allInfo;
00520                 }
00521                 else if (nearestIntersection)
00522                 {
00523                     // Nearest intersection
00524                     if
00525                     (
00526                         magSqr(allInfo.hitPoint()-start[segmentI])
00527                       < magSqr(hitInfo.hitPoint()-start[segmentI])
00528                     )
00529                     {
00530                         hitInfo = allInfo;
00531                     }
00532                 }
00533             }
00534         }
00535     }
00536 }
00537 
00538 
00539 // Exchanges indices to the processor they come from.
00540 // - calculates exchange map
00541 // - uses map to calculate local triangle index
00542 Foam::autoPtr<Foam::mapDistribute>
00543 Foam::distributedTriSurfaceMesh::calcLocalQueries
00544 (
00545     const List<pointIndexHit>& info,
00546     labelList& triangleIndex
00547 ) const
00548 {
00549     triangleIndex.setSize(info.size());
00550 
00551     const globalIndex& triIndexer = globalTris();
00552 
00553 
00554     // Determine send map
00555     // ~~~~~~~~~~~~~~~~~~
00556 
00557     // Since determining which processor the query should go to is
00558     // cheap we do a multi-pass algorithm to save some memory temporarily.
00559 
00560     // 1. Count
00561     labelList nSend(Pstream::nProcs(), 0);
00562 
00563     forAll(info, i)
00564     {
00565         if (info[i].hit())
00566         {
00567             label procI = triIndexer.whichProcID(info[i].index());
00568             nSend[procI]++;
00569         }
00570     }
00571 
00572     // 2. Size sendMap
00573     labelListList sendMap(Pstream::nProcs());
00574     forAll(nSend, procI)
00575     {
00576         sendMap[procI].setSize(nSend[procI]);
00577         nSend[procI] = 0;
00578     }
00579 
00580     // 3. Fill sendMap
00581     forAll(info, i)
00582     {
00583         if (info[i].hit())
00584         {
00585             label procI = triIndexer.whichProcID(info[i].index());
00586             triangleIndex[i] = triIndexer.toLocal(procI, info[i].index());
00587             sendMap[procI][nSend[procI]++] = i;
00588         }
00589         else
00590         {
00591             triangleIndex[i] = -1;
00592         }
00593     }
00594 
00595 
00596     // Send over how many I need to receive
00597     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00598 
00599     labelListList sendSizes(Pstream::nProcs());
00600     sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
00601     forAll(sendMap, procI)
00602     {
00603         sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
00604     }
00605     Pstream::gatherList(sendSizes);
00606     Pstream::scatterList(sendSizes);
00607 
00608 
00609     // Determine receive map
00610     // ~~~~~~~~~~~~~~~~~~~~~
00611 
00612     labelListList constructMap(Pstream::nProcs());
00613 
00614     // My local segments first
00615     constructMap[Pstream::myProcNo()] = identity
00616     (
00617         sendMap[Pstream::myProcNo()].size()
00618     );
00619 
00620     label segmentI = constructMap[Pstream::myProcNo()].size();
00621     forAll(constructMap, procI)
00622     {
00623         if (procI != Pstream::myProcNo())
00624         {
00625             // What I need to receive is what other processor is sending to me.
00626             label nRecv = sendSizes[procI][Pstream::myProcNo()];
00627             constructMap[procI].setSize(nRecv);
00628 
00629             for (label i = 0; i < nRecv; i++)
00630             {
00631                 constructMap[procI][i] = segmentI++;
00632             }
00633         }
00634     }
00635 
00636 
00637     // Pack into distribution map
00638     // ~~~~~~~~~~~~~~~~~~~~~~~~~~
00639 
00640     autoPtr<mapDistribute> mapPtr
00641     (
00642         new mapDistribute
00643         (
00644             segmentI,       // size after construction
00645             sendMap,
00646             constructMap,
00647             true            // reuse storage
00648         )
00649     );
00650     const mapDistribute& map = mapPtr();
00651 
00652 
00653     // Send over queries
00654     // ~~~~~~~~~~~~~~~~~
00655 
00656     map.distribute
00657     (
00658         //Pstream::scheduled,
00659         //map.schedule(),
00660         Pstream::nonBlocking,
00661         List<labelPair>(0),
00662         map.constructSize(),
00663         map.subMap(),           // what to send
00664         map.constructMap(),     // what to receive
00665         triangleIndex
00666     );
00667 
00668 
00669     return mapPtr;
00670 }
00671 
00672 
00673 Foam::label Foam::distributedTriSurfaceMesh::calcOverlappingProcs
00674 (
00675     const point& centre,
00676     const scalar radiusSqr,
00677     boolList& overlaps
00678 ) const
00679 {
00680     overlaps = false;
00681     label nOverlaps = 0;
00682 
00683     forAll(procBb_, procI)
00684     {
00685         const List<treeBoundBox>& bbs = procBb_[procI];
00686 
00687         forAll(bbs, bbI)
00688         {
00689             if (bbs[bbI].overlaps(centre, radiusSqr))
00690             {
00691                 overlaps[procI] = true;
00692                 nOverlaps++;
00693                 break;
00694             }
00695         }
00696     }
00697     return nOverlaps;
00698 }
00699 
00700 
00701 // Generate queries for parallel distance calculation
00702 // - calculates exchange map
00703 // - uses map to exchange points and radius
00704 Foam::autoPtr<Foam::mapDistribute>
00705 Foam::distributedTriSurfaceMesh::calcLocalQueries
00706 (
00707     const pointField& centres,
00708     const scalarField& radiusSqr,
00709 
00710     pointField& allCentres,
00711     scalarField& allRadiusSqr,
00712     labelList& allSegmentMap
00713 ) const
00714 {
00715     // Determine queries
00716     // ~~~~~~~~~~~~~~~~~
00717 
00718     labelListList sendMap(Pstream::nProcs());
00719 
00720     {
00721         // Queries
00722         DynamicList<point> dynAllCentres(centres.size());
00723         DynamicList<scalar> dynAllRadiusSqr(centres.size());
00724         // Original index of segment
00725         DynamicList<label> dynAllSegmentMap(centres.size());
00726         // Per processor indices into allSegments to send
00727         List<DynamicList<label> > dynSendMap(Pstream::nProcs());
00728 
00729         // Work array - whether processor bb overlaps the bounding sphere.
00730         boolList procBbOverlaps(Pstream::nProcs());
00731 
00732         forAll(centres, centreI)
00733         {
00734             // Find the processor this sample+radius overlaps.
00735             calcOverlappingProcs
00736             (
00737                 centres[centreI],
00738                 radiusSqr[centreI],
00739                 procBbOverlaps
00740             );
00741 
00742             forAll(procBbOverlaps, procI)
00743             {
00744                 if (procI != Pstream::myProcNo() && procBbOverlaps[procI])
00745                 {
00746                     dynSendMap[procI].append(dynAllCentres.size());
00747                     dynAllSegmentMap.append(centreI);
00748                     dynAllCentres.append(centres[centreI]);
00749                     dynAllRadiusSqr.append(radiusSqr[centreI]);
00750                 }
00751             }
00752         }
00753 
00754         // Convert dynamicList to labelList
00755         sendMap.setSize(Pstream::nProcs());
00756         forAll(sendMap, procI)
00757         {
00758             dynSendMap[procI].shrink();
00759             sendMap[procI].transfer(dynSendMap[procI]);
00760         }
00761 
00762         allCentres.transfer(dynAllCentres.shrink());
00763         allRadiusSqr.transfer(dynAllRadiusSqr.shrink());
00764         allSegmentMap.transfer(dynAllSegmentMap.shrink());
00765     }
00766 
00767 
00768     // Send over how many I need to receive.
00769     labelListList sendSizes(Pstream::nProcs());
00770     sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
00771     forAll(sendMap, procI)
00772     {
00773         sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
00774     }
00775     Pstream::gatherList(sendSizes);
00776     Pstream::scatterList(sendSizes);
00777 
00778 
00779     // Determine order of receiving
00780     labelListList constructMap(Pstream::nProcs());
00781 
00782     // My local segments first
00783     constructMap[Pstream::myProcNo()] = identity
00784     (
00785         sendMap[Pstream::myProcNo()].size()
00786     );
00787 
00788     label segmentI = constructMap[Pstream::myProcNo()].size();
00789     forAll(constructMap, procI)
00790     {
00791         if (procI != Pstream::myProcNo())
00792         {
00793             // What I need to receive is what other processor is sending to me.
00794             label nRecv = sendSizes[procI][Pstream::myProcNo()];
00795             constructMap[procI].setSize(nRecv);
00796 
00797             for (label i = 0; i < nRecv; i++)
00798             {
00799                 constructMap[procI][i] = segmentI++;
00800             }
00801         }
00802     }
00803 
00804     autoPtr<mapDistribute> mapPtr
00805     (
00806         new mapDistribute
00807         (
00808             segmentI,       // size after construction
00809             sendMap,
00810             constructMap,
00811             true            // reuse storage
00812         )
00813     );
00814     return mapPtr;
00815 }
00816 
00817 
00818 // Find bounding boxes that guarantee a more or less uniform distribution
00819 // of triangles. Decomposition in here is only used to get the bounding
00820 // boxes, actual decomposition is done later on.
00821 // Returns a per processor a list of bounding boxes that most accurately
00822 // describe the shape. For now just a single bounding box per processor but
00823 // optimisation might be to determine a better fitting shape.
00824 Foam::List<Foam::List<Foam::treeBoundBox> >
00825 Foam::distributedTriSurfaceMesh::independentlyDistributedBbs
00826 (
00827     const triSurface& s
00828 )
00829 {
00830     if (!decomposer_.valid())
00831     {
00832         // Use current decomposer.
00833         // Note: or always use hierarchical?
00834         IOdictionary decomposeDict
00835         (
00836             IOobject
00837             (
00838                 "decomposeParDict",
00839                 searchableSurface::time().system(),
00840                 searchableSurface::time(),
00841                 IOobject::MUST_READ,
00842                 IOobject::NO_WRITE,
00843                 false
00844             )
00845         );
00846         decomposer_ = decompositionMethod::New(decomposeDict);
00847 
00848         if (!decomposer_().parallelAware())
00849         {
00850             FatalErrorIn
00851             (
00852                 "distributedTriSurfaceMesh::independentlyDistributedBbs"
00853                 "(const triSurface&)"
00854             )   << "The decomposition method " << decomposer_().typeName
00855                 << " does not decompose in parallel."
00856                 << " Please choose one that does." << exit(FatalError);
00857         }
00858     }
00859 
00860     // Do decomposition according to triangle centre
00861     pointField triCentres(s.size());
00862     forAll (s, triI)
00863     {
00864         triCentres[triI] = s[triI].centre(s.points());
00865     }
00866 
00867     // Do the actual decomposition
00868     labelList distribution(decomposer_->decompose(triCentres));
00869 
00870     // Find bounding box for all triangles on new distribution.
00871 
00872     // Initialise to inverted box (VGREAT, -VGREAT)
00873     List<List<treeBoundBox> > bbs(Pstream::nProcs());
00874     forAll(bbs, procI)
00875     {
00876         bbs[procI].setSize(1);
00877         //bbs[procI][0] = boundBox::invertedBox;
00878         bbs[procI][0].min() = point( VGREAT,  VGREAT,  VGREAT);
00879         bbs[procI][0].max() = point(-VGREAT, -VGREAT, -VGREAT); 
00880     }
00881 
00882     forAll (s, triI)
00883     {
00884         point& bbMin = bbs[distribution[triI]][0].min();
00885         point& bbMax = bbs[distribution[triI]][0].max();
00886 
00887         const labelledTri& f = s[triI];
00888         const point& p0 = s.points()[f[0]];
00889         const point& p1 = s.points()[f[1]];
00890         const point& p2 = s.points()[f[2]];
00891 
00892         bbMin = min(bbMin, p0);
00893         bbMin = min(bbMin, p1);
00894         bbMin = min(bbMin, p2);
00895 
00896         bbMax = max(bbMax, p0);
00897         bbMax = max(bbMax, p1);
00898         bbMax = max(bbMax, p2);
00899     }
00900 
00901     // Now combine for all processors and convert to correct format.
00902     forAll(bbs, procI)
00903     {
00904         forAll(bbs[procI], i)
00905         {
00906             reduce(bbs[procI][i].min(), minOp<point>());
00907             reduce(bbs[procI][i].max(), maxOp<point>());
00908         }
00909     }
00910     return bbs;
00911 }
00912 
00913 
00914 void Foam::distributedTriSurfaceMesh::calcBounds
00915 (
00916     boundBox& bb,
00917     label& nPoints
00918 ) const
00919 {
00920     // Unfortunately nPoints constructs meshPoints() so do compact version
00921     // ourselves
00922 
00923     PackedList<1> pointIsUsed(points().size());
00924     pointIsUsed = 0U;
00925 
00926     nPoints = 0;
00927     bb.min() = point(VGREAT, VGREAT, VGREAT);
00928     bb.max() = point(-VGREAT, -VGREAT, -VGREAT);
00929 
00930     const triSurface& s = static_cast<const triSurface&>(*this);
00931 
00932     forAll(s, triI)
00933     {
00934         const labelledTri& f = s[triI];
00935 
00936         forAll(f, fp)
00937         {
00938             label pointI = f[fp];
00939             if (pointIsUsed.set(pointI, 1))
00940             {
00941                 bb.min() = ::Foam::min(bb.min(), points()[pointI]);
00942                 bb.max() = ::Foam::max(bb.max(), points()[pointI]);
00943                 nPoints++;
00944             }
00945         }
00946     }
00947 }
00948 
00949 
00950 // Does any part of triangle overlap bb.
00951 bool Foam::distributedTriSurfaceMesh::overlaps
00952 (
00953     const List<treeBoundBox>& bbs,
00954     const point& p0,
00955     const point& p1,
00956     const point& p2
00957 )
00958 {
00959     forAll(bbs, bbI)
00960     {
00961         const treeBoundBox& bb = bbs[bbI];
00962 
00963         boundBox triBb(p0, p0);
00964         triBb.min() = min(triBb.min(), p1);
00965         triBb.min() = min(triBb.min(), p2);
00966 
00967         triBb.max() = max(triBb.max(), p1);
00968         triBb.max() = max(triBb.max(), p2);
00969 
00970         //- Exact test of triangle intersecting bb
00971 
00972         // Quick rejection. If whole bounding box of tri is outside cubeBb then
00973         // there will be no intersection.
00974         if (bb.overlaps(triBb))
00975         {
00976             // Check if one or more triangle point inside
00977             if (bb.contains(p0) || bb.contains(p1) || bb.contains(p2))
00978             {
00979                 // One or more points inside
00980                 return true;
00981             }
00982 
00983             // Now we have the difficult case: all points are outside but
00984             // connecting edges might go through cube. Use fast intersection
00985             // of bounding box.
00986             bool intersect = triangleFuncs::intersectBb(p0, p1, p2, bb);
00987 
00988             if (intersect)
00989             {
00990                 return true;
00991             }
00992         }
00993     }
00994     return false;
00995 }
00996 
00997 
00998 void Foam::distributedTriSurfaceMesh::subsetMeshMap
00999 (
01000     const triSurface& s,
01001     const boolList& include,
01002     const label nIncluded,
01003     labelList& newToOldPoints,
01004     labelList& oldToNewPoints,
01005     labelList& newToOldFaces
01006 )
01007 {
01008     newToOldFaces.setSize(nIncluded);
01009     newToOldPoints.setSize(s.points().size());
01010     oldToNewPoints.setSize(s.points().size());
01011     oldToNewPoints = -1;
01012     {
01013         label faceI = 0;
01014         label pointI = 0;
01015 
01016         forAll(include, oldFacei)
01017         {
01018             if (include[oldFacei])
01019             {
01020                 // Store new faces compact
01021                 newToOldFaces[faceI++] = oldFacei;
01022 
01023                 // Renumber labels for triangle
01024                 const labelledTri& tri = s[oldFacei];
01025 
01026                 forAll(tri, fp)
01027                 {
01028                     label oldPointI = tri[fp];
01029 
01030                     if (oldToNewPoints[oldPointI] == -1)
01031                     {
01032                         oldToNewPoints[oldPointI] = pointI;
01033                         newToOldPoints[pointI++] = oldPointI;
01034                     }
01035                 }
01036             }
01037         }
01038         newToOldPoints.setSize(pointI);
01039     }
01040 }
01041 
01042 
01043 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
01044 (
01045     const triSurface& s,
01046     const labelList& newToOldPoints,
01047     const labelList& oldToNewPoints,
01048     const labelList& newToOldFaces
01049 )
01050 {
01051     // Extract points
01052     pointField newPoints(newToOldPoints.size());
01053     forAll(newToOldPoints, i)
01054     {
01055         newPoints[i] = s.points()[newToOldPoints[i]];
01056     }
01057     // Extract faces
01058     List<labelledTri> newTriangles(newToOldFaces.size());
01059 
01060     forAll(newToOldFaces, i)
01061     {
01062         // Get old vertex labels
01063         const labelledTri& tri = s[newToOldFaces[i]];
01064 
01065         newTriangles[i][0] = oldToNewPoints[tri[0]];
01066         newTriangles[i][1] = oldToNewPoints[tri[1]];
01067         newTriangles[i][2] = oldToNewPoints[tri[2]];
01068         newTriangles[i].region() = tri.region();
01069     }
01070 
01071     // Reuse storage.
01072     return triSurface(newTriangles, s.patches(), newPoints, true);
01073 }
01074 
01075 
01076 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
01077 (
01078     const triSurface& s,
01079     const boolList& include,
01080     labelList& newToOldPoints,
01081     labelList& newToOldFaces
01082 )
01083 {
01084     label n = 0;
01085 
01086     forAll(include, i)
01087     {
01088         if (include[i])
01089         {
01090             n++;
01091         }
01092     }
01093 
01094     labelList oldToNewPoints;
01095     subsetMeshMap
01096     (
01097         s,
01098         include,
01099         n,
01100         newToOldPoints,
01101         oldToNewPoints,
01102         newToOldFaces
01103     );
01104 
01105     return subsetMesh
01106     (
01107         s,
01108         newToOldPoints,
01109         oldToNewPoints,
01110         newToOldFaces
01111     );
01112 }
01113 
01114 
01115 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
01116 (
01117     const triSurface& s,
01118     const labelList& newToOldFaces,
01119     labelList& newToOldPoints
01120 )
01121 {
01122     const boolList include
01123     (
01124         createWithValues<boolList>
01125         (
01126             s.size(),
01127             false,
01128             newToOldFaces,
01129             true
01130         )
01131     );
01132 
01133     newToOldPoints.setSize(s.points().size());
01134     labelList oldToNewPoints(s.points().size(), -1);
01135     {
01136         label pointI = 0;
01137 
01138         forAll(include, oldFacei)
01139         {
01140             if (include[oldFacei])
01141             {
01142                 // Renumber labels for triangle
01143                 const labelledTri& tri = s[oldFacei];
01144 
01145                 forAll(tri, fp)
01146                 {
01147                     label oldPointI = tri[fp];
01148 
01149                     if (oldToNewPoints[oldPointI] == -1)
01150                     {
01151                         oldToNewPoints[oldPointI] = pointI;
01152                         newToOldPoints[pointI++] = oldPointI;
01153                     }
01154                 }
01155             }
01156         }
01157         newToOldPoints.setSize(pointI);
01158     }
01159 
01160     return subsetMesh
01161     (
01162         s,
01163         newToOldPoints,
01164         oldToNewPoints,
01165         newToOldFaces
01166     );
01167 }
01168 
01169 
01170 Foam::label Foam::distributedTriSurfaceMesh::findTriangle
01171 (
01172     const List<labelledTri>& allFaces,
01173     const labelListList& allPointFaces,
01174     const labelledTri& otherF
01175 )
01176 {
01177     // allFaces connected to otherF[0]
01178     const labelList& pFaces = allPointFaces[otherF[0]];
01179 
01180     forAll(pFaces, i)
01181     {
01182         const labelledTri& f = allFaces[pFaces[i]];
01183 
01184         if (f.region() == otherF.region())
01185         {
01186             // Find index of otherF[0]
01187             label fp0 = findIndex(f, otherF[0]);
01188             // Check rest of triangle in same order
01189             label fp1 = f.fcIndex(fp0);
01190             label fp2 = f.fcIndex(fp1);
01191 
01192             if (f[fp1] == otherF[1] && f[fp2] == otherF[2])
01193             {
01194                 return pFaces[i];
01195             }
01196         }
01197     }
01198     return -1;
01199 }
01200 
01201 
01202 // Merge into allSurf.
01203 void Foam::distributedTriSurfaceMesh::merge
01204 (
01205     const scalar mergeDist,
01206     const List<labelledTri>& subTris,
01207     const pointField& subPoints,
01208 
01209     List<labelledTri>& allTris,
01210     pointField& allPoints,
01211 
01212     labelList& faceConstructMap,
01213     labelList& pointConstructMap
01214 )
01215 {
01216     labelList subToAll;
01217     matchPoints
01218     (
01219         subPoints,
01220         allPoints,
01221         scalarField(subPoints.size(), mergeDist),   // match distance
01222         false,                                      // verbose
01223         pointConstructMap
01224     );
01225 
01226     label nOldAllPoints = allPoints.size();
01227 
01228 
01229     // Add all unmatched points
01230     // ~~~~~~~~~~~~~~~~~~~~~~~~
01231 
01232     label allPointI = nOldAllPoints;
01233     forAll(pointConstructMap, pointI)
01234     {
01235         if (pointConstructMap[pointI] == -1)
01236         {
01237             pointConstructMap[pointI] = allPointI++;
01238         }
01239     }
01240 
01241     if (allPointI > nOldAllPoints)
01242     {
01243         allPoints.setSize(allPointI);
01244 
01245         forAll(pointConstructMap, pointI)
01246         {
01247             if (pointConstructMap[pointI] >= nOldAllPoints)
01248             {
01249                 allPoints[pointConstructMap[pointI]] = subPoints[pointI];
01250             }
01251         }
01252     }
01253 
01254 
01255     // To check whether triangles are same we use pointFaces.
01256     labelListList allPointFaces;
01257     invertManyToMany(nOldAllPoints, allTris, allPointFaces);
01258 
01259 
01260     // Add all unmatched triangles
01261     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
01262 
01263     label allTriI = allTris.size();
01264     allTris.setSize(allTriI + subTris.size());
01265 
01266     faceConstructMap.setSize(subTris.size());
01267 
01268     forAll(subTris, triI)
01269     {
01270         const labelledTri& subTri = subTris[triI];
01271 
01272         // Get triangle in new numbering
01273         labelledTri mappedTri
01274         (
01275             pointConstructMap[subTri[0]],
01276             pointConstructMap[subTri[1]],
01277             pointConstructMap[subTri[2]],
01278             subTri.region()
01279         );
01280 
01281 
01282         // Check if all points were already in surface
01283         bool fullMatch = true;
01284 
01285         forAll(mappedTri, fp)
01286         {
01287             if (mappedTri[fp] >= nOldAllPoints)
01288             {
01289                 fullMatch = false;
01290                 break;
01291             }
01292         }
01293 
01294         if (fullMatch)
01295         {
01296             // All three points are mapped to old points. See if same
01297             // triangle.
01298             label i = findTriangle
01299             (
01300                 allTris,
01301                 allPointFaces,
01302                 mappedTri
01303             );
01304 
01305             if (i == -1)
01306             {
01307                 // Add
01308                 faceConstructMap[triI] = allTriI;
01309                 allTris[allTriI] = mappedTri;
01310                 allTriI++;
01311             }
01312             else
01313             {
01314                 faceConstructMap[triI] = i;
01315             }
01316         }
01317         else
01318         {
01319             // Add
01320             faceConstructMap[triI] = allTriI;
01321             allTris[allTriI] = mappedTri;
01322             allTriI++;
01323         }
01324     }
01325     allTris.setSize(allTriI);
01326 }
01327 
01328 
01329 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
01330 
01331 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
01332 (
01333     const IOobject& io,
01334     const triSurface& s,
01335     const dictionary& dict
01336 )
01337 :
01338     triSurfaceMesh(io, s),
01339     dict_(io, dict)
01340 {
01341     read();
01342 
01343     if (debug)
01344     {
01345         Info<< "Constructed from triSurface:" << endl;
01346         writeStats(Info);
01347 
01348         labelList nTris(Pstream::nProcs());
01349         nTris[Pstream::myProcNo()] = triSurface::size();
01350         Pstream::gatherList(nTris);
01351         Pstream::scatterList(nTris);
01352 
01353         Info<< endl<< "\tproc\ttris\tbb" << endl;
01354         forAll(nTris, procI)
01355         {
01356             Info<< '\t' << procI << '\t' << nTris[procI]
01357                  << '\t' << procBb_[procI] << endl;
01358         }
01359         Info<< endl;
01360     }
01361 }
01362 
01363 
01364 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io)
01365 :
01366     //triSurfaceMesh(io),
01367     triSurfaceMesh
01368     (
01369         IOobject
01370         (
01371             io.name(),
01372             io.time().findInstance(io.local(), word::null),
01373             io.local(),
01374             io.db(),
01375             io.readOpt(),
01376             io.writeOpt(),
01377             io.registerObject()
01378         )
01379     ),
01380     dict_
01381     (
01382         IOobject
01383         (
01384             searchableSurface::name() + "Dict",
01385             searchableSurface::instance(),
01386             searchableSurface::local(),
01387             searchableSurface::db(),
01388             searchableSurface::readOpt(),
01389             searchableSurface::writeOpt(),
01390             searchableSurface::registerObject()
01391         )
01392     )
01393 {
01394     read();
01395 
01396     if (debug)
01397     {
01398         Info<< "Read distributedTriSurface from " << io.objectPath()
01399             << ':' << endl;
01400         writeStats(Info);
01401 
01402         labelList nTris(Pstream::nProcs());
01403         nTris[Pstream::myProcNo()] = triSurface::size();
01404         Pstream::gatherList(nTris);
01405         Pstream::scatterList(nTris);
01406 
01407         Info<< endl<< "\tproc\ttris\tbb" << endl;
01408         forAll(nTris, procI)
01409         {
01410             Info<< '\t' << procI << '\t' << nTris[procI]
01411                  << '\t' << procBb_[procI] << endl;
01412         }
01413         Info<< endl;
01414     }
01415 }
01416 
01417 
01418 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
01419 (
01420     const IOobject& io,
01421     const dictionary& dict
01422 )
01423 :
01424     //triSurfaceMesh(io, dict),
01425     triSurfaceMesh
01426     (
01427         IOobject
01428         (
01429             io.name(),
01430             io.time().findInstance(io.local(), word::null),
01431             io.local(),
01432             io.db(),
01433             io.readOpt(),
01434             io.writeOpt(),
01435             io.registerObject()
01436         ),
01437         dict
01438     ),
01439     dict_
01440     (
01441         IOobject
01442         (
01443             searchableSurface::name() + "Dict",
01444             searchableSurface::instance(),
01445             searchableSurface::local(),
01446             searchableSurface::db(),
01447             searchableSurface::readOpt(),
01448             searchableSurface::writeOpt(),
01449             searchableSurface::registerObject()
01450         )
01451     )
01452 {
01453     read();
01454 
01455     if (debug)
01456     {
01457         Info<< "Read distributedTriSurface from " << io.objectPath()
01458             << " and dictionary:" << endl;
01459         writeStats(Info);
01460 
01461         labelList nTris(Pstream::nProcs());
01462         nTris[Pstream::myProcNo()] = triSurface::size();
01463         Pstream::gatherList(nTris);
01464         Pstream::scatterList(nTris);
01465 
01466         Info<< endl<< "\tproc\ttris\tbb" << endl;
01467         forAll(nTris, procI)
01468         {
01469             Info<< '\t' << procI << '\t' << nTris[procI]
01470                  << '\t' << procBb_[procI] << endl;
01471         }
01472         Info<< endl;
01473     }
01474 }
01475 
01476 
01477 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
01478 
01479 Foam::distributedTriSurfaceMesh::~distributedTriSurfaceMesh()
01480 {
01481     clearOut();
01482 }
01483 
01484 
01485 void Foam::distributedTriSurfaceMesh::clearOut()
01486 {
01487     globalTris_.clear();
01488     triSurfaceMesh::clearOut();
01489 }
01490 
01491 
01492 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
01493 
01494 const Foam::globalIndex& Foam::distributedTriSurfaceMesh::globalTris() const
01495 {
01496     if (!globalTris_.valid())
01497     {
01498         globalTris_.reset(new globalIndex(triSurface::size()));
01499     }
01500     return globalTris_;
01501 }
01502 
01503 
01504 void Foam::distributedTriSurfaceMesh::findNearest
01505 (
01506     const pointField& samples,
01507     const scalarField& nearestDistSqr,
01508     List<pointIndexHit>& info
01509 ) const
01510 {
01511     const indexedOctree<treeDataTriSurface>& octree = tree();
01512 
01513     // Important:force synchronised construction of indexing
01514     const globalIndex& triIndexer = globalTris();
01515 
01516 
01517     // Initialise
01518     // ~~~~~~~~~~
01519 
01520     info.setSize(samples.size());
01521     forAll(info, i)
01522     {
01523         info[i].setMiss();
01524     }
01525 
01526 
01527 
01528     // Do any local queries
01529     // ~~~~~~~~~~~~~~~~~~~~
01530 
01531     label nLocal = 0;
01532 
01533     {
01534         // Work array - whether processor bb overlaps the bounding sphere.
01535         boolList procBbOverlaps(Pstream::nProcs());
01536 
01537         forAll(samples, i)
01538         {
01539             // Find the processor this sample+radius overlaps.
01540             label nProcs = calcOverlappingProcs
01541             (
01542                 samples[i],
01543                 nearestDistSqr[i],
01544                 procBbOverlaps
01545             );
01546 
01547             // Overlaps local processor?
01548             if (procBbOverlaps[Pstream::myProcNo()])
01549             {
01550                 info[i] = octree.findNearest(samples[i], nearestDistSqr[i]);
01551                 if (info[i].hit())
01552                 {
01553                     info[i].setIndex(triIndexer.toGlobal(info[i].index()));
01554                 }
01555                 if (nProcs == 1)
01556                 {
01557                     // Fully local
01558                     nLocal++;
01559                 }
01560             }
01561         }
01562     }
01563 
01564 
01565     if
01566     (
01567         Pstream::parRun()
01568      && (
01569             returnReduce(nLocal, sumOp<label>())
01570           < returnReduce(samples.size(), sumOp<label>())
01571         )
01572     )
01573     {
01574         // Not all can be resolved locally. Build queries and map, send over
01575         // queries, do intersections, send back and merge.
01576 
01577         // Calculate queries and exchange map
01578         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01579 
01580         pointField allCentres;
01581         scalarField allRadiusSqr;
01582         labelList allSegmentMap;
01583         autoPtr<mapDistribute> mapPtr
01584         (
01585             calcLocalQueries
01586             (
01587                 samples,
01588                 nearestDistSqr,
01589 
01590                 allCentres,
01591                 allRadiusSqr,
01592                 allSegmentMap
01593             )
01594         );
01595         const mapDistribute& map = mapPtr();
01596 
01597 
01598         // swap samples to local processor
01599         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01600 
01601         map.distribute
01602         (
01603             //Pstream::scheduled,
01604             //map.schedule(),
01605             Pstream::nonBlocking,
01606             List<labelPair>(0),
01607             map.constructSize(),
01608             map.subMap(),           // what to send
01609             map.constructMap(),     // what to receive
01610             allCentres
01611         );
01612         map.distribute
01613         (
01614             //Pstream::scheduled,
01615             //map.schedule(),
01616             Pstream::nonBlocking,
01617             List<labelPair>(0),
01618             map.constructSize(),
01619             map.subMap(),           // what to send
01620             map.constructMap(),     // what to receive
01621             allRadiusSqr
01622         );
01623 
01624 
01625         // Do my tests
01626         // ~~~~~~~~~~~
01627 
01628         List<pointIndexHit> allInfo(allCentres.size());
01629         forAll(allInfo, i)
01630         {
01631             allInfo[i] = octree.findNearest
01632             (
01633                 allCentres[i],
01634                 allRadiusSqr[i]
01635             );
01636             if (allInfo[i].hit())
01637             {
01638                 allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index()));
01639             }
01640         }
01641 
01642 
01643         // Send back results
01644         // ~~~~~~~~~~~~~~~~~
01645 
01646         map.distribute
01647         (
01648             //Pstream::scheduled,
01649             //map.schedule            // note reverse schedule
01650             //(
01651             //    map.constructMap(),
01652             //    map.subMap()
01653             //),
01654             Pstream::nonBlocking,
01655             List<labelPair>(0),
01656             allSegmentMap.size(),
01657             map.constructMap(),     // what to send
01658             map.subMap(),           // what to receive
01659             allInfo
01660         );
01661 
01662 
01663         // Extract information
01664         // ~~~~~~~~~~~~~~~~~~~
01665 
01666         forAll(allInfo, i)
01667         {
01668             if (allInfo[i].hit())
01669             {
01670                 label pointI = allSegmentMap[i];
01671 
01672                 if (!info[pointI].hit())
01673                 {
01674                     // No intersection yet so take this one
01675                     info[pointI] = allInfo[i];
01676                 }
01677                 else
01678                 {
01679                     // Nearest intersection
01680                     if
01681                     (
01682                         magSqr(allInfo[i].hitPoint()-samples[pointI])
01683                       < magSqr(info[pointI].hitPoint()-samples[pointI])
01684                     )
01685                     {
01686                         info[pointI] = allInfo[i];
01687                     }
01688                 }
01689             }
01690         }
01691     }
01692 }
01693 
01694 
01695 void Foam::distributedTriSurfaceMesh::findLine
01696 (
01697     const pointField& start,
01698     const pointField& end,
01699     List<pointIndexHit>& info
01700 ) const
01701 {
01702     findLine
01703     (
01704         true,   // nearestIntersection
01705         start,
01706         end,
01707         info
01708     );
01709 }
01710 
01711 
01712 void Foam::distributedTriSurfaceMesh::findLineAny
01713 (
01714     const pointField& start,
01715     const pointField& end,
01716     List<pointIndexHit>& info
01717 ) const
01718 {
01719     findLine
01720     (
01721         true,   // nearestIntersection
01722         start,
01723         end,
01724         info
01725     );
01726 }
01727 
01728 
01729 void Foam::distributedTriSurfaceMesh::findLineAll
01730 (
01731     const pointField& start,
01732     const pointField& end,
01733     List<List<pointIndexHit> >& info
01734 ) const
01735 {
01736     // Reuse fineLine. We could modify all of findLine to do multiple
01737     // intersections but this would mean a lot of data transferred so
01738     // for now we just find nearest intersection and retest from that
01739     // intersection onwards.
01740 
01741     // Work array.
01742     List<pointIndexHit> hitInfo(start.size());
01743 
01744     findLine
01745     (
01746         true,   // nearestIntersection
01747         start,
01748         end,
01749         hitInfo
01750     );
01751 
01752     // Tolerances:
01753     // To find all intersections we add a small vector to the last intersection
01754     // This is chosen such that
01755     // - it is significant (SMALL is smallest representative relative tolerance;
01756     //   we need something bigger since we're doing calculations)
01757     // - if the start-end vector is zero we still progress
01758     const vectorField dirVec(end-start);
01759     const scalarField magSqrDirVec(magSqr(dirVec));
01760     const vectorField smallVec
01761     (
01762         Foam::sqrt(SMALL)*dirVec
01763       + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
01764     );
01765 
01766     // Copy to input and compact any hits
01767     labelList pointMap(start.size());
01768     pointField e0(start.size());
01769     pointField e1(start.size());
01770     label compactI = 0;
01771 
01772     info.setSize(hitInfo.size());
01773     forAll(hitInfo, pointI)
01774     {
01775         if (hitInfo[pointI].hit())
01776         {
01777             info[pointI].setSize(1);
01778             info[pointI][0] = hitInfo[pointI];
01779 
01780             point pt = hitInfo[pointI].hitPoint() + smallVec[pointI];
01781 
01782             if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
01783             {
01784                 e0[compactI] = pt;
01785                 e1[compactI] = end[pointI];
01786                 pointMap[compactI] = pointI;
01787                 compactI++;
01788             }
01789         }
01790         else
01791         {
01792             info[pointI].clear();
01793         }
01794     }
01795 
01796     e0.setSize(compactI);
01797     e1.setSize(compactI);
01798     pointMap.setSize(compactI);
01799 
01800     while (returnReduce(e0.size(), sumOp<label>()) > 0)
01801     {
01802         findLine
01803         (
01804             true,   // nearestIntersection
01805             e0,
01806             e1,
01807             hitInfo
01808         );
01809 
01810 
01811         // Extract
01812         label compactI = 0;
01813         forAll(hitInfo, i)
01814         {
01815             if (hitInfo[i].hit())
01816             {
01817                 label pointI = pointMap[i];
01818 
01819                 label sz = info[pointI].size();
01820                 info[pointI].setSize(sz+1);
01821                 info[pointI][sz] = hitInfo[i];
01822 
01823                 point pt = hitInfo[i].hitPoint() + smallVec[pointI];
01824 
01825                 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
01826                 {
01827                     e0[compactI] = pt;
01828                     e1[compactI] = end[pointI];
01829                     pointMap[compactI] = pointI;
01830                     compactI++;
01831                 }
01832             }
01833         }
01834 
01835         // Trim
01836         e0.setSize(compactI);
01837         e1.setSize(compactI);
01838         pointMap.setSize(compactI);
01839     }
01840 }
01841 
01842 
01843 void Foam::distributedTriSurfaceMesh::getRegion
01844 (
01845     const List<pointIndexHit>& info,
01846     labelList& region
01847 ) const
01848 {
01849     if (!Pstream::parRun())
01850     {
01851         region.setSize(info.size());
01852         forAll(info, i)
01853         {
01854             if (info[i].hit())
01855             {
01856                 region[i] = triSurface::operator[](info[i].index()).region();
01857             }
01858             else
01859             {
01860                 region[i] = -1;
01861             }
01862         }
01863         return;
01864     }
01865 
01866 
01867     // Get query data (= local index of triangle)
01868     // ~~~~~~~~~~~~~~
01869 
01870     labelList triangleIndex(info.size());
01871     autoPtr<mapDistribute> mapPtr
01872     (
01873         calcLocalQueries
01874         (
01875             info,
01876             triangleIndex
01877         )
01878     );
01879     const mapDistribute& map = mapPtr();
01880 
01881 
01882     // Do my tests
01883     // ~~~~~~~~~~~
01884 
01885     const triSurface& s = static_cast<const triSurface&>(*this);
01886 
01887     region.setSize(triangleIndex.size());
01888 
01889     forAll(triangleIndex, i)
01890     {
01891         label triI = triangleIndex[i];
01892         region[i] = s[triI].region();
01893     }
01894 
01895 
01896     // Send back results
01897     // ~~~~~~~~~~~~~~~~~
01898 
01899     map.distribute
01900     (
01901         //Pstream::scheduled,
01902         //map.schedule            // note reverse schedule
01903         //(
01904         //    map.constructMap(),
01905         //    map.subMap()
01906         //),
01907         Pstream::nonBlocking,
01908         List<labelPair>(0),
01909         info.size(),
01910         map.constructMap(),     // what to send
01911         map.subMap(),           // what to receive
01912         region
01913     );
01914 }
01915 
01916 
01917 void Foam::distributedTriSurfaceMesh::getNormal
01918 (
01919     const List<pointIndexHit>& info,
01920     vectorField& normal
01921 ) const
01922 {
01923     if (!Pstream::parRun())
01924     {
01925         normal.setSize(info.size());
01926 
01927         forAll(info, i)
01928         {
01929             if (info[i].hit())
01930             {
01931                 normal[i] = faceNormals()[info[i].index()];
01932             }
01933             else
01934             {
01935                 // Set to what?
01936                 normal[i] = vector::zero;
01937             }
01938         }
01939         return;
01940     }
01941 
01942 
01943     // Get query data (= local index of triangle)
01944     // ~~~~~~~~~~~~~~
01945 
01946     labelList triangleIndex(info.size());
01947     autoPtr<mapDistribute> mapPtr
01948     (
01949         calcLocalQueries
01950         (
01951             info,
01952             triangleIndex
01953         )
01954     );
01955     const mapDistribute& map = mapPtr();
01956 
01957 
01958     // Do my tests
01959     // ~~~~~~~~~~~
01960 
01961     const triSurface& s = static_cast<const triSurface&>(*this);
01962 
01963     normal.setSize(triangleIndex.size());
01964 
01965     forAll(triangleIndex, i)
01966     {
01967         label triI = triangleIndex[i];
01968         normal[i] = s[triI].normal(s.points());
01969         normal[i] /= mag(normal[i]) + VSMALL;
01970     }
01971 
01972 
01973     // Send back results
01974     // ~~~~~~~~~~~~~~~~~
01975 
01976     map.distribute
01977     (
01978         //Pstream::scheduled,
01979         //map.schedule            // note reverse schedule
01980         //(
01981         //    map.constructMap(),
01982         //    map.subMap()
01983         //),
01984         Pstream::nonBlocking,
01985         List<labelPair>(0),
01986         info.size(),
01987         map.constructMap(),     // what to send
01988         map.subMap(),           // what to receive
01989         normal
01990     );
01991 }
01992 
01993 
01994 void Foam::distributedTriSurfaceMesh::getField
01995 (
01996     const word& fieldName,
01997     const List<pointIndexHit>& info,
01998     labelList& values
01999 ) const
02000 {
02001     const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
02002     (
02003         fieldName
02004     );
02005 
02006 
02007     if (!Pstream::parRun())
02008     {
02009         values.setSize(info.size());
02010         forAll(info, i)
02011         {
02012             if (info[i].hit())
02013             {
02014                 values[i] = fld[info[i].index()];
02015             }
02016         }
02017         return;
02018     }
02019 
02020 
02021     // Get query data (= local index of triangle)
02022     // ~~~~~~~~~~~~~~
02023 
02024     labelList triangleIndex(info.size());
02025     autoPtr<mapDistribute> mapPtr
02026     (
02027         calcLocalQueries
02028         (
02029             info,
02030             triangleIndex
02031         )
02032     );
02033     const mapDistribute& map = mapPtr();
02034 
02035 
02036     // Do my tests
02037     // ~~~~~~~~~~~
02038 
02039     values.setSize(triangleIndex.size());
02040 
02041     forAll(triangleIndex, i)
02042     {
02043         label triI = triangleIndex[i];
02044         values[i] = fld[triI];
02045     }
02046 
02047 
02048     // Send back results
02049     // ~~~~~~~~~~~~~~~~~
02050 
02051     map.distribute
02052     (
02053         Pstream::nonBlocking,
02054         List<labelPair>(0),
02055         info.size(),
02056         map.constructMap(),     // what to send
02057         map.subMap(),           // what to receive
02058         values
02059     );
02060 }
02061 
02062 
02063 void Foam::distributedTriSurfaceMesh::getVolumeType
02064 (
02065     const pointField& points,
02066     List<volumeType>& volType
02067 ) const
02068 {
02069     FatalErrorIn
02070     (
02071         "distributedTriSurfaceMesh::getVolumeType"
02072         "(const pointField&, List<volumeType>&) const"
02073     )   << "Volume type not supported for distributed surfaces."
02074         << exit(FatalError);
02075 }
02076 
02077 
02078 // Subset the part of surface that is overlapping bb.
02079 Foam::triSurface Foam::distributedTriSurfaceMesh::overlappingSurface
02080 (
02081     const triSurface& s,
02082     const List<treeBoundBox>& bbs,
02083 
02084     labelList& subPointMap,
02085     labelList& subFaceMap
02086 )
02087 {
02088     // Determine what triangles to keep.
02089     boolList includedFace(s.size(), false);
02090 
02091     // Create a slightly larger bounding box.
02092     List<treeBoundBox> bbsX(bbs.size());
02093     const scalar eps = 1.0e-4;
02094     forAll(bbs, i)
02095     {
02096         const point mid = 0.5*(bbs[i].min() + bbs[i].max());
02097         const vector halfSpan = (1.0+eps)*(bbs[i].max() - mid);
02098 
02099         bbsX[i].min() = mid - halfSpan;
02100         bbsX[i].max() = mid + halfSpan;
02101     }
02102 
02103     forAll(s, triI)
02104     {
02105         const labelledTri& f = s[triI];
02106         const point& p0 = s.points()[f[0]];
02107         const point& p1 = s.points()[f[1]];
02108         const point& p2 = s.points()[f[2]];
02109 
02110         if (overlaps(bbsX, p0, p1, p2))
02111         {
02112             includedFace[triI] = true;
02113         }
02114     }
02115 
02116     return subsetMesh(s, includedFace, subPointMap, subFaceMap);
02117 }
02118 
02119 
02120 void Foam::distributedTriSurfaceMesh::distribute
02121 (
02122     const List<treeBoundBox>& bbs,
02123     const bool keepNonLocal,
02124     autoPtr<mapDistribute>& faceMap,
02125     autoPtr<mapDistribute>& pointMap
02126 )
02127 {
02128     // Get bbs of all domains
02129     // ~~~~~~~~~~~~~~~~~~~~~~
02130 
02131     {
02132         List<List<treeBoundBox> > newProcBb(Pstream::nProcs());
02133 
02134         switch(distType_)
02135         {
02136             case FOLLOW:
02137                 newProcBb[Pstream::myProcNo()].setSize(bbs.size());
02138                 forAll(bbs, i)
02139                 {
02140                     newProcBb[Pstream::myProcNo()][i] = bbs[i];
02141                 }
02142                 Pstream::gatherList(newProcBb);
02143                 Pstream::scatterList(newProcBb);
02144             break;
02145 
02146             case INDEPENDENT:
02147                 newProcBb = independentlyDistributedBbs(*this);
02148             break;
02149 
02150             case FROZEN:
02151                 return;
02152             break;
02153 
02154             default:
02155                 FatalErrorIn("distributedTriSurfaceMesh::distribute(..)")
02156                     << "Unsupported distribution type." << exit(FatalError);
02157             break;
02158         }
02159 
02160         //if (debug)
02161         //{
02162         //    Info<< "old bb:" << procBb_ << endl << endl;
02163         //    Info<< "new bb:" << newProcBb << endl << endl;
02164         //    Info<< "Same:" << (newProcBb == procBb_) << endl;
02165         //}
02166 
02167         if (newProcBb == procBb_)
02168         {
02169             return;
02170         }
02171         else
02172         {
02173             procBb_.transfer(newProcBb);
02174             dict_.set("bounds", procBb_[Pstream::myProcNo()]);
02175         }
02176     }
02177 
02178 
02179     // Debug information
02180     if (debug)
02181     {
02182         labelList nTris(Pstream::nProcs());
02183         nTris[Pstream::myProcNo()] = triSurface::size();
02184         Pstream::gatherList(nTris);
02185         Pstream::scatterList(nTris);
02186 
02187         Info<< "distributedTriSurfaceMesh::distribute : before distribution:"
02188             << endl
02189             << "\tproc\ttris" << endl;
02190 
02191         forAll(nTris, procI)
02192         {
02193             Info<< '\t' << procI << '\t' << nTris[procI] << endl;
02194         }
02195         Info<< endl;
02196     }
02197 
02198 
02199     // Use procBbs to determine which faces go where
02200     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02201 
02202     labelListList faceSendMap(Pstream::nProcs());
02203     labelListList pointSendMap(Pstream::nProcs());
02204 
02205     forAll(procBb_, procI)
02206     {
02207         overlappingSurface
02208         (
02209             *this,
02210             procBb_[procI],
02211             pointSendMap[procI],
02212             faceSendMap[procI]
02213         );
02214 
02215         if (debug)
02216         {
02217             //Pout<< "Overlapping with proc " << procI
02218             //    << " faces:" << faceSendMap[procI].size()
02219             //    << " points:" << pointSendMap[procI].size() << endl << endl;
02220         }
02221     }
02222 
02223     if (keepNonLocal)
02224     {
02225         // Include in faceSendMap/pointSendMap the triangles that are
02226         // not mapped to any processor so they stay local.
02227 
02228         const triSurface& s = static_cast<const triSurface&>(*this);
02229 
02230         boolList includedFace(s.size(), true);
02231 
02232         forAll(faceSendMap, procI)
02233         {
02234             if (procI != Pstream::myProcNo())
02235             {
02236                 forAll(faceSendMap[procI], i)
02237                 {
02238                     includedFace[faceSendMap[procI][i]] = false;
02239                 }
02240             }
02241         }
02242 
02243         // Combine includedFace (all triangles that are not on any neighbour)
02244         // with overlap.
02245 
02246         forAll(faceSendMap[Pstream::myProcNo()], i)
02247         {
02248             includedFace[faceSendMap[Pstream::myProcNo()][i]] = true;
02249         }
02250 
02251         subsetMesh
02252         (
02253             s,
02254             includedFace,
02255             pointSendMap[Pstream::myProcNo()],
02256             faceSendMap[Pstream::myProcNo()]
02257         );
02258     }
02259 
02260 
02261     // Send over how many faces/points I need to receive
02262     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02263 
02264     labelListList faceSendSizes(Pstream::nProcs());
02265     faceSendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
02266     forAll(faceSendMap, procI)
02267     {
02268         faceSendSizes[Pstream::myProcNo()][procI] = faceSendMap[procI].size();
02269     }
02270     Pstream::gatherList(faceSendSizes);
02271     Pstream::scatterList(faceSendSizes);
02272 
02273 
02274 
02275     // Exchange surfaces
02276     // ~~~~~~~~~~~~~~~~~
02277 
02278     // Storage for resulting surface
02279     List<labelledTri> allTris;
02280     pointField allPoints;
02281 
02282     labelListList faceConstructMap(Pstream::nProcs());
02283     labelListList pointConstructMap(Pstream::nProcs());
02284 
02285 
02286     // My own surface first
02287     // ~~~~~~~~~~~~~~~~~~~~
02288 
02289     {
02290         labelList pointMap;
02291         triSurface subSurface
02292         (
02293             subsetMesh
02294             (
02295                 *this,
02296                 faceSendMap[Pstream::myProcNo()],
02297                 pointMap
02298             )
02299         );
02300 
02301         allTris = subSurface;
02302         allPoints = subSurface.points();
02303 
02304         faceConstructMap[Pstream::myProcNo()] = identity
02305         (
02306             faceSendMap[Pstream::myProcNo()].size()
02307         );
02308         pointConstructMap[Pstream::myProcNo()] = identity
02309         (
02310             pointSendMap[Pstream::myProcNo()].size()
02311         );
02312     }
02313 
02314 
02315 
02316     // Send all
02317     // ~~~~~~~~
02318 
02319     forAll(faceSendSizes, procI)
02320     {
02321         if (procI != Pstream::myProcNo())
02322         {
02323             if (faceSendSizes[Pstream::myProcNo()][procI] > 0)
02324             {
02325                 OPstream str(Pstream::blocking, procI);
02326 
02327                 labelList pointMap;
02328                 triSurface subSurface
02329                 (
02330                     subsetMesh
02331                     (
02332                         *this,
02333                         faceSendMap[procI],
02334                         pointMap
02335                     )
02336                 );
02337 
02338                 //if (debug)
02339                 //{
02340                 //    Pout<< "Sending to " << procI
02341                 //        << " faces:" << faceSendMap[procI].size()
02342                 //        << " points:" << subSurface.points().size() << endl
02343                 //        << endl;
02344                 //}
02345 
02346                 str << subSurface;
02347            }
02348         }
02349     }
02350 
02351 
02352     // Receive and merge all
02353     // ~~~~~~~~~~~~~~~~~~~~~
02354 
02355     forAll(faceSendSizes, procI)
02356     {
02357         if (procI != Pstream::myProcNo())
02358         {
02359             if (faceSendSizes[procI][Pstream::myProcNo()] > 0)
02360             {
02361                 IPstream str(Pstream::blocking, procI);
02362 
02363                 // Receive
02364                 triSurface subSurface(str);
02365 
02366                 //if (debug)
02367                 //{
02368                 //    Pout<< "Received from " << procI
02369                 //        << " faces:" << subSurface.size()
02370                 //        << " points:" << subSurface.points().size() << endl
02371                 //        << endl;
02372                 //}
02373 
02374                 // Merge into allSurf
02375                 merge
02376                 (
02377                     mergeDist_,
02378                     subSurface,
02379                     subSurface.points(),
02380 
02381                     allTris,
02382                     allPoints,
02383                     faceConstructMap[procI],
02384                     pointConstructMap[procI]
02385                 );
02386 
02387                 //if (debug)
02388                 //{
02389                 //    Pout<< "Current merged surface : faces:" << allTris.size()
02390                 //        << " points:" << allPoints.size() << endl << endl;
02391                 //}
02392            }
02393         }
02394     }
02395 
02396 
02397     faceMap.reset
02398     (
02399         new mapDistribute
02400         (
02401             allTris.size(),
02402             faceSendMap,
02403             faceConstructMap,
02404             true
02405         )
02406     );
02407     pointMap.reset
02408     (
02409         new mapDistribute
02410         (
02411             allPoints.size(),
02412             pointSendMap,
02413             pointConstructMap,
02414             true
02415         )
02416     );
02417 
02418     // Construct triSurface. Reuse storage.
02419     triSurface::operator=(triSurface(allTris, patches(), allPoints, true));
02420 
02421     clearOut();
02422 
02423     // Regions stays same
02424     // Volume type stays same.
02425 
02426     distributeFields<label>(faceMap());
02427     distributeFields<scalar>(faceMap());
02428     distributeFields<vector>(faceMap());
02429     distributeFields<sphericalTensor>(faceMap());
02430     distributeFields<symmTensor>(faceMap());
02431     distributeFields<tensor>(faceMap());
02432 
02433     if (debug)
02434     {
02435         labelList nTris(Pstream::nProcs());
02436         nTris[Pstream::myProcNo()] = triSurface::size();
02437         Pstream::gatherList(nTris);
02438         Pstream::scatterList(nTris);
02439 
02440         Info<< "distributedTriSurfaceMesh::distribute : after distribution:"
02441             << endl
02442             << "\tproc\ttris" << endl;
02443 
02444         forAll(nTris, procI)
02445         {
02446             Info<< '\t' << procI << '\t' << nTris[procI] << endl;
02447         }
02448         Info<< endl;
02449     }
02450 }
02451 
02452 
02453 //- Write using given format, version and compression
02454 bool Foam::distributedTriSurfaceMesh::writeObject
02455 (
02456     IOstream::streamFormat fmt,
02457     IOstream::versionNumber ver,
02458     IOstream::compressionType cmp
02459 ) const
02460 {
02461     // Make sure dictionary goes to same directory as surface
02462     const_cast<fileName&>(dict_.instance()) = searchableSurface::instance();
02463 
02464     // Dictionary needs to be written in ascii - binary output not supported.
02465     return
02466         triSurfaceMesh::writeObject(fmt, ver, cmp)
02467      && dict_.writeObject(IOstream::ASCII, ver, cmp);
02468 }
02469 
02470 
02471 void Foam::distributedTriSurfaceMesh::writeStats(Ostream& os) const
02472 {
02473     boundBox bb;
02474     label nPoints;
02475     calcBounds(bb, nPoints);
02476     reduce(bb.min(), minOp<point>());
02477     reduce(bb.max(), maxOp<point>());
02478 
02479     os  << "Triangles    : " << returnReduce(triSurface::size(), sumOp<label>())
02480         << endl
02481         << "Vertices     : " << returnReduce(nPoints, sumOp<label>()) << endl
02482         << "Bounding Box : " << bb << endl;
02483 }
02484 
02485 
02486 // ************************************************************************* //
Copyright © 2000-2009 OpenCFD Ltd