Forward compatibility: flex
[foam-extend-3.2.git] / src / dynamicMesh / dynamicTopoFvMesh / fieldMapping / topoPatchMapper.C
blob7352b5f8a2b6fe73ebfe34b0bf7024a2477d0e5d
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend 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 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 Class
25     topoPatchMapper
27 Description
28     Implementation of the topoPatchMapper class
30 Author
31     Sandeep Menon
32     University of Massachusetts Amherst
33     All rights reserved
35 \*---------------------------------------------------------------------------*/
37 #include "IOmanip.H"
38 #include "meshOps.H"
39 #include "topoMapper.H"
40 #include "mapPolyMesh.H"
41 #include "topoPatchMapper.H"
42 #include "demandDrivenData.H"
44 namespace Foam
47 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
49 //- Clear out local storage
50 void topoPatchMapper::clearOut()
52     deleteDemandDrivenData(directAddrPtr_);
53     deleteDemandDrivenData(interpolationAddrPtr_);
54     deleteDemandDrivenData(weightsPtr_);
55     deleteDemandDrivenData(insertedFaceLabelsPtr_);
56     deleteDemandDrivenData(insertedFaceIndexMapPtr_);
57     deleteDemandDrivenData(insertedFaceAddressingPtr_);
58     deleteDemandDrivenData(areasPtr_);
59     deleteDemandDrivenData(centresPtr_);
63 //- Calculate the insertedFaceLabels list
64 void topoPatchMapper::calcInsertedFaceAddressing() const
66     if (insertedFaceLabelsPtr_ || insertedFaceAddressingPtr_)
67     {
68         FatalErrorIn
69         (
70             "void topoPatchMapper::calcInsertedFaceAddressing() const"
71         )   << " Inserted labels has already been calculated."
72             << abort(FatalError);
73     }
75     // Information from the old patch
76     const label oldPatchSize = sizeBeforeMapping();
77     const label oldPatchStart = mpm_.oldPatchStarts()[patch_.index()];
79     if (oldPatchSize == 0)
80     {
81         // Nothing to map from. Return empty.
82         insertedFaceLabelsPtr_ = new labelList(0);
83         insertedFaceIndexMapPtr_ = new labelList(0);
84         insertedFaceAddressingPtr_ = new labelListList(0);
85         return;
86     }
88     // Allocate for inserted face labels and addressing
89     label nInsertedFaces = 0;
91     insertedFaceLabelsPtr_ = new labelList(patchSize(), -1);
92     labelList& insertedFaces = *insertedFaceLabelsPtr_;
94     insertedFaceIndexMapPtr_ = new labelList(patchSize(), -1);
95     labelList& insertedFacesMap = *insertedFaceIndexMapPtr_;
97     insertedFaceAddressingPtr_ = new labelListList(patchSize(), labelList(0));
98     labelListList& insertedAddressing = *insertedFaceAddressingPtr_;
100     // Fetch current patch start
101     label pStart = patch_.patch().start();
103     // Fetch the current boundary
104     const polyBoundaryMesh& boundary = mpm_.mesh().boundaryMesh();
106     // Loop through the facesFromFaces map, and ensure that
107     // inserted faces are only mapped from faces on the same patch.
108     const List<objectMap>& fff = mpm_.facesFromFacesMap();
110     forAll(fff, objectI)
111     {
112         const objectMap& fffI = fff[objectI];
114         // Only pick boundary faces in this patch
115         if (boundary.whichPatch(fffI.index()) == patch_.index())
116         {
117             if (fffI.masterObjects().empty())
118             {
119                 // Write out for post-processing
120                 meshOps::writeVTK
121                 (
122                     mpm_.mesh(),
123                     "patchFaceInsError_"
124                   + Foam::name(fffI.index()),
125                     labelList(1, fffI.index()),
126                     2,
127                     mpm_.mesh().points(),
128                     List<edge>(0),
129                     mpm_.mesh().faces()
130                 );
132                 FatalErrorIn
133                 (
134                     "void topoPatchMapper::"
135                     "calcInsertedFaceAddressing() const"
136                 )   << " Mapping for inserted boundary face is incorrect."
137                     << " Found an empty masterObjects list."
138                     << nl << " Face: " << fffI.index()
139                     << nl << " Patch: " << patch_.name()
140                     << abort(FatalError);
141             }
142             else
143             {
144                 // Make an entry for the inserted label,
145                 // and renumber addressing to patch.
146                 insertedFaces[nInsertedFaces] = fffI.index() - pStart;
148                 // Add a mapping entry for facesFromFaces indices
149                 insertedFacesMap[nInsertedFaces] = objectI;
151                 // Make an entry for addressing
152                 labelList& addr = insertedAddressing[nInsertedFaces];
154                 // Check for illegal addressing
155                 addr = fffI.masterObjects();
157                 forAll(addr, faceI)
158                 {
159                     if (addr[faceI] < 0 || addr[faceI] >= oldPatchSize)
160                     {
161                         // Write out for post-processing
162                         meshOps::writeVTK
163                         (
164                             mpm_.mesh(),
165                             "patchFacePatchError_"
166                           + Foam::name(fffI.index()),
167                             labelList(1, fffI.index()),
168                             2,
169                             mpm_.mesh().points(),
170                             List<edge>(0),
171                             mpm_.mesh().faces()
172                         );
174                         FatalErrorIn
175                         (
176                             "void topoPatchMapper::"
177                             "calcInsertedFaceAddressing() const"
178                         )
179                             << "Addressing into another patch is not allowed."
180                             << nl << " Patch face index: " << faceI
181                             << nl << " Patch: " << patch_.name()
182                             << nl << " fffI.index: " << fffI.index()
183                             << nl << " pStart: " << pStart
184                             << nl << " addr: " << addr
185                             << nl << " addr[faceI]: " << addr[faceI]
186                             << nl << " oldPatchStart: " << oldPatchStart
187                             << nl << " oldPatchSize: " << oldPatchSize
188                             << abort(FatalError);
189                     }
190                 }
192                 nInsertedFaces++;
193             }
194         }
195     }
197     // Shorten inserted faces to actual size
198     insertedFaces.setSize(nInsertedFaces);
199     insertedFacesMap.setSize(nInsertedFaces);
200     insertedAddressing.setSize(nInsertedFaces);
204 //- Calculate addressing for mapping
205 void topoPatchMapper::calcAddressing() const
207     if (directAddrPtr_ || interpolationAddrPtr_)
208     {
209         FatalErrorIn("void topoPatchMapper::calcAddressing() const")
210             << "Addressing already calculated."
211             << abort(FatalError);
212     }
214     // Information from the old patch
215     const label oldPatchSize = sizeBeforeMapping();
216     const label oldPatchStart = mpm_.oldPatchStarts()[patch_.index()];
217     const label oldPatchEnd = oldPatchStart + oldPatchSize;
219     // Assemble the maps: slice to patch
220     if (direct())
221     {
222         if (oldPatchSize == 0)
223         {
224             // Nothing to map from. Return empty.
225             directAddrPtr_ = new labelList(0);
226             return;
227         }
229         // Direct mapping - slice to size
230         directAddrPtr_ =
231         (
232             new labelList(patch_.patch().patchSlice(mpm_.faceMap()))
233         );
235         labelList& addr = *directAddrPtr_;
237         // Shift to local patch indices.
238         // Also, check mapping for hits into other patches / internal faces.
239         forAll(addr, faceI)
240         {
241             if
242             (
243                 addr[faceI] >= oldPatchStart
244              && addr[faceI] < oldPatchEnd
245             )
246             {
247                 addr[faceI] -= oldPatchStart;
248             }
249             else
250             {
251                 // Relax addressing requirement for
252                 // processor patch faces. These require
253                 // cell-to-face interpolation anyway.
254                 if (isA<processorPolyPatch>(patch_.patch()))
255                 {
256                     // Artificially map from face[0] of this patch.
257                     addr[faceI] = 0;
258                     continue;
259                 }
261                 // Write out for post-processing
262                 meshOps::writeVTK
263                 (
264                     mpm_.mesh(),
265                     "patchFacePatchError_"
266                   + Foam::name(faceI),
267                     labelList(1, faceI),
268                     2,
269                     mpm_.mesh().points(),
270                     List<edge>(0),
271                     mpm_.mesh().faces()
272                 );
274                 FatalErrorIn
275                 (
276                     "void topoPatchMapper::calcAddressing() const"
277                 )
278                     << "Addressing into another patch is not allowed."
279                     << nl << " Patch: " << patch_.name()
280                     << nl << " Patch index: " << patch_.index()
281                     << nl << " Patch face index: " << faceI
282                     << nl << " addr[faceI]: " << addr[faceI]
283                     << nl << " oldPatchStart: " << oldPatchStart
284                     << nl << " oldPatchSize: " << oldPatchSize
285                     << nl << " oldPatchEnd: " << oldPatchEnd
286                     << nl << " nInserted: " << insertedObjectLabels().size()
287                     << abort(FatalError);
288             }
289         }
290     }
291     else
292     {
293         if (oldPatchSize == 0)
294         {
295             // Nothing to map from. Return empty.
296             interpolationAddrPtr_ = new labelListList(0);
297             return;
298         }
300         // Interpolative addressing
301         interpolationAddrPtr_ = new labelListList(patchSize(), labelList(0));
302         labelListList& addr = *interpolationAddrPtr_;
304         // Fetch the list of inserted faces / addressing
305         const labelList& insertedFaces = insertedObjectLabels();
306         const labelListList& insertedAddressing = insertedFaceAddressing();
308         // Make entries
309         forAll(insertedFaces, faceI)
310         {
311             addr[insertedFaces[faceI]] = insertedAddressing[faceI];
312         }
314         // Do mapped faces. Note that this can already be set by insertedFaces
315         // so check if addressing size still zero.
316         const labelList::subList fm = patch_.patch().patchSlice(mpm_.faceMap());
318         forAll(fm, faceI)
319         {
320             if (fm[faceI] > -1 && addr[faceI].size() == 0)
321             {
322                 // Mapped from a single face
323                 label oldFace = fm[faceI];
325                 if
326                 (
327                     oldFace >= oldPatchStart
328                  && oldFace < oldPatchEnd
329                 )
330                 {
331                     oldFace -= oldPatchStart;
332                 }
333                 else
334                 {
335                     FatalErrorIn
336                     (
337                         "void topoPatchMapper::calcAddressing() const"
338                     )
339                         << "Addressing into another patch is not allowed."
340                         << nl << " Patch: " << patch_.name()
341                         << nl << " Patch index: " << patch_.index()
342                         << nl << " Patch face index: " << faceI
343                         << nl << " faceMap[faceI]: " << oldFace
344                         << nl << " oldPatchStart: " << oldPatchStart
345                         << nl << " oldPatchSize: " << oldPatchSize
346                         << nl << " oldPatchEnd: " << oldPatchEnd
347                         << abort(FatalError);
348                 }
350                 addr[faceI] = labelList(1, oldFace);
351             }
352         }
354         // Check if we missed anything
355         forAll(addr, faceI)
356         {
357             if (addr[faceI].empty())
358             {
359                 // Relax addressing requirement for
360                 // processor patch faces. These require
361                 // cell-to-face interpolation anyway.
362                 if (isA<processorPolyPatch>(patch_.patch()))
363                 {
364                     // Artificially map from face[0] of this patch.
365                     addr[faceI] = labelList(1, 0);
367                     continue;
368                 }
370                 label oldFace = (faceI < fm.size() ? fm[faceI] : -1);
372                 FatalErrorIn
373                 (
374                     "void topoPatchMapper::calcAddressing() const"
375                 )
376                     << "Addressing is missing." << nl
377                     << " Patch face index: " << faceI << nl
378                     << " nInsertedFaces: " << insertedFaces.size() << nl
379                     << " faceMap[faceI]: " << oldFace << nl
380                     << " patch faceMap size: " << fm.size() << nl
381                     << " Patch: " << patch_.name() << nl
382                     << " polyPatch: " << nl << patch_.patch() << nl
383                     << " faceMap size: " << mpm_.faceMap().size() << nl
384                     << abort(FatalError);
385             }
386         }
387     }
391 //- Calculate inverse-distance weights for interpolative mapping
392 void topoPatchMapper::calcInverseDistanceWeights() const
394     if (weightsPtr_)
395     {
396         FatalErrorIn
397         (
398             "void topoPatchMapper::calcInverseDistanceWeights() const"
399         )
400             << "Weights already calculated."
401             << abort(FatalError);
402     }
404     // Fetch interpolative addressing
405     const labelListList& addr = addressing();
407     if (addr.empty())
408     {
409         // Nothing to map from. Return empty.
410         weightsPtr_ = new scalarListList(0);
411         return;
412     }
414     // Allocate memory
415     weightsPtr_ = new scalarListList(patchSize());
416     scalarListList& w = *weightsPtr_;
418     // Obtain face-centre information from old/new meshes
419     const vectorField& oldCentres = tMapper_.patchCentres(patch_.index());
420     const vectorField& newCentres = patch_.patch().faceCentres();
422     forAll(addr, faceI)
423     {
424         const labelList& mo = addr[faceI];
426         // Do mapped faces
427         if (mo.size() == 1)
428         {
429             w[faceI] = scalarList(1, 1.0);
430         }
431         else
432         {
433             // Map from masters, inverse-distance weights
434             scalar totalWeight = 0.0;
435             w[faceI] = scalarList(mo.size(), 0.0);
437             forAll (mo, oldFaceI)
438             {
439                 w[faceI][oldFaceI] =
440                 (
441                     1.0/stabilise
442                     (
443                         magSqr
444                         (
445                             newCentres[faceI]
446                           - oldCentres[mo[oldFaceI]]
447                         ),
448                         VSMALL
449                     )
450                 );
452                 totalWeight += w[faceI][oldFaceI];
453             }
455             // Normalize weights
456             scalar normFactor = (1.0/totalWeight);
458             forAll (mo, oldFaceI)
459             {
460                 w[faceI][oldFaceI] *= normFactor;
461             }
462         }
463     }
467 //- Calculate intersection weights for conservative mapping
468 void topoPatchMapper::calcIntersectionWeightsAndCentres() const
470     if (areasPtr_ || centresPtr_)
471     {
472         FatalErrorIn
473         (
474             "void topoPatchMapper::"
475             "calcIntersectionWeightsAndCentres() const"
476         )
477             << "Weights already calculated."
478             << abort(FatalError);
479     }
481     // Fetch interpolative addressing
482     const labelListList& addr = addressing();
484     if (addr.empty())
485     {
486         // Nothing to map from. Return empty.
487         areasPtr_ = new List<scalarList>(0);
488         centresPtr_ = new List<vectorList>(0);
489         return;
490     }
492     // Allocate memory
493     areasPtr_ = new List<scalarList>(patchSize(), scalarList(0));
494     List<scalarList>& a = *areasPtr_;
496     centresPtr_ = new List<vectorList>(patchSize(), vectorList(0));
497     List<vectorList>& x = *centresPtr_;
499     // Obtain stored face-centres
500     const vectorField& faceCentres = tMapper_.patchCentres(patch_.index());
502     // Fetch maps
503     const List<vectorField>& mapFaceCentres = tMapper_.faceCentres();
504     const List<scalarField>& mapFaceWeights = tMapper_.faceWeights();
506     // Fill in maps first
507     const labelList& insertedFaces = insertedObjectLabels();
508     const labelList& insertedFacesMap = insertedObjectMap();
510     forAll(insertedFaces, faceI)
511     {
512         a[insertedFaces[faceI]] = mapFaceWeights[insertedFacesMap[faceI]];
513         x[insertedFaces[faceI]] = mapFaceCentres[insertedFacesMap[faceI]];
514     }
516     // Now do mapped faces
517     forAll(addr, faceI)
518     {
519         const labelList& mo = addr[faceI];
521         // Check if this is indeed a mapped face
522         if (mo.size() == 1 && x[faceI].empty() && a[faceI].empty())
523         {
524             x[faceI] = vectorList(1, faceCentres[mo[0]]);
525             a[faceI] = scalarList(1, 1.0);
526         }
527     }
529     // Final check to ensure everything went okay
530     forAll(a, faceI)
531     {
532         if (a[faceI].empty())
533         {
534             FatalErrorIn
535             (
536                 "void topoPatchMapper::"
537                 "calcIntersectionWeightsAndCentres() const"
538             )
539                 << "Weights / centres is missing."
540                 << nl << " Patch face index: " << faceI
541                 << abort(FatalError);
542         }
543     }
547 const List<scalarList>& topoPatchMapper::intersectionWeights() const
549     if (direct())
550     {
551         FatalErrorIn
552         (
553             "const List<scalarList>& "
554             "topoPatchMapper::intersectionWeights() const"
555         )   << "Requested interpolative weights for a direct mapper."
556             << abort(FatalError);
557     }
559     if (!areasPtr_)
560     {
561         calcIntersectionWeightsAndCentres();
562     }
564     return *areasPtr_;
568 const List<vectorList>& topoPatchMapper::intersectionCentres() const
570     if (direct())
571     {
572         FatalErrorIn
573         (
574             "const List<vectorList>& "
575             "topoPatchMapper::intersectionCentres() const"
576         )   << "Requested interpolative weights for a direct mapper."
577             << abort(FatalError);
578     }
580     if (!centresPtr_)
581     {
582         calcIntersectionWeightsAndCentres();
583     }
585     return *centresPtr_;
589 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
591 // Construct from components
592 topoPatchMapper::topoPatchMapper
594     const fvPatch& patch,
595     const mapPolyMesh& mpm,
596     const topoMapper& mapper
599     patch_(patch),
600     mpm_(mpm),
601     tMapper_(mapper),
602     direct_(false),
603     sizeBeforeMapping_(0),
604     conservative_(false),
605     directAddrPtr_(NULL),
606     interpolationAddrPtr_(NULL),
607     weightsPtr_(NULL),
608     insertedFaceLabelsPtr_(NULL),
609     insertedFaceIndexMapPtr_(NULL),
610     insertedFaceAddressingPtr_(NULL),
611     areasPtr_(NULL),
612     centresPtr_(NULL)
614     // Compute sizeBeforeMapping.
615     // - This needs to be done before insertedObjects
616     //   is computed to determine direct mapping
617     if (isA<emptyPolyPatch>(patch_.patch()))
618     {
619         sizeBeforeMapping_ = 0;
620     }
621     else
622     {
623         label patchIndex = patch_.index();
624         label totalSize = mpm_.oldPatchSizes()[patchIndex];
626         // Fetch offset sizes from topoMapper
627         const labelListList& sizes = tMapper_.patchSizes();
629         // Add offset sizes
630         if (sizes.size())
631         {
632             // Fetch number of physical patches
633             label nPhysical = sizes[0].size();
635             if (patchIndex < nPhysical)
636             {
637                 forAll(sizes, pI)
638                 {
639                     totalSize += sizes[pI][patchIndex];
640                 }
641             }
642         }
644         sizeBeforeMapping_ = totalSize;
645     }
647     // Check for the possibility of direct mapping
648     if (insertedObjects())
649     {
650         direct_ = false;
651     }
652     else
653     {
654         direct_ = true;
655     }
658 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
660 topoPatchMapper::~topoPatchMapper()
662     clearOut();
665 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
667 //- Return the polyPatch size
668 label topoPatchMapper::patchSize() const
670     return patch_.patch().size();
674 //- Return size
675 label topoPatchMapper::size() const
677     return patch_.size();
681 //- Return size before mapping
682 label topoPatchMapper::sizeBeforeMapping() const
684     return sizeBeforeMapping_;
688 //- Is the mapping direct
689 bool topoPatchMapper::direct() const
691     return direct_;
695 //- Return direct addressing
696 const unallocLabelList& topoPatchMapper::directAddressing() const
698     if (!direct())
699     {
700         FatalErrorIn
701         (
702             "const unallocLabelList& "
703             "topoPatchMapper::directAddressing() const"
704         )   << "Requested direct addressing for an interpolative mapper."
705             << abort(FatalError);
706     }
708     if (!directAddrPtr_)
709     {
710         calcAddressing();
711     }
713     return *directAddrPtr_;
717 //- Return interpolation addressing
718 const labelListList& topoPatchMapper::addressing() const
720     if (direct())
721     {
722         FatalErrorIn
723         (
724             "const labelListList& "
725             "topoPatchMapper::addressing() const"
726         )   << "Requested interpolative addressing for a direct mapper."
727             << abort(FatalError);
728     }
730     if (!interpolationAddrPtr_)
731     {
732         calcAddressing();
733     }
735     return *interpolationAddrPtr_;
739 //- Return weights
740 const scalarListList& topoPatchMapper::weights() const
742     if (direct())
743     {
744         FatalErrorIn
745         (
746             "const scalarListList& "
747             "topoPatchMapper::weights() const"
748         )   << "Requested interpolative weights for a direct mapper."
749             << abort(FatalError);
750     }
752     if (conservative_)
753     {
754         if (!areasPtr_ && !centresPtr_)
755         {
756             calcIntersectionWeightsAndCentres();
757         }
759         return *areasPtr_;
760     }
762     if (!weightsPtr_)
763     {
764         calcInverseDistanceWeights();
765     }
767     return *weightsPtr_;
771 //- Are there any inserted faces
772 bool topoPatchMapper::insertedObjects() const
774     return insertedObjectLabels().size();
778 //- Return list of inserted faces
779 const labelList& topoPatchMapper::insertedObjectLabels() const
781     if (!insertedFaceLabelsPtr_)
782     {
783         calcInsertedFaceAddressing();
784     }
786     return *insertedFaceLabelsPtr_;
790 //- Return addressing map for inserted faces
791 const labelList& topoPatchMapper::insertedObjectMap() const
793     if (!insertedFaceIndexMapPtr_)
794     {
795         calcInsertedFaceAddressing();
796     }
798     return *insertedFaceIndexMapPtr_;
802 //- Return addressing for inserted faces
803 const labelListList& topoPatchMapper::insertedFaceAddressing() const
805     if (!insertedFaceAddressingPtr_)
806     {
807         calcInsertedFaceAddressing();
808     }
810     return *insertedFaceAddressingPtr_;
814 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
816 void topoPatchMapper::operator=(const topoPatchMapper& rhs)
818     // Check for assignment to self
819     if (this == &rhs)
820     {
821         FatalErrorIn("void topoPatchMapper::operator=")
822             << "Attempted assignment to self"
823             << abort(FatalError);
824     }
827 } // End namespace Foam
829 // ************************************************************************* //