initial commit for version 1.6.x patch release
[OpenFOAM-1.6.x.git] / src / finiteVolume / fields / fvPatchFields / derived / timeVaryingMappedFixedValue / timeVaryingMappedFixedValueFvPatchField.C
blobb1afef7b8837722e95ea616eafcfaf678e4cb12e
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 "timeVaryingMappedFixedValueFvPatchField.H"
28 #include "Time.H"
29 #include "triSurfaceTools.H"
30 #include "triSurface.H"
31 #include "vector2D.H"
32 #include "OFstream.H"
33 #include "long.H"
34 #include "AverageIOField.H"
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 namespace Foam
41 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
43 template<class Type>
44 timeVaryingMappedFixedValueFvPatchField<Type>::
45 timeVaryingMappedFixedValueFvPatchField
47     const fvPatch& p,
48     const DimensionedField<Type, volMesh>& iF
51     fixedValueFvPatchField<Type>(p, iF),
52     setAverage_(false),
53     referenceCS_(NULL),
54     nearestVertex_(0),
55     nearestVertexWeight_(0),
56     sampleTimes_(0),
57     startSampleTime_(-1),
58     startSampledValues_(0),
59     startAverage_(pTraits<Type>::zero),
60     endSampleTime_(-1),
61     endSampledValues_(0),
62     endAverage_(pTraits<Type>::zero)
64     if (debug)
65     {
66         Pout<< "timeVaryingMappedFixedValue :"
67             << " construct from fvPatch and internalField" << endl;
68     }
72 template<class Type>
73 timeVaryingMappedFixedValueFvPatchField<Type>::
74 timeVaryingMappedFixedValueFvPatchField
76     const timeVaryingMappedFixedValueFvPatchField<Type>& ptf,
77     const fvPatch& p,
78     const DimensionedField<Type, volMesh>& iF,
79     const fvPatchFieldMapper& mapper
82     fixedValueFvPatchField<Type>(ptf, p, iF, mapper),
83     setAverage_(ptf.setAverage_),
84     referenceCS_(NULL),
85     nearestVertex_(0),
86     nearestVertexWeight_(0),
87     sampleTimes_(0),
88     startSampleTime_(-1),
89     startSampledValues_(0),
90     startAverage_(pTraits<Type>::zero),
91     endSampleTime_(-1),
92     endSampledValues_(0),
93     endAverage_(pTraits<Type>::zero)
95     if (debug)
96     {
97         Pout<< "timeVaryingMappedFixedValue"
98             << " : construct from mappedFixedValue and mapper" << endl;
99     }
103 template<class Type>
104 timeVaryingMappedFixedValueFvPatchField<Type>::
105 timeVaryingMappedFixedValueFvPatchField
107     const fvPatch& p,
108     const DimensionedField<Type, volMesh>& iF,
109     const dictionary& dict
112     fixedValueFvPatchField<Type>(p, iF),
113     setAverage_(readBool(dict.lookup("setAverage"))),
114     referenceCS_(NULL),
115     nearestVertex_(0),
116     nearestVertexWeight_(0),
117     sampleTimes_(0),
118     startSampleTime_(-1),
119     startSampledValues_(0),
120     startAverage_(pTraits<Type>::zero),
121     endSampleTime_(-1),
122     endSampledValues_(0),
123     endAverage_(pTraits<Type>::zero)
125     if (debug)
126     {
127         Pout<< "timeVaryingMappedFixedValue : construct from dictionary"
128             << endl;
129     }
131     if (dict.found("value"))
132     {
133         fvPatchField<Type>::operator==(Field<Type>("value", dict, p.size()));
134     }
135     else
136     {
137         updateCoeffs();
138     }
142 template<class Type>
143 timeVaryingMappedFixedValueFvPatchField<Type>::
144 timeVaryingMappedFixedValueFvPatchField
146     const timeVaryingMappedFixedValueFvPatchField<Type>& ptf
149     fixedValueFvPatchField<Type>(ptf),
150     setAverage_(ptf.setAverage_),
151     referenceCS_(ptf.referenceCS_),
152     nearestVertex_(ptf.nearestVertex_),
153     nearestVertexWeight_(ptf.nearestVertexWeight_),
154     sampleTimes_(ptf.sampleTimes_),
155     startSampleTime_(ptf.startSampleTime_),
156     startSampledValues_(ptf.startSampledValues_),
157     startAverage_(ptf.startAverage_),
158     endSampleTime_(ptf.endSampleTime_),
159     endSampledValues_(ptf.endSampledValues_),
160     endAverage_(ptf.endAverage_)
162     if (debug)
163     {
164         Pout<< "timeVaryingMappedFixedValue : copy construct"
165             << endl;
166     }
171 template<class Type>
172 timeVaryingMappedFixedValueFvPatchField<Type>::
173 timeVaryingMappedFixedValueFvPatchField
175     const timeVaryingMappedFixedValueFvPatchField<Type>& ptf,
176     const DimensionedField<Type, volMesh>& iF
179     fixedValueFvPatchField<Type>(ptf, iF),
180     setAverage_(ptf.setAverage_),
181     referenceCS_(ptf.referenceCS_),
182     nearestVertex_(ptf.nearestVertex_),
183     nearestVertexWeight_(ptf.nearestVertexWeight_),
184     sampleTimes_(ptf.sampleTimes_),
185     startSampleTime_(ptf.startSampleTime_),
186     startSampledValues_(ptf.startSampledValues_),
187     startAverage_(ptf.startAverage_),
188     endSampleTime_(ptf.endSampleTime_),
189     endSampledValues_(ptf.endSampledValues_),
190     endAverage_(ptf.endAverage_)
192     if (debug)
193     {
194         Pout<< "timeVaryingMappedFixedValue :"
195             << " copy construct, resetting internal field" << endl;
196     }
200 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
202 template<class Type>
203 void timeVaryingMappedFixedValueFvPatchField<Type>::autoMap
205     const fvPatchFieldMapper& m
208     fixedValueFvPatchField<Type>::autoMap(m);
209     if (startSampledValues_.size())
210     {
211         startSampledValues_.autoMap(m);
212         endSampledValues_.autoMap(m);
213     }
217 template<class Type>
218 void timeVaryingMappedFixedValueFvPatchField<Type>::rmap
220     const fvPatchField<Type>& ptf,
221     const labelList& addr
224     fixedValueFvPatchField<Type>::rmap(ptf, addr);
226     const timeVaryingMappedFixedValueFvPatchField<Type>& tiptf =
227         refCast<const timeVaryingMappedFixedValueFvPatchField<Type> >(ptf);
229     startSampledValues_.rmap(tiptf.startSampledValues_, addr);
230     endSampledValues_.rmap(tiptf.endSampledValues_, addr);
234 template<class Type>
235 void timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()
237     // Read the sample points
239     pointIOField samplePoints
240     (
241         IOobject
242         (
243             "points",
244             this->db().time().constant(),
245             "boundaryData"/this->patch().name(),
246             this->db(),
247             IOobject::MUST_READ,
248             IOobject::AUTO_WRITE,
249             false
250         )
251     );
253     const fileName samplePointsFile = samplePoints.filePath();
255     if (debug)
256     {
257         Info<< "timeVaryingMappedFixedValueFvPatchField :"
258             << " Read " << samplePoints.size() << " sample points from "
259             << samplePointsFile << endl;
260     }
262     // Determine coordinate system from samplePoints
264     if (samplePoints.size() < 3)
265     {
266         FatalErrorIn
267         (
268             "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
269         )   << "Only " << samplePoints.size() << " points read from file "
270             << samplePoints.objectPath() << nl
271             << "Need at least three non-colinear samplePoints"
272             << " to be able to interpolate."
273             << "\n    on patch " << this->patch().name()
274             << " of field " << this->dimensionedInternalField().name()
275             << " in file " << this->dimensionedInternalField().objectPath()
276             << exit(FatalError);
277     }
279     const point& p0 = samplePoints[0];
281     // Find point separate from p0
282     vector e1;
283     label index1 = -1;
285     for (label i = 1; i < samplePoints.size(); i++)
286     {
287         e1 = samplePoints[i] - p0;
289         scalar magE1 = mag(e1);
291         if (magE1 > SMALL)
292         {
293             e1 /= magE1;
294             index1 = i;
295             break;
296         }
297     }
299     // Find point that makes angle with n1
300     label index2 = -1;
301     vector e2;
302     vector n;
304     for (label i = index1+1; i < samplePoints.size(); i++)
305     {
306         e2 = samplePoints[i] - p0;
308         scalar magE2 = mag(e2);
310         if (magE2 > SMALL)
311         {
312             e2 /= magE2;
314             n = e1^e2;
316             scalar magN = mag(n);
318             if (magN > SMALL)
319             {
320                 index2 = i;
321                 n /= magN;
322                 break;
323             }
324         }
325     }
327     if (index2 == -1)
328     {
329         FatalErrorIn
330         (
331             "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
332         )   << "Cannot find points that make valid normal." << nl
333             << "Need at least three sample points which are not in a line."
334             << "\n    on patch " << this->patch().name()
335             << " of field " << this->dimensionedInternalField().name()
336             << " in file " << this->dimensionedInternalField().objectPath()
337             << exit(FatalError);
338     }
340     if (debug)
341     {
342         Info<< "timeVaryingMappedFixedValueFvPatchField :"
343             << " Used points " << p0 << ' ' << samplePoints[index1]
344             << ' ' << samplePoints[index2]
345             << " to define coordinate system with normal " << n << endl;
346     }
348     referenceCS_.reset
349     (
350         new coordinateSystem
351         (
352             "reference",
353             p0,  // origin
354             n,   // normal
355             e1   // 0-axis
356         )
357     );
359     tmp<vectorField> tlocalVertices
360     (
361         referenceCS().localPosition(samplePoints)
362     );
363     const vectorField& localVertices = tlocalVertices();
365     // Determine triangulation
366     List<vector2D> localVertices2D(localVertices.size());
367     forAll(localVertices, i)
368     {
369         localVertices2D[i][0] = localVertices[i][0];
370         localVertices2D[i][1] = localVertices[i][1];
371     }
373     triSurface s(triSurfaceTools::delaunay2D(localVertices2D));
375     tmp<pointField> localFaceCentres
376     (
377         referenceCS().localPosition
378         (
379             this->patch().patch().faceCentres()
380         )
381     );
383     if (debug)
384     {
385         Pout<< "readSamplePoints :"
386             <<" Dumping triangulated surface to triangulation.stl" << endl;
387         s.write(this->db().time().path()/"triangulation.stl");
389         OFstream str(this->db().time().path()/"localFaceCentres.obj");
390         Pout<< "readSamplePoints :"
391             << " Dumping face centres to " << str.name() << endl;
393         forAll(localFaceCentres(), i)
394         {
395             const point& p = localFaceCentres()[i];
396             str<< "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
397         }
398     }
400     // Determine interpolation onto face centres.
401     triSurfaceTools::calcInterpolationWeights
402     (
403         s,
404         localFaceCentres,   // points to interpolate to
405         nearestVertex_,
406         nearestVertexWeight_
407     );
411     // Read the times for which data is available
413     const fileName samplePointsDir = samplePointsFile.path();
415     sampleTimes_ = Time::findTimes(samplePointsDir);
417     if (debug)
418     {
419         Info<< "timeVaryingMappedFixedValueFvPatchField : In directory "
420             << samplePointsDir << " found times " << timeNames(sampleTimes_)
421             << endl;
422     }
426 template<class Type>
427 wordList timeVaryingMappedFixedValueFvPatchField<Type>::timeNames
429     const instantList& times
432     wordList names(times.size());
434     forAll(times, i)
435     {
436         names[i] = times[i].name();
437     }
438     return names;
442 template<class Type>
443 void timeVaryingMappedFixedValueFvPatchField<Type>::findTime
445     const fileName& instance,
446     const fileName& local,
447     const scalar timeVal,
448     label& lo,
449     label& hi
450 ) const
452     lo = startSampleTime_;
453     hi = -1;
455     for (label i = startSampleTime_+1; i < sampleTimes_.size(); i++)
456     {
457         if (sampleTimes_[i].value() > timeVal)
458         {
459             break;
460         }
461         else
462         {
463             lo = i;
464         }
465     }
467     if (lo == -1)
468     {
469         FatalErrorIn("findTime")
470             << "Cannot find starting sampling values for current time "
471             << timeVal << nl
472             << "Have sampling values for times "
473             << timeNames(sampleTimes_) << nl
474             << "In directory "
475             <<  this->db().time().constant()/"boundaryData"/this->patch().name()
476             << "\n    on patch " << this->patch().name()
477             << " of field " << this->dimensionedInternalField().name()
478             << " in file " << this->dimensionedInternalField().objectPath()
479             << exit(FatalError);
480     }
482     if (lo < sampleTimes_.size()-1)
483     {
484         hi = lo+1;
485     }
488     if (debug)
489     {
490         if (hi == -1)
491         {
492             Pout<< "findTime : Found time " << timeVal << " after"
493                 << " index:" << lo << " time:" << sampleTimes_[lo].value()
494                 << endl;
495         }
496         else
497         {
498             Pout<< "findTime : Found time " << timeVal << " inbetween"
499                 << " index:" << lo << " time:" << sampleTimes_[lo].value()
500                 << " and index:" << hi << " time:" << sampleTimes_[hi].value()
501                 << endl;
502         }
503     }
507 template<class Type>
508 void timeVaryingMappedFixedValueFvPatchField<Type>::checkTable()
510     // Initialise
511     if (startSampleTime_ == -1 && endSampleTime_ == -1)
512     {
513         readSamplePoints();
514     }
516     // Find current time in sampleTimes
517     label lo = -1;
518     label hi = -1;
520     findTime
521     (
522         this->db().time().constant(),
523         "boundaryData"/this->patch().name(),
524         this->db().time().value(),
525         lo,
526         hi
527     );
529     // Update sampled data fields.
531     if (lo != startSampleTime_)
532     {
533         startSampleTime_ = lo;
535         if (startSampleTime_ == endSampleTime_)
536         {
537             // No need to reread since are end values
538             if (debug)
539             {
540                 Pout<< "checkTable : Setting startValues to (already read) "
541                     <<   "boundaryData"
542                         /this->patch().name()
543                         /sampleTimes_[startSampleTime_].name()
544                     << endl;
545             }
546             startSampledValues_ = endSampledValues_;
547             startAverage_ = endAverage_;
548         }
549         else
550         {
551             if (debug)
552             {
553                 Pout<< "checkTable : Reading startValues from "
554                     <<   "boundaryData"
555                         /this->patch().name()
556                         /sampleTimes_[lo].name()
557                     << endl;
558             }
561             // Reread values and interpolate
562             AverageIOField<Type> vals
563             (
564                 IOobject
565                 (
566                     this->dimensionedInternalField().name(),
567                     this->db().time().constant(),
568                     "boundaryData"
569                    /this->patch().name()
570                    /sampleTimes_[startSampleTime_].name(),
571                     this->db(),
572                     IOobject::MUST_READ,
573                     IOobject::AUTO_WRITE,
574                     false
575                 )
576             );
578             startAverage_ = vals.average();
579             startSampledValues_ = interpolate(vals);
580         }
581     }
583     if (hi != endSampleTime_)
584     {
585         endSampleTime_ = hi;
587         if (endSampleTime_ == -1)
588         {
589             // endTime no longer valid. Might as well clear endValues.
590             if (debug)
591             {
592                 Pout<< "checkTable : Clearing endValues" << endl;
593             }
594             endSampledValues_.clear();
595         }
596         else
597         {
598             if (debug)
599             {
600                 Pout<< "checkTable : Reading endValues from "
601                     <<   "boundaryData"
602                         /this->patch().name()
603                         /sampleTimes_[endSampleTime_].name()
604                     << endl;
605             }
606             // Reread values and interpolate
607             AverageIOField<Type> vals
608             (
609                 IOobject
610                 (
611                     this->dimensionedInternalField().name(),
612                     this->db().time().constant(),
613                     "boundaryData"
614                    /this->patch().name()
615                    /sampleTimes_[endSampleTime_].name(),
616                     this->db(),
617                     IOobject::MUST_READ,
618                     IOobject::AUTO_WRITE,
619                     false
620                 )
621             );
622             endAverage_ = vals.average();
623             endSampledValues_ = interpolate(vals);
624         }
625     }
629 template<class Type>
630 tmp<Field<Type> > timeVaryingMappedFixedValueFvPatchField<Type>::interpolate
632     const Field<Type>& sourceFld
633 ) const
635     tmp<Field<Type> > tfld(new Field<Type>(nearestVertex_.size()));
636     Field<Type>& fld = tfld();
638     forAll(fld, i)
639     {
640         const FixedList<label, 3>& verts = nearestVertex_[i];
641         const FixedList<scalar, 3>& w = nearestVertexWeight_[i];
643         if (verts[2] == -1)
644         {
645             if (verts[1] == -1)
646             {
647                 // Use vertex0 only
648                 fld[i] = sourceFld[verts[0]];
649             }
650             else
651             {
652                 // Use vertex 0,1
653                 fld[i] =
654                     w[0]*sourceFld[verts[0]]
655                   + w[1]*sourceFld[verts[1]];
656             }
657         }
658         else
659         {
660             fld[i] =
661                 w[0]*sourceFld[verts[0]]
662               + w[1]*sourceFld[verts[1]]
663               + w[2]*sourceFld[verts[2]];
664         }
665     }
666     return tfld;
670 template<class Type>
671 void timeVaryingMappedFixedValueFvPatchField<Type>::updateCoeffs()
673     if (this->updated())
674     {
675         return;
676     }
678     checkTable();
680     // Interpolate between the sampled data
682     Type wantedAverage;
684     if (endSampleTime_ == -1)
685     {
686         // only start value
687         if (debug)
688         {
689             Pout<< "updateCoeffs : Sampled, non-interpolated values"
690                 << " from start time:"
691                 << sampleTimes_[startSampleTime_].name() << nl;
692         }
694         this->operator==(startSampledValues_);
695         wantedAverage = startAverage_;
696     }
697     else
698     {
699         scalar start = sampleTimes_[startSampleTime_].value();
700         scalar end = sampleTimes_[endSampleTime_].value();
702         scalar s = (this->db().time().value()-start)/(end-start);
704         if (debug)
705         {
706             Pout<< "updateCoeffs : Sampled, interpolated values"
707                 << " between start time:"
708                 << sampleTimes_[startSampleTime_].name()
709                 << " and end time:" << sampleTimes_[endSampleTime_].name()
710                 << " with weight:" << s << endl;
711         }
713         this->operator==((1-s)*startSampledValues_ + s*endSampledValues_);
714         wantedAverage = (1-s)*startAverage_ + s*endAverage_;
715     }
717     // Enforce average. Either by scaling (if scaling factor > 0.5) or by
718     // offsetting.
719     if (setAverage_)
720     {
721         const Field<Type>& fld = *this;
723         Type averagePsi =
724             gSum(this->patch().magSf()*fld)
725            /gSum(this->patch().magSf());
727         if (debug)
728         {
729             Pout<< "updateCoeffs :"
730                 << " actual average:" << averagePsi
731                 << " wanted average:" << wantedAverage
732                 << endl;
733         }
735         if (mag(averagePsi) < VSMALL)
736         {
737             // Field too small to scale. Offset instead.
738             const Type offset = wantedAverage - averagePsi;
739             if (debug)
740             {
741                 Pout<< "updateCoeffs :"
742                     << " offsetting with:" << offset << endl;
743             }
744             this->operator==(fld+offset);
745         }
746         else
747         {
748             const scalar scale = mag(wantedAverage)/mag(averagePsi);
750             if (debug)
751             {
752                 Pout<< "updateCoeffs :"
753                     << " scaling with:" << scale << endl;
754             }
755             this->operator==(scale*fld);
756         }
757     }
759     if (debug)
760     {
761         Pout<< "updateCoeffs : set fixedValue to min:" << gMin(*this)
762             << " max:" << gMax(*this) << endl;
763     }
765     fixedValueFvPatchField<Type>::updateCoeffs();
769 template<class Type>
770 void timeVaryingMappedFixedValueFvPatchField<Type>::write(Ostream& os) const
772     fvPatchField<Type>::write(os);
773     os.writeKeyword("setAverage") << setAverage_ << token::END_STATEMENT << nl;
774     this->writeEntry("value", os);
778 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
780 } // End namespace Foam
782 // ************************************************************************* //