BUG: UListIO: byteSize overflowing on really big faceLists
[OpenFOAM-2.0.x.git] / src / meshTools / directMapped / directMappedPolyPatch / directMappedPatchBase.C
blob201371cbc7d28657c233c2aa5e97c600502d0e5a
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
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
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
19     for more details.
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"
31 #include "OFstream.H"
32 #include "Random.H"
33 #include "treeDataFace.H"
34 #include "indexedOctree.H"
35 #include "polyMesh.H"
36 #include "polyPatch.H"
37 #include "Time.H"
38 #include "mapDistribute.H"
39 #include "SubField.H"
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
43 namespace Foam
45     defineTypeNameAndDebug(directMappedPatchBase, 0);
47     template<>
48     const char* Foam::NamedEnum
49     <
50         Foam::directMappedPatchBase::sampleMode,
51         3
52     >::names[] =
53     {
54         "nearestCell",
55         "nearestPatchFace",
56         "nearestFace"
57     };
59     template<>
60     const char* Foam::NamedEnum
61     <
62         Foam::directMappedPatchBase::offsetMode,
63         3
64     >::names[] =
65     {
66         "uniform",
67         "nonuniform",
68         "normal"
69     };
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
84     pointField& samples,
85     labelList& patchFaceProcs,
86     labelList& patchFaces,
87     pointField& patchFc
88 ) const
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>
110     (
111         globalSamples,
112         accessOp<pointField>()
113     );
114     patchFaces = ListListOps::combine<labelList>
115     (
116         globalFaces,
117         accessOp<labelList>()
118     );
119     patchFc = ListListOps::combine<pointField>
120     (
121         globalFc,
122         accessOp<pointField>()
123     );
125     patchFaceProcs.setSize(patchFaces.size());
126     labelList nPerProc
127     (
128         ListListOps::subSizes
129         (
130             globalFaces,
131             accessOp<labelList>()
132         )
133     );
134     label sampleI = 0;
135     forAll(nPerProc, procI)
136     {
137         for (label i = 0; i < nPerProc[procI]; i++)
138         {
139             patchFaceProcs[sampleI++] = procI;
140         }
141     }
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
153 ) const
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());
161     switch (mode_)
162     {
163         case NEARESTCELL:
164         {
165             if (samplePatch_.size() && samplePatch_ != "none")
166             {
167                 FatalErrorIn
168                 (
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);
173             }
175             // Octree based search engine. Uses min tetDecomp so force
176             // calculation
177             (void)mesh.tetBasePtIs();
178             meshSearch meshSearchEngine(mesh, false);
180             forAll(samples, sampleI)
181             {
182                 const point& sample = samples[sampleI];
184                 label cellI = meshSearchEngine.findCell(sample);
186                 if (cellI == -1)
187                 {
188                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
189                     nearest[sampleI].second().second() = Pstream::myProcNo();
190                 }
191                 else
192                 {
193                     const point& cc = mesh.cellCentres()[cellI];
195                     nearest[sampleI].first() = pointIndexHit
196                     (
197                         true,
198                         cc,
199                         cellI
200                     );
201                     nearest[sampleI].second().first() = magSqr(cc-sample);
202                     nearest[sampleI].second().second() = Pstream::myProcNo();
203                 }
204             }
205             break;
206         }
208         case NEARESTPATCHFACE:
209         {
210             Random rndGen(123456);
212             const polyPatch& pp = samplePolyPatch();
214             if (pp.empty())
215             {
216                 forAll(samples, sampleI)
217                 {
218                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
219                     nearest[sampleI].second().second() = Pstream::myProcNo();
220                 }
221             }
222             else
223             {
224                 // patch faces
225                 const labelList patchFaces(identity(pp.size()) + pp.start());
227                 treeBoundBox patchBb
228                 (
229                     treeBoundBox(pp.points(), pp.meshPoints()).extend
230                     (
231                         rndGen,
232                         1E-4
233                     )
234                 );
235                 patchBb.min() -= point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
236                 patchBb.max() += point(ROOTVSMALL, ROOTVSMALL, ROOTVSMALL);
238                 indexedOctree<treeDataFace> boundaryTree
239                 (
240                     treeDataFace    // all information needed to search faces
241                     (
242                         false,      // do not cache bb
243                         mesh,
244                         patchFaces  // boundary faces only
245                     ),
246                     patchBb,        // overall search domain
247                     8,              // maxLevel
248                     10,             // leafsize
249                     3.0             // duplicity
250                 );
252                 forAll(samples, sampleI)
253                 {
254                     const point& sample = samples[sampleI];
256                     pointIndexHit& nearInfo = nearest[sampleI].first();
257                     nearInfo = boundaryTree.findNearest
258                     (
259                         sample,
260                         magSqr(patchBb.span())
261                     );
263                     if (!nearInfo.hit())
264                     {
265                         nearest[sampleI].second().first() = Foam::sqr(GREAT);
266                         nearest[sampleI].second().second() =
267                             Pstream::myProcNo();
268                     }
269                     else
270                     {
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() =
275                             Pstream::myProcNo();
276                     }
277                 }
278             }
279             break;
280         }
282         case NEARESTFACE:
283         {
284             if (samplePatch_.size() && samplePatch_ != "none")
285             {
286                 FatalErrorIn
287                 (
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);
292             }
294             // Octree based search engine
295             meshSearch meshSearchEngine(mesh, false);
297             forAll(samples, sampleI)
298             {
299                 const point& sample = samples[sampleI];
301                 label faceI = meshSearchEngine.findNearestFace(sample);
303                 if (faceI == -1)
304                 {
305                     nearest[sampleI].second().first() = Foam::sqr(GREAT);
306                     nearest[sampleI].second().second() = Pstream::myProcNo();
307                 }
308                 else
309                 {
310                     const point& fc = mesh.faceCentres()[faceI];
312                     nearest[sampleI].first() = pointIndexHit
313                     (
314                         true,
315                         fc,
316                         faceI
317                     );
318                     nearest[sampleI].second().first() = magSqr(fc-sample);
319                     nearest[sampleI].second().second() = Pstream::myProcNo();
320                 }
321             }
322             break;
323         }
325         default:
326         {
327             FatalErrorIn("directMappedPatchBase::findSamples(..)")
328                 << "problem." << abort(FatalError);
329         }
330     }
333     // Find nearest.
334     Pstream::listCombineGather(nearest, nearestEqOp());
335     Pstream::listCombineScatter(nearest);
337     if (debug)
338     {
339         Info<< "directMappedPatchBase::findSamples on mesh " << sampleRegion_
340             << " : " << endl;
341         forAll(nearest, sampleI)
342         {
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;
350         }
351     }
353     // Check for samples not being found
354     forAll(nearest, sampleI)
355     {
356         if (!nearest[sampleI].first().hit())
357         {
358             FatalErrorIn
359             (
360                 "directMappedPatchBase::findSamples"
361                 "(const pointField&, labelList&"
362                 ", labelList&, pointField&)"
363             )   << "Did not find sample " << samples[sampleI]
364                 << " on any processor of region " << sampleRegion_
365                 << exit(FatalError);
366         }
367     }
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)
376     {
377         sampleProcs[sampleI] = nearest[sampleI].second().second();
378         sampleIndices[sampleI] = nearest[sampleI].first().index();
379         sampleLocations[sampleI] = nearest[sampleI].first().hitPoint();
380     }
384 void Foam::directMappedPatchBase::calcMapping() const
386     if (mapPtr_.valid())
387     {
388         FatalErrorIn("directMappedPatchBase::calcMapping() const")
389             << "Mapping already calculated" << exit(FatalError);
390     }
392     // Do a sanity check
393     // Am I sampling my own patch? This only makes sense for a non-zero
394     // offset.
395     bool sampleMyself =
396     (
397         mode_ == NEARESTPATCHFACE
398      && sampleRegion_ == patch_.boundaryMesh().mesh().name()
399      && samplePatch_ == patch_.name()
400     );
402     // Check offset
403     vectorField d(samplePoints()-patch_.faceCentres());
404     if (sampleMyself && gAverage(mag(d)) <= ROOTVSMALL)
405     {
406         WarningIn
407         (
408             "directMappedPatchBase::directMappedPatchBase\n"
409             "(\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"
415             ")\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;
428     }
432     // Get global list of all samples and the processor and face they come from.
433     pointField samples;
434     labelList patchFaceProcs;
435     labelList patchFaces;
436     pointField patchFc;
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.
452     //forAll(samples, i)
453     //{
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]
463     //        << nl << endl;
464     //}
468     if (debug && Pstream::master())
469     {
470         OFstream str
471         (
472             patch_.boundaryMesh().mesh().time().path()
473           / patch_.name()
474           + "_directMapped.obj"
475         );
476         Pout<< "Dumping mapping as lines from patch faceCentres to"
477             << " sampled cell/faceCentres to file " << str.name() << endl;
479         label vertI = 0;
481         forAll(patchFc, i)
482         {
483             meshTools::writeOBJ(str, patchFc[i]);
484             vertI++;
485             meshTools::writeOBJ(str, sampleLocations[i]);
486             vertI++;
487             str << "l " << vertI-1 << ' ' << vertI << nl;
488         }
489     }
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)
502     {
503         subMap[procI] = UIndirectList<label>
504         (
505             sampleIndices,
506             subMap[procI]
507         );
508         constructMap[procI] = UIndirectList<label>
509         (
510             patchFaces,
511             constructMap[procI]
512         );
514         //if (debug)
515         //{
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;
521         //}
522     }
524     // Redo constructSize
525     mapPtr_().constructSize() = patch_.size();
527     if (debug)
528     {
529         // Check that all elements get a value.
530         PackedBoolList used(patch_.size());
531         forAll(constructMap, procI)
532         {
533             const labelList& map = constructMap[procI];
535             forAll(map, i)
536             {
537                 label faceI = map[i];
539                 if (used[faceI] == 0)
540                 {
541                     used[faceI] = 1;
542                 }
543                 else
544                 {
545                     FatalErrorIn("directMappedPatchBase::calcMapping() const")
546                         << "On patch " << patch_.name()
547                         << " patchface " << faceI
548                         << " is assigned to more than once."
549                         << abort(FatalError);
550                 }
551             }
552         }
553         forAll(used, faceI)
554         {
555             if (used[faceI] == 0)
556             {
557                 FatalErrorIn("directMappedPatchBase::calcMapping() const")
558                     << "On patch " << patch_.name()
559                     << " patchface " << faceI
560                     << " is never assigned to."
561                     << abort(FatalError);
562             }
563         }
564     }
568 // * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * * * * * //
570 Foam::directMappedPatchBase::directMappedPatchBase
572     const polyPatch& pp
575     patch_(pp),
576     sampleRegion_(patch_.boundaryMesh().mesh().name()),
577     mode_(NEARESTPATCHFACE),
578     samplePatch_("none"),
579     offsetMode_(UNIFORM),
580     offset_(vector::zero),
581     offsets_(pp.size(), offset_),
582     distance_(0),
583     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
584     mapPtr_(NULL)
588 Foam::directMappedPatchBase::directMappedPatchBase
590     const polyPatch& pp,
591     const word& sampleRegion,
592     const sampleMode mode,
593     const word& samplePatch,
594     const vectorField& offsets
597     patch_(pp),
598     sampleRegion_(sampleRegion),
599     mode_(mode),
600     samplePatch_(samplePatch),
601     offsetMode_(NONUNIFORM),
602     offset_(vector::zero),
603     offsets_(offsets),
604     distance_(0),
605     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
606     mapPtr_(NULL)
610 Foam::directMappedPatchBase::directMappedPatchBase
612     const polyPatch& pp,
613     const word& sampleRegion,
614     const sampleMode mode,
615     const word& samplePatch,
616     const vector& offset
619     patch_(pp),
620     sampleRegion_(sampleRegion),
621     mode_(mode),
622     samplePatch_(samplePatch),
623     offsetMode_(UNIFORM),
624     offset_(offset),
625     offsets_(0),
626     distance_(0),
627     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
628     mapPtr_(NULL)
632 Foam::directMappedPatchBase::directMappedPatchBase
634     const polyPatch& pp,
635     const word& sampleRegion,
636     const sampleMode mode,
637     const word& samplePatch,
638     const scalar distance
641     patch_(pp),
642     sampleRegion_(sampleRegion),
643     mode_(mode),
644     samplePatch_(samplePatch),
645     offsetMode_(NORMAL),
646     offset_(vector::zero),
647     offsets_(0),
648     distance_(distance),
649     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
650     mapPtr_(NULL)
654 Foam::directMappedPatchBase::directMappedPatchBase
656     const polyPatch& pp,
657     const dictionary& dict
660     patch_(pp),
661     sampleRegion_
662     (
663         dict.lookupOrDefault
664         (
665             "sampleRegion",
666             patch_.boundaryMesh().mesh().name()
667         )
668     ),
669     mode_(sampleModeNames_.read(dict.lookup("sampleMode"))),
670     samplePatch_(dict.lookup("samplePatch")),
671     offsetMode_(UNIFORM),
672     offset_(vector::zero),
673     offsets_(0),
674     distance_(0.0),
675     sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
676     mapPtr_(NULL)
678     if (dict.found("offsetMode"))
679     {
680         offsetMode_ = offsetModeNames_.read(dict.lookup("offsetMode"));
682         switch(offsetMode_)
683         {
684             case UNIFORM:
685             {
686                 offset_ = point(dict.lookup("offset"));
687             }
688             break;
690             case NONUNIFORM:
691             {
692                 offsets_ = pointField(dict.lookup("offsets"));
693             }
694             break;
696             case NORMAL:
697             {
698                 distance_ = readScalar(dict.lookup("distance"));
699             }
700             break;
701         }
702     }
703     else if (dict.found("offset"))
704     {
705         offsetMode_ = UNIFORM;
706         offset_ = point(dict.lookup("offset"));
707     }
708     else if (dict.found("offsets"))
709     {
710         offsetMode_ = NONUNIFORM;
711         offsets_ = pointField(dict.lookup("offsets"));
712     }
713     else
714     {
715         FatalIOErrorIn
716         (
717             "directMappedPatchBase::directMappedPatchBase\n"
718             "(\n"
719             "    const polyPatch& pp,\n"
720             "    const dictionary& dict\n"
721             ")\n",
722             dict
723         )   << "Please supply the offsetMode as one of "
724             << NamedEnum<offsetMode, 3>::words()
725             << exit(FatalIOError);
726     }
730 Foam::directMappedPatchBase::directMappedPatchBase
732     const polyPatch& pp,
733     const directMappedPatchBase& dmp
736     patch_(pp),
737     sampleRegion_(dmp.sampleRegion_),
738     mode_(dmp.mode_),
739     samplePatch_(dmp.samplePatch_),
740     offsetMode_(dmp.offsetMode_),
741     offset_(dmp.offset_),
742     offsets_(dmp.offsets_),
743     distance_(dmp.distance_),
744     sameRegion_(dmp.sameRegion_),
745     mapPtr_(NULL)
749 Foam::directMappedPatchBase::directMappedPatchBase
751     const polyPatch& pp,
752     const directMappedPatchBase& dmp,
753     const labelUList& mapAddressing
756     patch_(pp),
757     sampleRegion_(dmp.sampleRegion_),
758     mode_(dmp.mode_),
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_),
765     mapPtr_(NULL)
769 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
771 Foam::directMappedPatchBase::~directMappedPatchBase()
773     clearOut();
777 void Foam::directMappedPatchBase::clearOut()
779     mapPtr_.clear();
783 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
785 const Foam::polyMesh& Foam::directMappedPatchBase::sampleMesh() const
787     return patch_.boundaryMesh().mesh().time().lookupObject<polyMesh>
788     (
789         sampleRegion_
790     );
794 const Foam::polyPatch& Foam::directMappedPatchBase::samplePolyPatch() const
796     const polyMesh& nbrMesh = sampleMesh();
798     const label patchI = nbrMesh.boundaryMesh().findPatchID(samplePatch_);
800     if (patchI == -1)
801     {
802         FatalErrorIn("directMappedPatchBase::samplePolyPatch() ")
803             << "Cannot find patch " << samplePatch_
804             << " in region " << sampleRegion_ << endl
805             << "Valid patches are " << nbrMesh.boundaryMesh().names()
806             << exit(FatalError);
807     }
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();
818     switch(offsetMode_)
819     {
820         case UNIFORM:
821         {
822             fld += offset_;
823         }
824         break;
826         case NONUNIFORM:
827         {
828             fld += offsets_;
829         }
830         break;
832         case NORMAL:
833         {
834             // Get outwards pointing normal
835             vectorField n(patch_.faceAreas());
836             n /= mag(n);
838             fld += distance_*n;
839         }
840         break;
841     }
843     return tfld;
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;
859     switch(offsetMode_)
860     {
861         case UNIFORM:
862         {
863             os.writeKeyword("offset") << offset_ << token::END_STATEMENT << nl;
864         }
865         break;
867         case NONUNIFORM:
868         {
869             os.writeKeyword("offsets") << offsets_ << token::END_STATEMENT
870                 << nl;
871         }
872         break;
874         case NORMAL:
875         {
876             os.writeKeyword("distance") << distance_ << token::END_STATEMENT
877                 << nl;
878         }
879         break;
880     }
884 // ************************************************************************* //