1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by 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
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"
34 #include "treeDataFace.H"
35 #include "indexedOctree.H"
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41 defineTypeNameAndDebug(directMappedPatchBase, 0);
44 const char* NamedEnum<directMappedPatchBase::sampleMode, 3>::names[] =
51 const NamedEnum<directMappedPatchBase::sampleMode, 3>
52 directMappedPatchBase::sampleModeNames_;
55 //- Private class for finding nearest
56 // - point+local index
59 typedef Tuple2<pointIndexHit, Tuple2<scalar, label> > nearInfo;
66 void operator()(nearInfo& x, const nearInfo& y) const
74 else if (y.second().first() < x.second().first())
84 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
86 void Foam::directMappedPatchBase::collectSamples
89 labelList& patchFaceProcs,
90 labelList& patchFaces,
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>
116 accessOp<pointField>()
118 patchFaces = ListListOps::combine<labelList>
121 accessOp<labelList>()
123 patchFc = ListListOps::combine<pointField>
126 accessOp<pointField>()
129 patchFaceProcs.setSize(patchFaces.size());
132 ListListOps::subSizes
135 accessOp<labelList>()
139 forAll(nPerProc, procI)
141 for (label i = 0; i < nPerProc[procI]; i++)
143 patchFaceProcs[sampleI++] = procI;
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
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());
169 if (samplePatch_.size() && samplePatch_ != "none")
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);
179 // Octree based search engine
180 meshSearch meshSearchEngine(mesh, false);
182 forAll(samples, sampleI)
184 const point& sample = samples[sampleI];
186 label cellI = meshSearchEngine.findCell(sample);
190 nearest[sampleI].second().first() = Foam::sqr(GREAT);
191 nearest[sampleI].second().second() = Pstream::myProcNo();
195 const point& cc = mesh.cellCentres()[cellI];
197 nearest[sampleI].first() = pointIndexHit
203 nearest[sampleI].second().first() = magSqr(cc-sample);
204 nearest[sampleI].second().second() = Pstream::myProcNo();
210 case NEARESTPATCHFACE:
212 Random rndGen(123456);
214 const polyPatch& pp = samplePolyPatch();
218 forAll(samples, sampleI)
220 nearest[sampleI].second().first() = Foam::sqr(GREAT);
221 nearest[sampleI].second().second() = Pstream::myProcNo();
227 const labelList patchFaces(identity(pp.size()) + pp.start());
231 treeBoundBox(pp.points(), pp.meshPoints()).extend
237 patchBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
238 patchBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
240 indexedOctree<treeDataFace> boundaryTree
242 treeDataFace // all information needed to search faces
244 false, // do not cache bb
246 patchFaces // boundary faces only
248 patchBb, // overall search domain
254 forAll(samples, sampleI)
256 const point& sample = samples[sampleI];
258 pointIndexHit& nearInfo = nearest[sampleI].first();
259 nearInfo = boundaryTree.findNearest
262 magSqr(patchBb.span())
267 nearest[sampleI].second().first() = Foam::sqr(GREAT);
268 nearest[sampleI].second().second() =
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() =
286 if (samplePatch_.size() && samplePatch_ != "none")
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);
296 // Octree based search engine
297 meshSearch meshSearchEngine(mesh, false);
299 forAll(samples, sampleI)
301 const point& sample = samples[sampleI];
303 label faceI = meshSearchEngine.findNearestFace(sample);
307 nearest[sampleI].second().first() = Foam::sqr(GREAT);
308 nearest[sampleI].second().second() = Pstream::myProcNo();
312 const point& fc = mesh.faceCentres()[faceI];
314 nearest[sampleI].first() = pointIndexHit
320 nearest[sampleI].second().first() = magSqr(fc-sample);
321 nearest[sampleI].second().second() = Pstream::myProcNo();
329 FatalErrorIn("directMappedPatchBase::findSamples(..)")
330 << "problem." << abort(FatalError);
336 Pstream::listCombineGather(nearest, nearestEqOp());
337 Pstream::listCombineScatter(nearest);
341 Info<< "directMappedPatchBase::findSamples on mesh " << sampleRegion_
343 forAll(nearest, sampleI)
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;
355 // Check for samples not being found
356 forAll(nearest, sampleI)
358 if (!nearest[sampleI].first().hit())
362 "directMappedPatchBase::findSamples"
363 "(const pointField&, labelList&"
364 ", labelList&, pointField&)"
365 ) << "Did not find sample " << samples[sampleI]
366 << " on any processor of region" << sampleRegion_
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)
379 sampleProcs[sampleI] = nearest[sampleI].second().second();
380 sampleIndices[sampleI] = nearest[sampleI].first().index();
381 sampleLocations[sampleI] = nearest[sampleI].first().hitPoint();
386 void Foam::directMappedPatchBase::calcMapping() const
390 FatalErrorIn("directMappedPatchBase::calcMapping() const")
391 << "Mapping already calculated" << exit(FatalError);
396 gAverage(mag(offsets_)) <= ROOTVSMALL
397 && mode_ == NEARESTPATCHFACE
398 && sampleRegion_ == patch_.boundaryMesh().mesh().name()
399 && samplePatch_ == patch_.name()
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;
418 // Get global list of all samples and the processor and face they come from.
420 labelList patchFaceProcs;
421 labelList patchFaces;
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.
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]
454 if (debug && Pstream::master())
458 patch_.boundaryMesh().mesh().time().path()
460 + "_directMapped.obj"
462 Pout<< "Dumping mapping as lines from patch faceCentres to"
463 << " sampled cell/faceCentres to file " << str.name() << endl;
469 meshTools::writeOBJ(str, patchFc[i]);
471 meshTools::writeOBJ(str, sampleLocations[i]);
473 str << "l " << vertI-1 << ' ' << vertI << nl;
478 //// Check that actual offset vector (sampleLocations - patchFc) is more or
480 //if (Pstream::master())
482 // const scalarField magOffset(mag(sampleLocations - patchFc));
483 // const scalar avgOffset(average(magOffset));
485 // forAll(magOffset, sampleI)
489 // mag(magOffset[sampleI]-avgOffset)
490 // > max(SMALL, 0.001*avgOffset)
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]
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."
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)
523 subMap[procI] = UIndirectList<label>
528 constructMap[procI] = UIndirectList<label>
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;
543 // Redo constructSize
544 mapPtr_().constructSize() = patch_.size();
548 // Check that all elements get a value.
549 PackedBoolList used(patch_.size());
550 forAll(constructMap, procI)
552 const labelList& map = constructMap[procI];
556 label faceI = map[i];
558 if (used[faceI] == 0)
564 FatalErrorIn("directMappedPatchBase::calcMapping() const")
565 << "On patch " << patch_.name()
566 << " patchface " << faceI
567 << " is assigned to more than once."
568 << abort(FatalError);
574 if (used[faceI] == 0)
576 FatalErrorIn("directMappedPatchBase::calcMapping() const")
577 << "On patch " << patch_.name()
578 << " patchface " << faceI
579 << " is never assigned to."
580 << abort(FatalError);
587 // * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * //
589 Foam::directMappedPatchBase::directMappedPatchBase
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()),
606 Foam::directMappedPatchBase::directMappedPatchBase
609 const word& sampleRegion,
610 const sampleMode mode,
611 const word& samplePatch,
612 const vectorField& offsets
616 sampleRegion_(sampleRegion),
618 samplePatch_(samplePatch),
619 uniformOffset_(false),
621 sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
626 Foam::directMappedPatchBase::directMappedPatchBase
629 const word& sampleRegion,
630 const sampleMode mode,
631 const word& samplePatch,
636 sampleRegion_(sampleRegion),
638 samplePatch_(samplePatch),
639 uniformOffset_(true),
642 sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
647 Foam::directMappedPatchBase::directMappedPatchBase
650 const dictionary& dict
659 patch_.boundaryMesh().mesh().name()
662 mode_(sampleModeNames_.read(dict.lookup("sampleMode"))),
663 samplePatch_(dict.lookup("samplePatch")),
664 uniformOffset_(dict.found("offset")),
668 ? point(dict.lookup("offset"))
674 ? pointField(patch_.size(), offset_)
675 : dict.lookup("offsets")
677 sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
682 Foam::directMappedPatchBase::directMappedPatchBase
685 const directMappedPatchBase& dmp
689 sampleRegion_(dmp.sampleRegion_),
691 samplePatch_(dmp.samplePatch_),
692 uniformOffset_(dmp.uniformOffset_),
693 offset_(dmp.offset_),
694 offsets_(dmp.offsets_),
695 sameRegion_(dmp.sameRegion_),
700 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
702 Foam::directMappedPatchBase::~directMappedPatchBase()
708 void Foam::directMappedPatchBase::clearOut()
714 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
716 const Foam::polyMesh& Foam::directMappedPatchBase::sampleMesh() const
718 return patch_.boundaryMesh().mesh().time().lookupObject<polyMesh>
725 const Foam::polyPatch& Foam::directMappedPatchBase::samplePolyPatch() const
727 const polyMesh& nbrMesh = sampleMesh();
729 label patchI = nbrMesh.boundaryMesh().findPatchID(samplePatch_);
733 FatalErrorIn("directMappedPatchBase::samplePolyPatch() ")
734 << "Cannot find patch " << samplePatch_
735 << " in region " << sampleRegion_ << endl
736 << "Valid patches are " << nbrMesh.boundaryMesh().names()
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;
754 os.writeKeyword("offset") << offset_ << token::END_STATEMENT << nl;
758 os.writeKeyword("offsets") << offsets_ << token::END_STATEMENT << nl;
763 // ************************************************************************* //