1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "directMappedPatchBase.H"
27 #include "addToRunTimeSelectionTable.H"
28 #include "ListListOps.H"
29 #include "meshSearch.H"
30 #include "meshTools.H"
33 #include "treeDataFace.H"
34 #include "indexedOctree.H"
36 #include "polyPatch.H"
38 #include "mapDistribute.H"
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
45 defineTypeNameAndDebug(directMappedPatchBase, 0);
48 const char* Foam::NamedEnum
50 Foam::directMappedPatchBase::sampleMode,
60 const char* Foam::NamedEnum
62 Foam::directMappedPatchBase::offsetMode,
73 const Foam::NamedEnum<Foam::directMappedPatchBase::sampleMode, 3>
74 Foam::directMappedPatchBase::sampleModeNames_;
76 const Foam::NamedEnum<Foam::directMappedPatchBase::offsetMode, 3>
77 Foam::directMappedPatchBase::offsetModeNames_;
80 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
82 void Foam::directMappedPatchBase::collectSamples
85 labelList& patchFaceProcs,
86 labelList& patchFaces,
91 // Collect all sample points and the faces they come from.
92 List<pointField> globalFc(Pstream::nProcs());
93 List<pointField> globalSamples(Pstream::nProcs());
94 labelListList globalFaces(Pstream::nProcs());
96 globalFc[Pstream::myProcNo()] = patch_.faceCentres();
97 globalSamples[Pstream::myProcNo()] = samplePoints();
98 globalFaces[Pstream::myProcNo()] = identity(patch_.size());
100 // Distribute to all processors
101 Pstream::gatherList(globalSamples);
102 Pstream::scatterList(globalSamples);
103 Pstream::gatherList(globalFaces);
104 Pstream::scatterList(globalFaces);
105 Pstream::gatherList(globalFc);
106 Pstream::scatterList(globalFc);
108 // Rework into straight list
109 samples = ListListOps::combine<pointField>
112 accessOp<pointField>()
114 patchFaces = ListListOps::combine<labelList>
117 accessOp<labelList>()
119 patchFc = ListListOps::combine<pointField>
122 accessOp<pointField>()
125 patchFaceProcs.setSize(patchFaces.size());
128 ListListOps::subSizes
131 accessOp<labelList>()
135 forAll(nPerProc, procI)
137 for (label i = 0; i < nPerProc[procI]; i++)
139 patchFaceProcs[sampleI++] = procI;
145 // Find the processor/cell containing the samples. Does not account
146 // for samples being found in two processors.
147 void Foam::directMappedPatchBase::findSamples
149 const pointField& samples,
150 labelList& sampleProcs,
151 labelList& sampleIndices,
152 pointField& sampleLocations
155 // Lookup the correct region
156 const polyMesh& mesh = sampleMesh();
158 // All the info for nearest. Construct to miss
159 List<nearInfo> nearest(samples.size());
165 if (samplePatch_.size() && samplePatch_ != "none")
169 "directMappedPatchBase::findSamples(const pointField&,"
170 " labelList&, labelList&, pointField&) const"
171 ) << "No need to supply a patch name when in "
172 << sampleModeNames_[mode_] << " mode." << exit(FatalError);
175 // Octree based search engine. Uses min tetDecomp so force
177 (void)mesh.tetBasePtIs();
178 meshSearch meshSearchEngine(mesh, false);
180 forAll(samples, sampleI)
182 const point& sample = samples[sampleI];
184 label cellI = meshSearchEngine.findCell(sample);
188 nearest[sampleI].second().first() = Foam::sqr(GREAT);
189 nearest[sampleI].second().second() = Pstream::myProcNo();
193 const point& cc = mesh.cellCentres()[cellI];
195 nearest[sampleI].first() = pointIndexHit
201 nearest[sampleI].second().first() = magSqr(cc-sample);
202 nearest[sampleI].second().second() = Pstream::myProcNo();
208 case NEARESTPATCHFACE:
210 Random rndGen(123456);
212 const polyPatch& pp = samplePolyPatch();
216 forAll(samples, sampleI)
218 nearest[sampleI].second().first() = Foam::sqr(GREAT);
219 nearest[sampleI].second().second() = Pstream::myProcNo();
225 const labelList patchFaces(identity(pp.size()) + pp.start());
229 treeBoundBox(pp.points(), pp.meshPoints()).extend
235 patchBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
236 patchBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
238 indexedOctree<treeDataFace> boundaryTree
240 treeDataFace // all information needed to search faces
242 false, // do not cache bb
244 patchFaces // boundary faces only
246 patchBb, // overall search domain
252 forAll(samples, sampleI)
254 const point& sample = samples[sampleI];
256 pointIndexHit& nearInfo = nearest[sampleI].first();
257 nearInfo = boundaryTree.findNearest
260 magSqr(patchBb.span())
265 nearest[sampleI].second().first() = Foam::sqr(GREAT);
266 nearest[sampleI].second().second() =
271 point fc(pp[nearInfo.index()].centre(pp.points()));
272 nearInfo.setPoint(fc);
273 nearest[sampleI].second().first() = magSqr(fc-sample);
274 nearest[sampleI].second().second() =
284 if (samplePatch_.size() && samplePatch_ != "none")
288 "directMappedPatchBase::findSamples(const pointField&,"
289 " labelList&, labelList&, pointField&) const"
290 ) << "No need to supply a patch name when in "
291 << sampleModeNames_[mode_] << " mode." << exit(FatalError);
294 // Octree based search engine
295 meshSearch meshSearchEngine(mesh, false);
297 forAll(samples, sampleI)
299 const point& sample = samples[sampleI];
301 label faceI = meshSearchEngine.findNearestFace(sample);
305 nearest[sampleI].second().first() = Foam::sqr(GREAT);
306 nearest[sampleI].second().second() = Pstream::myProcNo();
310 const point& fc = mesh.faceCentres()[faceI];
312 nearest[sampleI].first() = pointIndexHit
318 nearest[sampleI].second().first() = magSqr(fc-sample);
319 nearest[sampleI].second().second() = Pstream::myProcNo();
327 FatalErrorIn("directMappedPatchBase::findSamples(..)")
328 << "problem." << abort(FatalError);
334 Pstream::listCombineGather(nearest, nearestEqOp());
335 Pstream::listCombineScatter(nearest);
339 Info<< "directMappedPatchBase::findSamples on mesh " << sampleRegion_
341 forAll(nearest, sampleI)
343 label procI = nearest[sampleI].second().second();
344 label localI = nearest[sampleI].first().index();
346 Info<< " " << sampleI << " coord:"<< samples[sampleI]
347 << " found on processor:" << procI
348 << " in local cell/face:" << localI
349 << " with cc:" << nearest[sampleI].first().rawPoint() << endl;
353 // Check for samples not being found
354 forAll(nearest, sampleI)
356 if (!nearest[sampleI].first().hit())
360 "directMappedPatchBase::findSamples"
361 "(const pointField&, labelList&"
362 ", labelList&, pointField&)"
363 ) << "Did not find sample " << samples[sampleI]
364 << " on any processor of region " << sampleRegion_
370 // Convert back into proc+local index
371 sampleProcs.setSize(samples.size());
372 sampleIndices.setSize(samples.size());
373 sampleLocations.setSize(samples.size());
375 forAll(nearest, sampleI)
377 sampleProcs[sampleI] = nearest[sampleI].second().second();
378 sampleIndices[sampleI] = nearest[sampleI].first().index();
379 sampleLocations[sampleI] = nearest[sampleI].first().hitPoint();
384 void Foam::directMappedPatchBase::calcMapping() const
388 FatalErrorIn("directMappedPatchBase::calcMapping() const")
389 << "Mapping already calculated" << exit(FatalError);
393 // Am I sampling my own patch? This only makes sense for a non-zero
397 mode_ == NEARESTPATCHFACE
398 && sampleRegion_ == patch_.boundaryMesh().mesh().name()
399 && samplePatch_ == patch_.name()
403 vectorField d(samplePoints()-patch_.faceCentres());
404 if (sampleMyself && gAverage(mag(d)) <= ROOTVSMALL)
408 "directMappedPatchBase::directMappedPatchBase\n"
410 " const polyPatch& pp,\n"
411 " const word& sampleRegion,\n"
412 " const sampleMode mode,\n"
413 " const word& samplePatch,\n"
414 " const vector& offset\n"
416 ) << "Invalid offset " << d << endl
417 << "Offset is the vector added to the patch face centres to"
418 << " find the patch face supplying the data." << endl
419 << "Setting it to " << d
420 << " on the same patch, on the same region"
421 << " will find the faces themselves which does not make sense"
422 << " for anything but testing." << endl
423 << "patch_:" << patch_.name() << endl
424 << "sampleRegion_:" << sampleRegion_ << endl
425 << "mode_:" << sampleModeNames_[mode_] << endl
426 << "samplePatch_:" << samplePatch_ << endl
427 << "offsetMode_:" << offsetModeNames_[offsetMode_] << endl;
432 // Get global list of all samples and the processor and face they come from.
434 labelList patchFaceProcs;
435 labelList patchFaces;
437 collectSamples(samples, patchFaceProcs, patchFaces, patchFc);
439 // Find processor and cell/face samples are in and actual location.
440 labelList sampleProcs;
441 labelList sampleIndices;
442 pointField sampleLocations;
443 findSamples(samples, sampleProcs, sampleIndices, sampleLocations);
446 // Now we have all the data we need:
447 // - where sample originates from (so destination when mapping):
448 // patchFaces, patchFaceProcs.
449 // - cell/face sample is in (so source when mapping)
450 // sampleIndices, sampleProcs.
454 // Info<< i << " need data in region "
455 // << patch_.boundaryMesh().mesh().name()
456 // << " for proc:" << patchFaceProcs[i]
457 // << " face:" << patchFaces[i]
458 // << " at:" << patchFc[i] << endl
459 // << "Found data in region " << sampleRegion_
460 // << " at proc:" << sampleProcs[i]
461 // << " face:" << sampleIndices[i]
462 // << " at:" << sampleLocations[i]
468 if (debug && Pstream::master())
472 patch_.boundaryMesh().mesh().time().path()
474 + "_directMapped.obj"
476 Pout<< "Dumping mapping as lines from patch faceCentres to"
477 << " sampled cell/faceCentres to file " << str.name() << endl;
483 meshTools::writeOBJ(str, patchFc[i]);
485 meshTools::writeOBJ(str, sampleLocations[i]);
487 str << "l " << vertI-1 << ' ' << vertI << nl;
492 // Determine schedule.
493 mapPtr_.reset(new mapDistribute(sampleProcs, patchFaceProcs));
495 // Rework the schedule from indices into samples to cell data to send,
496 // face data to receive.
498 labelListList& subMap = mapPtr_().subMap();
499 labelListList& constructMap = mapPtr_().constructMap();
501 forAll(subMap, procI)
503 subMap[procI] = UIndirectList<label>
508 constructMap[procI] = UIndirectList<label>
516 // Pout<< "To proc:" << procI << " sending values of cells/faces:"
517 // << subMap[procI] << endl;
518 // Pout<< "From proc:" << procI
519 // << " receiving values of patch faces:"
520 // << constructMap[procI] << endl;
524 // Redo constructSize
525 mapPtr_().constructSize() = patch_.size();
529 // Check that all elements get a value.
530 PackedBoolList used(patch_.size());
531 forAll(constructMap, procI)
533 const labelList& map = constructMap[procI];
537 label faceI = map[i];
539 if (used[faceI] == 0)
545 FatalErrorIn("directMappedPatchBase::calcMapping() const")
546 << "On patch " << patch_.name()
547 << " patchface " << faceI
548 << " is assigned to more than once."
549 << abort(FatalError);
555 if (used[faceI] == 0)
557 FatalErrorIn("directMappedPatchBase::calcMapping() const")
558 << "On patch " << patch_.name()
559 << " patchface " << faceI
560 << " is never assigned to."
561 << abort(FatalError);
568 // * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * //
570 Foam::directMappedPatchBase::directMappedPatchBase
576 sampleRegion_(patch_.boundaryMesh().mesh().name()),
577 mode_(NEARESTPATCHFACE),
578 samplePatch_("none"),
579 offsetMode_(UNIFORM),
580 offset_(vector::zero),
581 offsets_(pp.size(), offset_),
583 sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
588 Foam::directMappedPatchBase::directMappedPatchBase
591 const word& sampleRegion,
592 const sampleMode mode,
593 const word& samplePatch,
594 const vectorField& offsets
598 sampleRegion_(sampleRegion),
600 samplePatch_(samplePatch),
601 offsetMode_(NONUNIFORM),
602 offset_(vector::zero),
605 sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
610 Foam::directMappedPatchBase::directMappedPatchBase
613 const word& sampleRegion,
614 const sampleMode mode,
615 const word& samplePatch,
620 sampleRegion_(sampleRegion),
622 samplePatch_(samplePatch),
623 offsetMode_(UNIFORM),
627 sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
632 Foam::directMappedPatchBase::directMappedPatchBase
635 const word& sampleRegion,
636 const sampleMode mode,
637 const word& samplePatch,
638 const scalar distance
642 sampleRegion_(sampleRegion),
644 samplePatch_(samplePatch),
646 offset_(vector::zero),
649 sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
654 Foam::directMappedPatchBase::directMappedPatchBase
657 const dictionary& dict
666 patch_.boundaryMesh().mesh().name()
669 mode_(sampleModeNames_.read(dict.lookup("sampleMode"))),
670 samplePatch_(dict.lookup("samplePatch")),
671 offsetMode_(UNIFORM),
672 offset_(vector::zero),
675 sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
678 if (dict.found("offsetMode"))
680 offsetMode_ = offsetModeNames_.read(dict.lookup("offsetMode"));
686 offset_ = point(dict.lookup("offset"));
692 offsets_ = pointField(dict.lookup("offsets"));
698 distance_ = readScalar(dict.lookup("distance"));
703 else if (dict.found("offset"))
705 offsetMode_ = UNIFORM;
706 offset_ = point(dict.lookup("offset"));
708 else if (dict.found("offsets"))
710 offsetMode_ = NONUNIFORM;
711 offsets_ = pointField(dict.lookup("offsets"));
717 "directMappedPatchBase::directMappedPatchBase\n"
719 " const polyPatch& pp,\n"
720 " const dictionary& dict\n"
723 ) << "Please supply the offsetMode as one of "
724 << NamedEnum<offsetMode, 3>::words()
725 << exit(FatalIOError);
730 Foam::directMappedPatchBase::directMappedPatchBase
733 const directMappedPatchBase& dmp
737 sampleRegion_(dmp.sampleRegion_),
739 samplePatch_(dmp.samplePatch_),
740 offsetMode_(dmp.offsetMode_),
741 offset_(dmp.offset_),
742 offsets_(dmp.offsets_),
743 distance_(dmp.distance_),
744 sameRegion_(dmp.sameRegion_),
749 Foam::directMappedPatchBase::directMappedPatchBase
752 const directMappedPatchBase& dmp,
753 const labelUList& mapAddressing
757 sampleRegion_(dmp.sampleRegion_),
759 samplePatch_(dmp.samplePatch_),
760 offsetMode_(dmp.offsetMode_),
761 offset_(dmp.offset_),
762 offsets_(dmp.offsets_, mapAddressing),
763 distance_(dmp.distance_),
764 sameRegion_(dmp.sameRegion_),
769 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
771 Foam::directMappedPatchBase::~directMappedPatchBase()
777 void Foam::directMappedPatchBase::clearOut()
783 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
785 const Foam::polyMesh& Foam::directMappedPatchBase::sampleMesh() const
787 return patch_.boundaryMesh().mesh().time().lookupObject<polyMesh>
794 const Foam::polyPatch& Foam::directMappedPatchBase::samplePolyPatch() const
796 const polyMesh& nbrMesh = sampleMesh();
798 const label patchI = nbrMesh.boundaryMesh().findPatchID(samplePatch_);
802 FatalErrorIn("directMappedPatchBase::samplePolyPatch() ")
803 << "Cannot find patch " << samplePatch_
804 << " in region " << sampleRegion_ << endl
805 << "Valid patches are " << nbrMesh.boundaryMesh().names()
809 return nbrMesh.boundaryMesh()[patchI];
813 Foam::tmp<Foam::pointField> Foam::directMappedPatchBase::samplePoints() const
815 tmp<pointField> tfld(new pointField(patch_.faceCentres()));
816 pointField& fld = tfld();
834 // Get outwards pointing normal
835 vectorField n(patch_.faceAreas());
847 void Foam::directMappedPatchBase::write(Ostream& os) const
849 os.writeKeyword("sampleMode") << sampleModeNames_[mode_]
850 << token::END_STATEMENT << nl;
851 os.writeKeyword("sampleRegion") << sampleRegion_
852 << token::END_STATEMENT << nl;
853 os.writeKeyword("samplePatch") << samplePatch_
854 << token::END_STATEMENT << nl;
856 os.writeKeyword("offsetMode") << offsetModeNames_[offsetMode_]
857 << token::END_STATEMENT << nl;
863 os.writeKeyword("offset") << offset_ << token::END_STATEMENT << nl;
869 os.writeKeyword("offsets") << offsets_ << token::END_STATEMENT
876 os.writeKeyword("distance") << distance_ << token::END_STATEMENT
884 // ************************************************************************* //