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

directMappedPatchBase.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 "directMappedPatchBase.H"
00028 #include "addToRunTimeSelectionTable.H"
00029 #include "ListListOps.H"
00030 #include "meshSearch.H"
00031 #include "meshTools.H"
00032 #include "OFstream.H"
00033 #include "Random.H"
00034 #include "treeDataFace.H"
00035 #include "indexedOctree.H"
00036 
00037 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00038 
00039 namespace Foam
00040 {
00041     defineTypeNameAndDebug(directMappedPatchBase, 0);
00042 
00043     template<>
00044     const char* NamedEnum<directMappedPatchBase::sampleMode, 3>::names[] =
00045     {
00046         "nearestCell",
00047         "nearestPatchFace",
00048         "nearestFace"
00049     };
00050 
00051     const NamedEnum<directMappedPatchBase::sampleMode, 3>
00052         directMappedPatchBase::sampleModeNames_;
00053 }
00054 
00055 
00056 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00057 
00058 void Foam::directMappedPatchBase::collectSamples
00059 (
00060     pointField& samples,
00061     labelList& patchFaceProcs,
00062     labelList& patchFaces,
00063     pointField& patchFc
00064 ) const
00065 {
00066 
00067     // Collect all sample points and the faces they come from.
00068     List<pointField> globalFc(Pstream::nProcs());
00069     List<pointField> globalSamples(Pstream::nProcs());
00070     labelListList globalFaces(Pstream::nProcs());
00071 
00072     globalFc[Pstream::myProcNo()] = patch_.faceCentres();
00073     globalSamples[Pstream::myProcNo()] = globalFc[Pstream::myProcNo()]+offset_;
00074     globalFaces[Pstream::myProcNo()] = identity(patch_.size());
00075 
00076     // Distribute to all processors
00077     Pstream::gatherList(globalSamples);
00078     Pstream::scatterList(globalSamples);
00079     Pstream::gatherList(globalFaces);
00080     Pstream::scatterList(globalFaces);
00081     Pstream::gatherList(globalFc);
00082     Pstream::scatterList(globalFc);
00083 
00084     // Rework into straight list
00085     samples = ListListOps::combine<pointField>
00086     (
00087         globalSamples,
00088         accessOp<pointField>()
00089     );
00090     patchFaces = ListListOps::combine<labelList>
00091     (
00092         globalFaces,
00093         accessOp<labelList>()
00094     );
00095     patchFc = ListListOps::combine<pointField>
00096     (
00097         globalFc,
00098         accessOp<pointField>()
00099     );
00100 
00101     patchFaceProcs.setSize(patchFaces.size());
00102     labelList nPerProc
00103     (
00104         ListListOps::subSizes
00105         (
00106             globalFaces,
00107             accessOp<labelList>()
00108         )
00109     );
00110     label sampleI = 0;
00111     forAll(nPerProc, procI)
00112     {
00113         for (label i = 0; i < nPerProc[procI]; i++)
00114         {
00115             patchFaceProcs[sampleI++] = procI;
00116         }
00117     }
00118 }
00119 
00120 
00121 // Find the processor/cell containing the samples. Does not account
00122 // for samples being found in two processors.
00123 void Foam::directMappedPatchBase::findSamples
00124 (
00125     const pointField& samples,
00126     labelList& sampleProcs,
00127     labelList& sampleIndices,
00128     pointField& sampleLocations
00129 ) const
00130 {
00131     // Lookup the correct region
00132     const polyMesh& mesh = sampleMesh();
00133 
00134     // All the info for nearest. Construct to miss
00135     List<nearInfo> nearest(samples.size());
00136 
00137     switch (mode_)
00138     {
00139         case NEARESTCELL:
00140         {
00141             if (samplePatch_.size() && samplePatch_ != "none")
00142             {
00143                 FatalErrorIn
00144                 (
00145                     "directMappedPatchBase::findSamples(const pointField&,"
00146                     " labelList&, labelList&, pointField&) const"
00147                 )   << "No need to supply a patch name when in "
00148                     << sampleModeNames_[mode_] << " mode." << exit(FatalError);
00149             }
00150 
00151             // Octree based search engine
00152             meshSearch meshSearchEngine(mesh, false);
00153 
00154             forAll(samples, sampleI)
00155             {
00156                 const point& sample = samples[sampleI];
00157 
00158                 label cellI = meshSearchEngine.findCell(sample);
00159 
00160                 if (cellI == -1)
00161                 {
00162                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
00163                     nearest[sampleI].second().second() = Pstream::myProcNo();
00164                 }
00165                 else
00166                 {
00167                     const point& cc = mesh.cellCentres()[cellI];
00168 
00169                     nearest[sampleI].first() = pointIndexHit
00170                     (
00171                         true,
00172                         cc,
00173                         cellI
00174                     );
00175                     nearest[sampleI].second().first() = magSqr(cc-sample);
00176                     nearest[sampleI].second().second() = Pstream::myProcNo();
00177                 }
00178             }
00179             break;
00180         }
00181 
00182         case NEARESTPATCHFACE:
00183         {
00184             Random rndGen(123456);
00185 
00186             const polyPatch& pp = samplePolyPatch();
00187 
00188             if (pp.empty())
00189             {
00190                 forAll(samples, sampleI)
00191                 {
00192                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
00193                     nearest[sampleI].second().second() = Pstream::myProcNo();
00194                 }
00195             }
00196             else
00197             {
00198                 // patch faces
00199                 const labelList patchFaces(identity(pp.size()) + pp.start());
00200 
00201                 treeBoundBox patchBb
00202                 (
00203                     treeBoundBox(pp.points(), pp.meshPoints()).extend
00204                     (
00205                         rndGen,
00206                         1E-4
00207                     )
00208                 );
00209                 patchBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00210                 patchBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
00211 
00212                 indexedOctree<treeDataFace> boundaryTree
00213                 (
00214                     treeDataFace    // all information needed to search faces
00215                     (
00216                         false,      // do not cache bb
00217                         mesh,
00218                         patchFaces  // boundary faces only
00219                     ),
00220                     patchBb,        // overall search domain
00221                     8,              // maxLevel
00222                     10,             // leafsize
00223                     3.0             // duplicity
00224                 );
00225 
00226                 forAll(samples, sampleI)
00227                 {
00228                     const point& sample = samples[sampleI];
00229 
00230                     pointIndexHit& nearInfo = nearest[sampleI].first();
00231                     nearInfo = boundaryTree.findNearest
00232                     (
00233                         sample,
00234                         magSqr(patchBb.span())
00235                     );
00236 
00237                     if (!nearInfo.hit())
00238                     {
00239                         nearest[sampleI].second().first() = Foam::sqr(GREAT);
00240                         nearest[sampleI].second().second() =
00241                             Pstream::myProcNo();
00242                     }
00243                     else
00244                     {
00245                         point fc(pp[nearInfo.index()].centre(pp.points()));
00246                         nearInfo.setPoint(fc);
00247                         nearest[sampleI].second().first() = magSqr(fc-sample);
00248                         nearest[sampleI].second().second() =
00249                             Pstream::myProcNo();
00250                     }
00251                 }
00252             }
00253             break;
00254         }
00255 
00256         case NEARESTFACE:
00257         {
00258             if (samplePatch_.size() && samplePatch_ != "none")
00259             {
00260                 FatalErrorIn
00261                 (
00262                     "directMappedPatchBase::findSamples(const pointField&,"
00263                     " labelList&, labelList&, pointField&) const"
00264                 )   << "No need to supply a patch name when in "
00265                     << sampleModeNames_[mode_] << " mode." << exit(FatalError);
00266             }
00267 
00268             // Octree based search engine
00269             meshSearch meshSearchEngine(mesh, false);
00270 
00271             forAll(samples, sampleI)
00272             {
00273                 const point& sample = samples[sampleI];
00274 
00275                 label faceI = meshSearchEngine.findNearestFace(sample);
00276 
00277                 if (faceI == -1)
00278                 {
00279                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
00280                     nearest[sampleI].second().second() = Pstream::myProcNo();
00281                 }
00282                 else
00283                 {
00284                     const point& fc = mesh.faceCentres()[faceI];
00285 
00286                     nearest[sampleI].first() = pointIndexHit
00287                     (
00288                         true,
00289                         fc,
00290                         faceI
00291                     );
00292                     nearest[sampleI].second().first() = magSqr(fc-sample);
00293                     nearest[sampleI].second().second() = Pstream::myProcNo();
00294                 }
00295             }
00296             break;
00297         }
00298 
00299         default:
00300         {
00301             FatalErrorIn("directMappedPatchBase::findSamples(..)")
00302                 << "problem." << abort(FatalError);
00303         }
00304     }
00305 
00306 
00307     // Find nearest.
00308     Pstream::listCombineGather(nearest, nearestEqOp());
00309     Pstream::listCombineScatter(nearest);
00310 
00311     if (debug)
00312     {
00313         Info<< "directMappedPatchBase::findSamples on mesh " << sampleRegion_
00314             << " : " << endl;
00315         forAll(nearest, sampleI)
00316         {
00317             label procI = nearest[sampleI].second().second();
00318             label localI = nearest[sampleI].first().index();
00319 
00320             Info<< "    " << sampleI << " coord:"<< samples[sampleI]
00321                 << " found on processor:" << procI
00322                 << " in local cell/face:" << localI
00323                 << " with cc:" << nearest[sampleI].first().rawPoint() << endl;
00324         }
00325     }
00326 
00327     // Check for samples not being found
00328     forAll(nearest, sampleI)
00329     {
00330         if (!nearest[sampleI].first().hit())
00331         {
00332             FatalErrorIn
00333             (
00334                 "directMappedPatchBase::findSamples"
00335                 "(const pointField&, labelList&"
00336                 ", labelList&, pointField&)"
00337             )   << "Did not find sample " << samples[sampleI]
00338                 << " on any processor of region" << sampleRegion_
00339                 << exit(FatalError);
00340         }
00341     }
00342 
00343 
00344     // Convert back into proc+local index
00345     sampleProcs.setSize(samples.size());
00346     sampleIndices.setSize(samples.size());
00347     sampleLocations.setSize(samples.size());
00348 
00349     forAll(nearest, sampleI)
00350     {
00351         sampleProcs[sampleI] = nearest[sampleI].second().second();
00352         sampleIndices[sampleI] = nearest[sampleI].first().index();
00353         sampleLocations[sampleI] = nearest[sampleI].first().hitPoint();
00354     }
00355 }
00356 
00357 
00358 void Foam::directMappedPatchBase::calcMapping() const
00359 {
00360     if (mapPtr_.valid())
00361     {
00362         FatalErrorIn("directMappedPatchBase::calcMapping() const")
00363             << "Mapping already calculated" << exit(FatalError);
00364     }
00365 
00366     if
00367     (
00368         offset_ == vector::zero
00369      && sampleRegion_ == patch_.boundaryMesh().mesh().name()
00370     )
00371     {
00372         FatalErrorIn("directMappedPatchBase::calcMapping() const")
00373             << "Invalid offset " << offset_ << endl
00374             << "Offset is the vector added to the patch face centres to"
00375             << " find the cell supplying the data."
00376             << exit(FatalError);
00377     }
00378 
00379 
00380     // Get global list of all samples and the processor and face they come from.
00381     pointField samples;
00382     labelList patchFaceProcs;
00383     labelList patchFaces;
00384     pointField patchFc;
00385     collectSamples(samples, patchFaceProcs, patchFaces, patchFc);
00386 
00387     // Find processor and cell/face samples are in and actual location.
00388     labelList sampleProcs;
00389     labelList sampleIndices;
00390     pointField sampleLocations;
00391     findSamples(samples, sampleProcs, sampleIndices, sampleLocations);
00392 
00393 
00394     // Now we have all the data we need:
00395     // - where sample originates from (so destination when mapping):
00396     //   patchFaces, patchFaceProcs.
00397     // - cell/face sample is in (so source when mapping)
00398     //   sampleIndices, sampleProcs.
00399 
00400     //forAll(samples, i)
00401     //{
00402     //    Info<< i << " need data in region "
00403     //        << patch_.boundaryMesh().mesh().name()
00404     //        << " for proc:" << patchFaceProcs[i]
00405     //        << " face:" << patchFaces[i]
00406     //        << " at:" << patchFc[i] << endl
00407     //        << "Found data in region " << sampleRegion_
00408     //        << " at proc:" << sampleProcs[i]
00409     //        << " face:" << sampleIndices[i]
00410     //        << " at:" << sampleLocations[i]
00411     //        << nl << endl;
00412     //}
00413 
00414 
00415 
00416     if (debug && Pstream::master())
00417     {
00418         OFstream str
00419         (
00420             patch_.boundaryMesh().mesh().time().path()
00421           / patch_.name()
00422           + "_directMapped.obj"
00423         );
00424         Pout<< "Dumping mapping as lines from patch faceCentres to"
00425             << " sampled cellCentres to file " << str.name() << endl;
00426 
00427         label vertI = 0;
00428 
00429         forAll(patchFc, i)
00430         {
00431             meshTools::writeOBJ(str, patchFc[i]);
00432             vertI++;
00433             meshTools::writeOBJ(str, sampleLocations[i]);
00434             vertI++;
00435             str << "l " << vertI-1 << ' ' << vertI << nl;
00436         }
00437     }
00438 
00439 
00440     // Check that actual offset vector (sampleLocations - patchFc) is more or
00441     // less constant.
00442     if (Pstream::master())
00443     {
00444         const scalarField magOffset(mag(sampleLocations - patchFc));
00445         const scalar avgOffset(average(magOffset));
00446 
00447         forAll(magOffset, sampleI)
00448         {
00449             if (mag(magOffset[sampleI]-avgOffset) > max(SMALL, 0.001*avgOffset))
00450             {
00451                 WarningIn("directMappedPatchBase::calcMapping() const")
00452                     << "The actual cell/face centres picked up using offset "
00453                     << offset_ << " are not" << endl
00454                     << "    on a single plane."
00455                     << " This might give numerical problems." << endl
00456                     << "    At patchface " << patchFc[sampleI]
00457                     << " the sampled cell/face " << sampleLocations[sampleI]
00458                     << endl
00459                     << "    is not on a plane " << avgOffset
00460                     << " offset from the patch." << endl
00461                     << "    You might want to shift your plane offset."
00462                     << " Set the debug flag to get a dump of sampled cells."
00463                     << endl;
00464                 break;
00465             }
00466         }
00467     }
00468 
00469 
00470     // Determine schedule.
00471     mapPtr_.reset(new mapDistribute(sampleProcs, patchFaceProcs));
00472 
00473     // Rework the schedule from indices into samples to cell data to send,
00474     // face data to receive.
00475 
00476     labelListList& subMap = mapPtr_().subMap();
00477     labelListList& constructMap = mapPtr_().constructMap();
00478 
00479     forAll(subMap, procI)
00480     {
00481         subMap[procI] = UIndirectList<label>
00482         (
00483             sampleIndices,
00484             subMap[procI]
00485         );
00486         constructMap[procI] = UIndirectList<label>
00487         (
00488             patchFaces,
00489             constructMap[procI]
00490         );
00491 
00492         if (debug)
00493         {
00494             Pout<< "To proc:" << procI << " sending values of cells/faces:"
00495                 << subMap[procI] << endl;
00496             Pout<< "From proc:" << procI << " receiving values of patch faces:"
00497                 << constructMap[procI] << endl;
00498         }
00499     }
00500 
00501     // Redo constructSize
00502     mapPtr_().constructSize() = patch_.size();
00503 
00504     if (debug)
00505     {
00506         // Check that all elements get a value.
00507         PackedBoolList used(patch_.size());
00508         forAll(constructMap, procI)
00509         {
00510             const labelList& map = constructMap[procI];
00511 
00512             forAll(map, i)
00513             {
00514                 label faceI = map[i];
00515 
00516                 if (used[faceI] == 0)
00517                 {
00518                     used[faceI] = 1;
00519                 }
00520                 else
00521                 {
00522                     FatalErrorIn("directMappedPatchBase::calcMapping() const")
00523                         << "On patch " << patch_.name()
00524                         << " patchface " << faceI
00525                         << " is assigned to more than once."
00526                         << abort(FatalError);
00527                 }
00528             }
00529         }
00530         forAll(used, faceI)
00531         {
00532             if (used[faceI] == 0)
00533             {
00534                 FatalErrorIn("directMappedPatchBase::calcMapping() const")
00535                     << "On patch " << patch_.name()
00536                     << " patchface " << faceI
00537                     << " is never assigned to."
00538                     << abort(FatalError);
00539             }
00540         }
00541     }
00542 }
00543 
00544 
00545 // * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * * * * * //
00546 
00547 Foam::directMappedPatchBase::directMappedPatchBase
00548 (
00549      const polyPatch& pp
00550 )
00551 :
00552     patch_(pp),
00553     sampleRegion_(patch_.boundaryMesh().mesh().name()),
00554     mode_(NEARESTPATCHFACE),
00555     samplePatch_("none"),
00556     offset_(vector::zero),
00557     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
00558     mapPtr_(NULL)
00559 {}
00560 
00561 
00562 Foam::directMappedPatchBase::directMappedPatchBase
00563 (
00564     const polyPatch& pp,
00565     const dictionary& dict
00566 )
00567 :
00568     patch_(pp),
00569     sampleRegion_
00570     (
00571         dict.lookupOrDefault
00572         (
00573             "sampleRegion",
00574             patch_.boundaryMesh().mesh().name()
00575         )
00576     ),
00577     mode_(sampleModeNames_.read(dict.lookup("sampleMode"))),
00578     samplePatch_(dict.lookup("samplePatch")),
00579     offset_(dict.lookup("offset")),
00580     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
00581     mapPtr_(NULL)
00582 {}
00583 
00584 
00585 Foam::directMappedPatchBase::directMappedPatchBase
00586 (
00587     const polyPatch& pp,
00588     const directMappedPatchBase& dmp
00589 )
00590 :
00591     patch_(pp),
00592     sampleRegion_(dmp.sampleRegion_),
00593     mode_(dmp.mode_),
00594     samplePatch_(dmp.samplePatch_),
00595     offset_(dmp.offset_),
00596     sameRegion_(dmp.sameRegion_),
00597     mapPtr_(NULL)
00598 {}
00599 
00600 
00601 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
00602 
00603 Foam::directMappedPatchBase::~directMappedPatchBase()
00604 {
00605     clearOut();
00606 }
00607 
00608 
00609 void Foam::directMappedPatchBase::clearOut()
00610 {
00611     mapPtr_.clear();
00612 }
00613 
00614 
00615 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00616 
00617 const Foam::polyMesh& Foam::directMappedPatchBase::sampleMesh() const
00618 {
00619     return patch_.boundaryMesh().mesh().time().lookupObject<polyMesh>
00620     (
00621         sampleRegion_
00622     );
00623 }
00624 
00625 
00626 const Foam::polyPatch& Foam::directMappedPatchBase::samplePolyPatch() const
00627 {
00628     const polyMesh& nbrMesh = sampleMesh();
00629 
00630     label patchI = nbrMesh.boundaryMesh().findPatchID(samplePatch_);
00631 
00632     if (patchI == -1)
00633     {
00634         FatalErrorIn("directMappedPatchBase::samplePolyPatch() ")
00635             << "Cannot find patch " << samplePatch_
00636             << " in region " << sampleRegion_ << endl
00637             << "Valid patches are " << nbrMesh.boundaryMesh().names()
00638             << exit(FatalError);
00639     }
00640 
00641     return nbrMesh.boundaryMesh()[patchI];
00642 }
00643 
00644 
00645 void Foam::directMappedPatchBase::write(Ostream& os) const
00646 {
00647     os.writeKeyword("sampleMode") << sampleModeNames_[mode_]
00648         << token::END_STATEMENT << nl;
00649     os.writeKeyword("sampleRegion") << sampleRegion_
00650         << token::END_STATEMENT << nl;
00651     os.writeKeyword("samplePatch") << samplePatch_
00652         << token::END_STATEMENT << nl;
00653     os.writeKeyword("offset") << offset_ << token::END_STATEMENT << nl;
00654 }
00655 
00656 
00657 // ************************************************************************* //
Copyright © 2000-2009 OpenCFD Ltd