ENH: splitMeshRegions now fills in coupling information in directMapped patch.
[OpenFOAM-1.6.x.git] / src / meshTools / directMapped / directMappedPolyPatch / directMappedPatchBase.C
blob79db3162ce4c1140168e2bb509d19938e0103b39
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
11     OpenFOAM is free software; you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation; either version 2 of the License, or (at your
14     option) any later version.
16     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19     for more details.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM; if not, write to the Free Software Foundation,
23     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "directMappedPatchBase.H"
28 #include "addToRunTimeSelectionTable.H"
29 #include "ListListOps.H"
30 #include "meshSearch.H"
31 #include "meshTools.H"
32 #include "OFstream.H"
33 #include "Random.H"
34 #include "treeDataFace.H"
35 #include "indexedOctree.H"
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 namespace Foam
41     defineTypeNameAndDebug(directMappedPatchBase, 0);
43     template<>
44     const char* NamedEnum<directMappedPatchBase::sampleMode, 3>::names[] =
45     {
46         "nearestCell",
47         "nearestPatchFace",
48         "nearestFace"
49     };
51     const NamedEnum<directMappedPatchBase::sampleMode, 3>
52         directMappedPatchBase::sampleModeNames_;
55     //- Private class for finding nearest
56     //  - point+local index
57     //  - sqr(distance)
58     //  - processor
59     typedef Tuple2<pointIndexHit, Tuple2<scalar, label> > nearInfo;
61     class nearestEqOp
62     {
64     public:
66         void operator()(nearInfo& x, const nearInfo& y) const
67         {
68             if (y.first().hit())
69             {
70                 if (!x.first().hit())
71                 {
72                     x = y;
73                 }
74                 else if (y.second().first() < x.second().first())
75                 {
76                     x = y;
77                 }
78             }
79         }
80     };
84 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
86 void Foam::directMappedPatchBase::collectSamples
88     pointField& samples,
89     labelList& patchFaceProcs,
90     labelList& patchFaces,
91     pointField& patchFc
92 ) const
95     // Collect all sample points and the faces they come from.
96     List<pointField> globalFc(Pstream::nProcs());
97     List<pointField> globalSamples(Pstream::nProcs());
98     labelListList globalFaces(Pstream::nProcs());
100     globalFc[Pstream::myProcNo()] = patch_.faceCentres();
101     globalSamples[Pstream::myProcNo()] = globalFc[Pstream::myProcNo()]+offsets_;
102     globalFaces[Pstream::myProcNo()] = identity(patch_.size());
104     // Distribute to all processors
105     Pstream::gatherList(globalSamples);
106     Pstream::scatterList(globalSamples);
107     Pstream::gatherList(globalFaces);
108     Pstream::scatterList(globalFaces);
109     Pstream::gatherList(globalFc);
110     Pstream::scatterList(globalFc);
112     // Rework into straight list
113     samples = ListListOps::combine<pointField>
114     (
115         globalSamples,
116         accessOp<pointField>()
117     );
118     patchFaces = ListListOps::combine<labelList>
119     (
120         globalFaces,
121         accessOp<labelList>()
122     );
123     patchFc = ListListOps::combine<pointField>
124     (
125         globalFc,
126         accessOp<pointField>()
127     );
129     patchFaceProcs.setSize(patchFaces.size());
130     labelList nPerProc
131     (
132         ListListOps::subSizes
133         (
134             globalFaces,
135             accessOp<labelList>()
136         )
137     );
138     label sampleI = 0;
139     forAll(nPerProc, procI)
140     {
141         for (label i = 0; i < nPerProc[procI]; i++)
142         {
143             patchFaceProcs[sampleI++] = procI;
144         }
145     }
149 // Find the processor/cell containing the samples. Does not account
150 // for samples being found in two processors.
151 void Foam::directMappedPatchBase::findSamples
153     const pointField& samples,
154     labelList& sampleProcs,
155     labelList& sampleIndices,
156     pointField& sampleLocations
157 ) const
159     // Lookup the correct region
160     const polyMesh& mesh = sampleMesh();
162     // All the info for nearest. Construct to miss
163     List<nearInfo> nearest(samples.size());
165     switch (mode_)
166     {
167         case NEARESTCELL:
168         {
169             if (samplePatch_.size() && samplePatch_ != "none")
170             {
171                 FatalErrorIn
172                 (
173                     "directMappedPatchBase::findSamples(const pointField&,"
174                     " labelList&, labelList&, pointField&) const"
175                 )   << "No need to supply a patch name when in "
176                     << sampleModeNames_[mode_] << " mode." << exit(FatalError);
177             }
179             // Octree based search engine
180             meshSearch meshSearchEngine(mesh, false);
182             forAll(samples, sampleI)
183             {
184                 const point& sample = samples[sampleI];
186                 label cellI = meshSearchEngine.findCell(sample);
188                 if (cellI == -1)
189                 {
190                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
191                     nearest[sampleI].second().second() = Pstream::myProcNo();
192                 }
193                 else
194                 {
195                     const point& cc = mesh.cellCentres()[cellI];
197                     nearest[sampleI].first() = pointIndexHit
198                     (
199                         true,
200                         cc,
201                         cellI
202                     );
203                     nearest[sampleI].second().first() = magSqr(cc-sample);
204                     nearest[sampleI].second().second() = Pstream::myProcNo();
205                 }
206             }
207             break;
208         }
210         case NEARESTPATCHFACE:
211         {
212             Random rndGen(123456);
214             const polyPatch& pp = samplePolyPatch();
216             if (pp.empty())
217             {
218                 forAll(samples, sampleI)
219                 {
220                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
221                     nearest[sampleI].second().second() = Pstream::myProcNo();
222                 }
223             }
224             else
225             {
226                 // patch faces
227                 const labelList patchFaces(identity(pp.size()) + pp.start());
229                 treeBoundBox patchBb
230                 (
231                     treeBoundBox(pp.points(), pp.meshPoints()).extend
232                     (
233                         rndGen,
234                         1E-4
235                     )
236                 );
237                 patchBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
238                 patchBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
240                 indexedOctree<treeDataFace> boundaryTree
241                 (
242                     treeDataFace    // all information needed to search faces
243                     (
244                         false,      // do not cache bb
245                         mesh,
246                         patchFaces  // boundary faces only
247                     ),
248                     patchBb,        // overall search domain
249                     8,              // maxLevel
250                     10,             // leafsize
251                     3.0             // duplicity
252                 );
254                 forAll(samples, sampleI)
255                 {
256                     const point& sample = samples[sampleI];
258                     pointIndexHit& nearInfo = nearest[sampleI].first();
259                     nearInfo = boundaryTree.findNearest
260                     (
261                         sample,
262                         magSqr(patchBb.span())
263                     );
265                     if (!nearInfo.hit())
266                     {
267                         nearest[sampleI].second().first() = Foam::sqr(GREAT);
268                         nearest[sampleI].second().second() =
269                             Pstream::myProcNo();
270                     }
271                     else
272                     {
273                         point fc(pp[nearInfo.index()].centre(pp.points()));
274                         nearInfo.setPoint(fc);
275                         nearest[sampleI].second().first() = magSqr(fc-sample);
276                         nearest[sampleI].second().second() =
277                             Pstream::myProcNo();
278                     }
279                 }
280             }
281             break;
282         }
284         case NEARESTFACE:
285         {
286             if (samplePatch_.size() && samplePatch_ != "none")
287             {
288                 FatalErrorIn
289                 (
290                     "directMappedPatchBase::findSamples(const pointField&,"
291                     " labelList&, labelList&, pointField&) const"
292                 )   << "No need to supply a patch name when in "
293                     << sampleModeNames_[mode_] << " mode." << exit(FatalError);
294             }
296             // Octree based search engine
297             meshSearch meshSearchEngine(mesh, false);
299             forAll(samples, sampleI)
300             {
301                 const point& sample = samples[sampleI];
303                 label faceI = meshSearchEngine.findNearestFace(sample);
305                 if (faceI == -1)
306                 {
307                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
308                     nearest[sampleI].second().second() = Pstream::myProcNo();
309                 }
310                 else
311                 {
312                     const point& fc = mesh.faceCentres()[faceI];
314                     nearest[sampleI].first() = pointIndexHit
315                     (
316                         true,
317                         fc,
318                         faceI
319                     );
320                     nearest[sampleI].second().first() = magSqr(fc-sample);
321                     nearest[sampleI].second().second() = Pstream::myProcNo();
322                 }
323             }
324             break;
325         }
327         default:
328         {
329             FatalErrorIn("directMappedPatchBase::findSamples(..)")
330                 << "problem." << abort(FatalError);
331         }
332     }
335     // Find nearest.
336     Pstream::listCombineGather(nearest, nearestEqOp());
337     Pstream::listCombineScatter(nearest);
339     if (debug)
340     {
341         Info<< "directMappedPatchBase::findSamples on mesh " << sampleRegion_
342             << " : " << endl;
343         forAll(nearest, sampleI)
344         {
345             label procI = nearest[sampleI].second().second();
346             label localI = nearest[sampleI].first().index();
348             Info<< "    " << sampleI << " coord:"<< samples[sampleI]
349                 << " found on processor:" << procI
350                 << " in local cell/face:" << localI
351                 << " with cc:" << nearest[sampleI].first().rawPoint() << endl;
352         }
353     }
355     // Check for samples not being found
356     forAll(nearest, sampleI)
357     {
358         if (!nearest[sampleI].first().hit())
359         {
360             FatalErrorIn
361             (
362                 "directMappedPatchBase::findSamples"
363                 "(const pointField&, labelList&"
364                 ", labelList&, pointField&)"
365             )   << "Did not find sample " << samples[sampleI]
366                 << " on any processor of region" << sampleRegion_
367                 << exit(FatalError);
368         }
369     }
372     // Convert back into proc+local index
373     sampleProcs.setSize(samples.size());
374     sampleIndices.setSize(samples.size());
375     sampleLocations.setSize(samples.size());
377     forAll(nearest, sampleI)
378     {
379         sampleProcs[sampleI] = nearest[sampleI].second().second();
380         sampleIndices[sampleI] = nearest[sampleI].first().index();
381         sampleLocations[sampleI] = nearest[sampleI].first().hitPoint();
382     }
386 void Foam::directMappedPatchBase::calcMapping() const
388     if (mapPtr_.valid())
389     {
390         FatalErrorIn("directMappedPatchBase::calcMapping() const")
391             << "Mapping already calculated" << exit(FatalError);
392     }
394     if
395     (
396         gAverage(mag(offsets_)) <= ROOTVSMALL
397      && mode_ == NEARESTPATCHFACE
398      && sampleRegion_ == patch_.boundaryMesh().mesh().name()
399      && samplePatch_ == patch_.name()
400     )
401     {
402         WarningIn("directMappedPatchBase::calcMapping() const")
403             << "Invalid offset " << offsets_ << endl
404             << "Offset is the vector added to the patch face centres to"
405             << " find the patch face supplying the data." << endl
406             << "Setting it to " << offsets_
407             << " on the same patch, on the same region"
408             << " will find the faces themselves which does not make sense"
409             << " for anything but testing." << endl
410             << "patch_:" << patch_.name() << endl
411             << "sampleRegion_:" << sampleRegion_ << endl
412             << "mode_:" << sampleModeNames_[mode_] << endl
413             << "samplePatch_:" << samplePatch_ << endl
414             << "offsets_:" << offsets_ << endl;
415     }
418     // Get global list of all samples and the processor and face they come from.
419     pointField samples;
420     labelList patchFaceProcs;
421     labelList patchFaces;
422     pointField patchFc;
423     collectSamples(samples, patchFaceProcs, patchFaces, patchFc);
425     // Find processor and cell/face samples are in and actual location.
426     labelList sampleProcs;
427     labelList sampleIndices;
428     pointField sampleLocations;
429     findSamples(samples, sampleProcs, sampleIndices, sampleLocations);
432     // Now we have all the data we need:
433     // - where sample originates from (so destination when mapping):
434     //   patchFaces, patchFaceProcs.
435     // - cell/face sample is in (so source when mapping)
436     //   sampleIndices, sampleProcs.
438     //forAll(samples, i)
439     //{
440     //    Info<< i << " need data in region "
441     //        << patch_.boundaryMesh().mesh().name()
442     //        << " for proc:" << patchFaceProcs[i]
443     //        << " face:" << patchFaces[i]
444     //        << " at:" << patchFc[i] << endl
445     //        << "Found data in region " << sampleRegion_
446     //        << " at proc:" << sampleProcs[i]
447     //        << " face:" << sampleIndices[i]
448     //        << " at:" << sampleLocations[i]
449     //        << nl << endl;
450     //}
454     if (debug && Pstream::master())
455     {
456         OFstream str
457         (
458             patch_.boundaryMesh().mesh().time().path()
459           / patch_.name()
460           + "_directMapped.obj"
461         );
462         Pout<< "Dumping mapping as lines from patch faceCentres to"
463             << " sampled cell/faceCentres to file " << str.name() << endl;
465         label vertI = 0;
467         forAll(patchFc, i)
468         {
469             meshTools::writeOBJ(str, patchFc[i]);
470             vertI++;
471             meshTools::writeOBJ(str, sampleLocations[i]);
472             vertI++;
473             str << "l " << vertI-1 << ' ' << vertI << nl;
474         }
475     }
478     //// Check that actual offset vector (sampleLocations - patchFc) is more or
479     //// less constant.
480     //if (Pstream::master())
481     //{
482     //    const scalarField magOffset(mag(sampleLocations - patchFc));
483     //    const scalar avgOffset(average(magOffset));
484     //
485     //    forAll(magOffset, sampleI)
486     //    {
487     //        if
488     //        (
489     //            mag(magOffset[sampleI]-avgOffset)
490     //          > max(SMALL, 0.001*avgOffset)
491     //        )
492     //        {
493     //            WarningIn("directMappedPatchBase::calcMapping() const")
494     //                << "The actual cell/face centres picked up using offset "
495     //                << offsets_ << " are not" << endl
496     //                << "    on a single plane."
497     //                << " This might give numerical problems." << endl
498     //                << "    At patchface " << patchFc[sampleI]
499     //                << " the sampled cell/face " << sampleLocations[sampleI]
500     //                << endl
501     //                << "    is not on a plane " << avgOffset
502     //                << " offset from the patch." << endl
503     //                << "    You might want to shift your plane offset."
504     //                << " Set the debug flag to get a dump of sampled cells."
505     //                << endl;
506     //            break;
507     //        }
508     //    }
509     //}
512     // Determine schedule.
513     mapPtr_.reset(new mapDistribute(sampleProcs, patchFaceProcs));
515     // Rework the schedule from indices into samples to cell data to send,
516     // face data to receive.
518     labelListList& subMap = mapPtr_().subMap();
519     labelListList& constructMap = mapPtr_().constructMap();
521     forAll(subMap, procI)
522     {
523         subMap[procI] = UIndirectList<label>
524         (
525             sampleIndices,
526             subMap[procI]
527         );
528         constructMap[procI] = UIndirectList<label>
529         (
530             patchFaces,
531             constructMap[procI]
532         );
534         if (debug)
535         {
536             Pout<< "To proc:" << procI << " sending values of cells/faces:"
537                 << subMap[procI] << endl;
538             Pout<< "From proc:" << procI << " receiving values of patch faces:"
539                 << constructMap[procI] << endl;
540         }
541     }
543     // Redo constructSize
544     mapPtr_().constructSize() = patch_.size();
546     if (debug)
547     {
548         // Check that all elements get a value.
549         PackedBoolList used(patch_.size());
550         forAll(constructMap, procI)
551         {
552             const labelList& map = constructMap[procI];
554             forAll(map, i)
555             {
556                 label faceI = map[i];
558                 if (used[faceI] == 0)
559                 {
560                     used[faceI] = 1;
561                 }
562                 else
563                 {
564                     FatalErrorIn("directMappedPatchBase::calcMapping() const")
565                         << "On patch " << patch_.name()
566                         << " patchface " << faceI
567                         << " is assigned to more than once."
568                         << abort(FatalError);
569                 }
570             }
571         }
572         forAll(used, faceI)
573         {
574             if (used[faceI] == 0)
575             {
576                 FatalErrorIn("directMappedPatchBase::calcMapping() const")
577                     << "On patch " << patch_.name()
578                     << " patchface " << faceI
579                     << " is never assigned to."
580                     << abort(FatalError);
581             }
582         }
583     }
587 // * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * * * * * //
589 Foam::directMappedPatchBase::directMappedPatchBase
591     const polyPatch& pp
594     patch_(pp),
595     sampleRegion_(patch_.boundaryMesh().mesh().name()),
596     mode_(NEARESTPATCHFACE),
597     samplePatch_("none"),
598     uniformOffset_(true),
599     offset_(vector::zero),
600     offsets_(pp.size(), offset_),
601     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
602     mapPtr_(NULL)
606 Foam::directMappedPatchBase::directMappedPatchBase
608     const polyPatch& pp,
609     const word& sampleRegion,
610     const sampleMode mode,
611     const word& samplePatch,
612     const vectorField& offsets
615     patch_(pp),
616     sampleRegion_(sampleRegion),
617     mode_(mode),
618     samplePatch_(samplePatch),
619     uniformOffset_(false),
620     offsets_(offsets),
621     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
622     mapPtr_(NULL)
626 Foam::directMappedPatchBase::directMappedPatchBase
628     const polyPatch& pp,
629     const word& sampleRegion,
630     const sampleMode mode,
631     const word& samplePatch,
632     const vector& offset
635     patch_(pp),
636     sampleRegion_(sampleRegion),
637     mode_(mode),
638     samplePatch_(samplePatch),
639     uniformOffset_(true),
640     offset_(offset),
641     offsets_(0),
642     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
643     mapPtr_(NULL)
647 Foam::directMappedPatchBase::directMappedPatchBase
649     const polyPatch& pp,
650     const dictionary& dict
653     patch_(pp),
654     sampleRegion_
655     (
656         dict.lookupOrDefault
657         (
658             "sampleRegion",
659             patch_.boundaryMesh().mesh().name()
660         )
661     ),
662     mode_(sampleModeNames_.read(dict.lookup("sampleMode"))),
663     samplePatch_(dict.lookup("samplePatch")),
664     uniformOffset_(dict.found("offset")),
665     offset_
666     (
667         uniformOffset_
668       ? point(dict.lookup("offset"))
669       : vector::zero
670     ),
671     offsets_
672     (
673         uniformOffset_
674       ? pointField(patch_.size(), offset_)
675       : dict.lookup("offsets")
676     ),
677     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
678     mapPtr_(NULL)
682 Foam::directMappedPatchBase::directMappedPatchBase
684     const polyPatch& pp,
685     const directMappedPatchBase& dmp
688     patch_(pp),
689     sampleRegion_(dmp.sampleRegion_),
690     mode_(dmp.mode_),
691     samplePatch_(dmp.samplePatch_),
692     uniformOffset_(dmp.uniformOffset_),
693     offset_(dmp.offset_),
694     offsets_(dmp.offsets_),
695     sameRegion_(dmp.sameRegion_),
696     mapPtr_(NULL)
700 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
702 Foam::directMappedPatchBase::~directMappedPatchBase()
704     clearOut();
708 void Foam::directMappedPatchBase::clearOut()
710     mapPtr_.clear();
714 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
716 const Foam::polyMesh& Foam::directMappedPatchBase::sampleMesh() const
718     return patch_.boundaryMesh().mesh().time().lookupObject<polyMesh>
719     (
720         sampleRegion_
721     );
725 const Foam::polyPatch& Foam::directMappedPatchBase::samplePolyPatch() const
727     const polyMesh& nbrMesh = sampleMesh();
729     label patchI = nbrMesh.boundaryMesh().findPatchID(samplePatch_);
731     if (patchI == -1)
732     {
733         FatalErrorIn("directMappedPatchBase::samplePolyPatch() ")
734             << "Cannot find patch " << samplePatch_
735             << " in region " << sampleRegion_ << endl
736             << "Valid patches are " << nbrMesh.boundaryMesh().names()
737             << exit(FatalError);
738     }
740     return nbrMesh.boundaryMesh()[patchI];
744 void Foam::directMappedPatchBase::write(Ostream& os) const
746     os.writeKeyword("sampleMode") << sampleModeNames_[mode_]
747         << token::END_STATEMENT << nl;
748     os.writeKeyword("sampleRegion") << sampleRegion_
749         << token::END_STATEMENT << nl;
750     os.writeKeyword("samplePatch") << samplePatch_
751         << token::END_STATEMENT << nl;
752     if (uniformOffset_)
753     {
754         os.writeKeyword("offset") << offset_ << token::END_STATEMENT << nl;
755     }
756     else
757     {
758         os.writeKeyword("offsets") << offsets_ << token::END_STATEMENT << nl;
759     }
763 // ************************************************************************* //