Fix tutorials: typo in tutorials/viscoelastic/viscoelasticFluidFoam/S-MDCPP/constant...
[OpenFOAM-1.6-ext.git] / src / finiteVolume / fields / fvPatchFields / derived / timeVaryingMappedFixedValue / timeVaryingMappedFixedValueFvPatchField.C
blob027db8071bb0638df4e748ea040a4b6d29f10e0f
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright held by original author
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     fieldTableName_(iF.name()),
53     setAverage_(false),
54     referenceCS_(NULL),
55     nearestVertex_(0),
56     nearestVertexWeight_(0),
57     sampleTimes_(0),
58     startSampleTime_(-1),
59     startSampledValues_(0),
60     startAverage_(pTraits<Type>::zero),
61     endSampleTime_(-1),
62     endSampledValues_(0),
63     endAverage_(pTraits<Type>::zero)
65     if (debug)
66     {
67         Pout<< "timeVaryingMappedFixedValue :"
68             << " construct from fvPatch and internalField" << endl;
69     }
73 template<class Type>
74 timeVaryingMappedFixedValueFvPatchField<Type>::
75 timeVaryingMappedFixedValueFvPatchField
77     const timeVaryingMappedFixedValueFvPatchField<Type>& ptf,
78     const fvPatch& p,
79     const DimensionedField<Type, volMesh>& iF,
80     const fvPatchFieldMapper& mapper
83     fixedValueFvPatchField<Type>(ptf, p, iF, mapper),
84     fieldTableName_(ptf.fieldTableName_),
85     setAverage_(ptf.setAverage_),
86     referenceCS_(NULL),
87     nearestVertex_(0),
88     nearestVertexWeight_(0),
89     sampleTimes_(0),
90     startSampleTime_(-1),
91     startSampledValues_(0),
92     startAverage_(pTraits<Type>::zero),
93     endSampleTime_(-1),
94     endSampledValues_(0),
95     endAverage_(pTraits<Type>::zero)
97     if (debug)
98     {
99         Pout<< "timeVaryingMappedFixedValue"
100             << " : construct from mappedFixedValue and mapper" << endl;
101     }
105 template<class Type>
106 timeVaryingMappedFixedValueFvPatchField<Type>::
107 timeVaryingMappedFixedValueFvPatchField
109     const fvPatch& p,
110     const DimensionedField<Type, volMesh>& iF,
111     const dictionary& dict
114     fixedValueFvPatchField<Type>(p, iF),
115     fieldTableName_(iF.name()),
116     setAverage_(readBool(dict.lookup("setAverage"))),
117     referenceCS_(NULL),
118     nearestVertex_(0),
119     nearestVertexWeight_(0),
120     sampleTimes_(0),
121     startSampleTime_(-1),
122     startSampledValues_(0),
123     startAverage_(pTraits<Type>::zero),
124     endSampleTime_(-1),
125     endSampledValues_(0),
126     endAverage_(pTraits<Type>::zero)
128     if (debug)
129     {
130         Pout<< "timeVaryingMappedFixedValue : construct from dictionary"
131             << endl;
132     }
134     if (dict.found("fieldTableName"))
135     {
136         dict.lookup("fieldTableName") >> fieldTableName_;
137     }
139     if (dict.found("value"))
140     {
141         fvPatchField<Type>::operator==(Field<Type>("value", dict, p.size()));
142     }
143     else
144     {
145         updateCoeffs();
146     }
150 template<class Type>
151 timeVaryingMappedFixedValueFvPatchField<Type>::
152 timeVaryingMappedFixedValueFvPatchField
154     const timeVaryingMappedFixedValueFvPatchField<Type>& ptf
157     fixedValueFvPatchField<Type>(ptf),
158     fieldTableName_(ptf.fieldTableName_),
159     setAverage_(ptf.setAverage_),
160     referenceCS_(ptf.referenceCS_),
161     nearestVertex_(ptf.nearestVertex_),
162     nearestVertexWeight_(ptf.nearestVertexWeight_),
163     sampleTimes_(ptf.sampleTimes_),
164     startSampleTime_(ptf.startSampleTime_),
165     startSampledValues_(ptf.startSampledValues_),
166     startAverage_(ptf.startAverage_),
167     endSampleTime_(ptf.endSampleTime_),
168     endSampledValues_(ptf.endSampledValues_),
169     endAverage_(ptf.endAverage_)
171     if (debug)
172     {
173         Pout<< "timeVaryingMappedFixedValue : copy construct"
174             << endl;
175     }
180 template<class Type>
181 timeVaryingMappedFixedValueFvPatchField<Type>::
182 timeVaryingMappedFixedValueFvPatchField
184     const timeVaryingMappedFixedValueFvPatchField<Type>& ptf,
185     const DimensionedField<Type, volMesh>& iF
188     fixedValueFvPatchField<Type>(ptf, iF),
189     fieldTableName_(ptf.fieldTableName_),
190     setAverage_(ptf.setAverage_),
191     referenceCS_(ptf.referenceCS_),
192     nearestVertex_(ptf.nearestVertex_),
193     nearestVertexWeight_(ptf.nearestVertexWeight_),
194     sampleTimes_(ptf.sampleTimes_),
195     startSampleTime_(ptf.startSampleTime_),
196     startSampledValues_(ptf.startSampledValues_),
197     startAverage_(ptf.startAverage_),
198     endSampleTime_(ptf.endSampleTime_),
199     endSampledValues_(ptf.endSampledValues_),
200     endAverage_(ptf.endAverage_)
202     if (debug)
203     {
204         Pout<< "timeVaryingMappedFixedValue :"
205             << " copy construct, resetting internal field" << endl;
206     }
210 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
212 template<class Type>
213 void timeVaryingMappedFixedValueFvPatchField<Type>::autoMap
215     const fvPatchFieldMapper& m
218     fixedValueFvPatchField<Type>::autoMap(m);
219     if (startSampledValues_.size() > 0)
220     {
221         startSampledValues_.autoMap(m);
222         endSampledValues_.autoMap(m);
223     }
227 template<class Type>
228 void timeVaryingMappedFixedValueFvPatchField<Type>::rmap
230     const fvPatchField<Type>& ptf,
231     const labelList& addr
234     fixedValueFvPatchField<Type>::rmap(ptf, addr);
236     const timeVaryingMappedFixedValueFvPatchField<Type>& tiptf =
237         refCast<const timeVaryingMappedFixedValueFvPatchField<Type> >(ptf);
239     startSampledValues_.rmap(tiptf.startSampledValues_, addr);
240     endSampledValues_.rmap(tiptf.endSampledValues_, addr);
244 template<class Type>
245 void timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()
247     // Read the sample points
249     pointIOField samplePoints
250     (
251         IOobject
252         (
253             "points",
254             this->db().time().constant(),
255             "boundaryData"/this->patch().name(),
256             this->db(),
257             IOobject::MUST_READ,
258             IOobject::AUTO_WRITE,
259             false
260         )
261     );
263     const fileName samplePointsFile = samplePoints.filePath();
265     if (debug)
266     {
267         Info<< "timeVaryingMappedFixedValueFvPatchField :"
268             << " Read " << samplePoints.size() << " sample points from "
269             << samplePointsFile << endl;
270     }
272     // Determine coordinate system from samplePoints
274     if (samplePoints.size() < 3)
275     {
276         FatalErrorIn
277         (
278             "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
279         )   << "Only " << samplePoints.size() << " points read from file "
280             << samplePoints.objectPath() << nl
281             << "Need at least three non-colinear samplePoints"
282             << " to be able to interpolate."
283             << "\n    on patch " << this->patch().name()
284             << " of field " << this->dimensionedInternalField().name()
285             << " in file " << this->dimensionedInternalField().objectPath()
286             << exit(FatalError);
287     }
289     const point& p0 = samplePoints[0];
291     // Find point separate from p0
292     vector e1;
293     label index1 = -1;
295     for (label i = 1; i < samplePoints.size(); i++)
296     {
297         e1 = samplePoints[i] - p0;
299         scalar magE1 = mag(e1);
301         if (magE1 > SMALL)
302         {
303             e1 /= magE1;
304             index1 = i;
305             break;
306         }
307     }
309     // Find point that makes angle with n1
310     label index2 = -1;
311     vector e2;
312     vector n;
314     for (label i = index1+1; i < samplePoints.size(); i++)
315     {
316         e2 = samplePoints[i] - p0;
318         scalar magE2 = mag(e2);
320         if (magE2 > SMALL)
321         {
322             e2 /= magE2;
324             n = e1^e2;
326             scalar magN = mag(n);
328             if (magN > SMALL)
329             {
330                 index2 = i;
331                 n /= magN;
332                 break;
333             }
334         }
335     }
337     if (index2 == -1)
338     {
339         FatalErrorIn
340         (
341             "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
342         )   << "Cannot find points that make valid normal." << nl
343             << "Need at least three sample points which are not in a line."
344             << "\n    on patch " << this->patch().name()
345             << " of points " << samplePoints.name()
346             << " in file " << samplePoints.objectPath()
347             << exit(FatalError);
348     }
350     if (debug)
351     {
352         Info<< "timeVaryingMappedFixedValueFvPatchField :"
353             << " Used points " << p0 << ' ' << samplePoints[index1]
354             << ' ' << samplePoints[index2]
355             << " to define coordinate system with normal " << n << endl;
356     }
358     referenceCS_.reset
359     (
360         new coordinateSystem
361         (
362             "reference",
363             p0,  // origin
364             n,   // normal
365             e1   // 0-axis
366         )
367     );
369     tmp<vectorField> tlocalVertices
370     (
371         referenceCS().localPosition(samplePoints)
372     );
373     const vectorField& localVertices = tlocalVertices();
375     // Determine triangulation
376     List<vector2D> localVertices2D(localVertices.size());
377     forAll(localVertices, i)
378     {
379         localVertices2D[i][0] = localVertices[i][0];
380         localVertices2D[i][1] = localVertices[i][1];
381     }
383     triSurface s(triSurfaceTools::delaunay2D(localVertices2D));
385     tmp<pointField> localFaceCentres
386     (
387         referenceCS().localPosition
388         (
389             this->patch().patch().faceCentres()
390         )
391     );
393     if (debug)
394     {
395         Pout<< "readSamplePoints :"
396             <<" Dumping triangulated surface to triangulation.stl" << endl;
397         s.write(this->db().time().path()/"triangulation.stl");
399         OFstream str(this->db().time().path()/"localFaceCentres.obj");
400         Pout<< "readSamplePoints :"
401             << " Dumping face centres to " << str.name() << endl;
403         forAll(localFaceCentres(), i)
404         {
405             const point& p = localFaceCentres()[i];
406             str<< "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
407         }
408     }
410     // Determine interpolation onto face centres.
411     triSurfaceTools::calcInterpolationWeights
412     (
413         s,
414         localFaceCentres,   // points to interpolate to
415         nearestVertex_,
416         nearestVertexWeight_
417     );
421     // Read the times for which data is available
423     const fileName samplePointsDir = samplePointsFile.path();
425     sampleTimes_ = Time::findTimes(samplePointsDir);
427     if (debug)
428     {
429         Info<< "timeVaryingMappedFixedValueFvPatchField : In directory "
430             << samplePointsDir << " found times " << timeNames(sampleTimes_)
431             << endl;
432     }
436 template<class Type>
437 wordList timeVaryingMappedFixedValueFvPatchField<Type>::timeNames
439     const instantList& times
442     wordList names(times.size());
444     forAll(times, i)
445     {
446         names[i] = times[i].name();
447     }
448     return names;
452 template<class Type>
453 void timeVaryingMappedFixedValueFvPatchField<Type>::findTime
455     const fileName& instance,
456     const fileName& local,
457     const scalar timeVal,
458     label& lo,
459     label& hi
460 ) const
462     lo = startSampleTime_;
463     hi = -1;
465     for (label i = startSampleTime_+1; i < sampleTimes_.size(); i++)
466     {
467         if (sampleTimes_[i].value() > timeVal)
468         {
469             break;
470         }
471         else
472         {
473             lo = i;
474         }
475     }
477     if (lo == -1)
478     {
479         FatalErrorIn("findTime")
480             << "Cannot find starting sampling values for current time "
481             << timeVal << nl
482             << "Have sampling values for times "
483             << timeNames(sampleTimes_) << nl
484             << "In directory "
485             <<  this->db().time().constant()/"boundaryData"/this->patch().name()
486             << "\n    on patch " << this->patch().name()
487             << " of field " << fieldTableName_
488             << exit(FatalError);
489     }
491     if (lo < sampleTimes_.size()-1)
492     {
493         hi = lo+1;
494     }
497     if (debug)
498     {
499         if (hi == -1)
500         {
501             Pout<< "findTime : Found time " << timeVal << " after"
502                 << " index:" << lo << " time:" << sampleTimes_[lo].value()
503                 << endl;
504         }
505         else
506         {
507             Pout<< "findTime : Found time " << timeVal << " inbetween"
508                 << " index:" << lo << " time:" << sampleTimes_[lo].value()
509                 << " and index:" << hi << " time:" << sampleTimes_[hi].value()
510                 << endl;
511         }
512     }
516 template<class Type>
517 void timeVaryingMappedFixedValueFvPatchField<Type>::checkTable()
519     // Initialise
520     if (startSampleTime_ == -1 && endSampleTime_ == -1)
521     {
522         readSamplePoints();
523     }
525     // Find current time in sampleTimes
526     label lo = -1;
527     label hi = -1;
529     findTime
530     (
531         this->db().time().constant(),
532         "boundaryData"/this->patch().name(),
533         this->db().time().value(),
534         lo,
535         hi
536     );
538     // Update sampled data fields.
540     if (lo != startSampleTime_)
541     {
542         startSampleTime_ = lo;
544         if (startSampleTime_ == endSampleTime_)
545         {
546             // No need to reread since are end values
547             if (debug)
548             {
549                 Pout<< "checkTable : Setting startValues to (already read) "
550                     <<   "boundaryData"
551                         /this->patch().name()
552                         /sampleTimes_[startSampleTime_].name()
553                     << endl;
554             }
555             startSampledValues_ = endSampledValues_;
556             startAverage_ = endAverage_;
557         }
558         else
559         {
560             if (debug)
561             {
562                 Pout<< "checkTable : Reading startValues from "
563                     <<   "boundaryData"
564                         /this->patch().name()
565                         /sampleTimes_[lo].name()
566                     << endl;
567             }
570             // Reread values and interpolate
571             AverageIOField<Type> vals
572             (
573                 IOobject
574                 (
575                     fieldTableName_,
576                     this->db().time().constant(),
577                     "boundaryData"
578                    /this->patch().name()
579                    /sampleTimes_[startSampleTime_].name(),
580                     this->db(),
581                     IOobject::MUST_READ,
582                     IOobject::AUTO_WRITE,
583                     false
584                 )
585             );
587             startAverage_ = vals.average();
588             startSampledValues_ = interpolate(vals);
589         }
590     }
592     if (hi != endSampleTime_)
593     {
594         endSampleTime_ = hi;
596         if (endSampleTime_ == -1)
597         {
598             // endTime no longer valid. Might as well clear endValues.
599             if (debug)
600             {
601                 Pout<< "checkTable : Clearing endValues" << endl;
602             }
603             endSampledValues_.clear();
604         }
605         else
606         {
607             if (debug)
608             {
609                 Pout<< "checkTable : Reading endValues from "
610                     <<   "boundaryData"
611                         /this->patch().name()
612                         /sampleTimes_[endSampleTime_].name()
613                     << endl;
614             }
615             // Reread values and interpolate
616             AverageIOField<Type> vals
617             (
618                 IOobject
619                 (
620                     fieldTableName_,
621                     this->db().time().constant(),
622                     "boundaryData"
623                    /this->patch().name()
624                    /sampleTimes_[endSampleTime_].name(),
625                     this->db(),
626                     IOobject::MUST_READ,
627                     IOobject::AUTO_WRITE,
628                     false
629                 )
630             );
631             endAverage_ = vals.average();
632             endSampledValues_ = interpolate(vals);
633         }
634     }
638 template<class Type>
639 tmp<Field<Type> > timeVaryingMappedFixedValueFvPatchField<Type>::interpolate
641     const Field<Type>& sourceFld
642 ) const
644     tmp<Field<Type> > tfld(new Field<Type>(nearestVertex_.size()));
645     Field<Type>& fld = tfld();
647     forAll(fld, i)
648     {
649         const FixedList<label, 3>& verts = nearestVertex_[i];
650         const FixedList<scalar, 3>& w = nearestVertexWeight_[i];
652         if (verts[2] == -1)
653         {
654             if (verts[1] == -1)
655             {
656                 // Use vertex0 only
657                 fld[i] = sourceFld[verts[0]];
658             }
659             else
660             {
661                 // Use vertex 0,1
662                 fld[i] =
663                     w[0]*sourceFld[verts[0]]
664                   + w[1]*sourceFld[verts[1]];
665             }
666         }
667         else
668         {
669             fld[i] =
670                 w[0]*sourceFld[verts[0]]
671               + w[1]*sourceFld[verts[1]]
672               + w[2]*sourceFld[verts[2]];
673         }
674     }
675     return tfld;
679 template<class Type>
680 void timeVaryingMappedFixedValueFvPatchField<Type>::updateCoeffs()
682     if (this->updated())
683     {
684         return;
685     }
687     checkTable();
689     // Interpolate between the sampled data
691     Type wantedAverage;
693     if (endSampleTime_ == -1)
694     {
695         // only start value
696         if (debug)
697         {
698             Pout<< "updateCoeffs : Sampled, non-interpolated values"
699                 << " from start time:"
700                 << sampleTimes_[startSampleTime_].name() << nl;
701         }
703         this->operator==(startSampledValues_);
704         wantedAverage = startAverage_;
705     }
706     else
707     {
708         scalar start = sampleTimes_[startSampleTime_].value();
709         scalar end = sampleTimes_[endSampleTime_].value();
711         scalar s = (this->db().time().value()-start)/(end-start);
713         if (debug)
714         {
715             Pout<< "updateCoeffs : Sampled, interpolated values"
716                 << " between start time:"
717                 << sampleTimes_[startSampleTime_].name()
718                 << " and end time:" << sampleTimes_[endSampleTime_].name()
719                 << " with weight:" << s << endl;
720         }
722         this->operator==((1-s)*startSampledValues_ + s*endSampledValues_);
723         wantedAverage = (1-s)*startAverage_ + s*endAverage_;
724     }
726     // Enforce average. Either by scaling (if scaling factor > 0.5) or by
727     // offsetting.
728     if (setAverage_)
729     {
730         const Field<Type>& fld = *this;
732         Type averagePsi =
733             gSum(this->patch().magSf()*fld)
734            /gSum(this->patch().magSf());
736         if (debug)
737         {
738             Pout<< "updateCoeffs :"
739                 << " actual average:" << averagePsi
740                 << " wanted average:" << wantedAverage
741                 << endl;
742         }
744         if (mag(averagePsi) < VSMALL)
745         {
746             // Field too small to scale. Offset instead.
747             const Type offset = wantedAverage - averagePsi;
748             if (debug)
749             {
750                 Pout<< "updateCoeffs :"
751                     << " offsetting with:" << offset << endl;
752             }
753             this->operator==(fld+offset);
754         }
755         else
756         {
757             const scalar scale = mag(wantedAverage)/mag(averagePsi);
759             if (debug)
760             {
761                 Pout<< "updateCoeffs :"
762                     << " scaling with:" << scale << endl;
763             }
764             this->operator==(scale*fld);
765         }
766     }
768     if (debug)
769     {
770         Pout<< "updateCoeffs : set fixedValue to min:" << gMin(*this)
771             << " max:" << gMax(*this) << endl;
772     }
774     fixedValueFvPatchField<Type>::updateCoeffs();
778 template<class Type>
779 void timeVaryingMappedFixedValueFvPatchField<Type>::write(Ostream& os) const
781     fvPatchField<Type>::write(os);
782     os.writeKeyword("setAverage") << setAverage_ << token::END_STATEMENT << nl;
784     if (fieldTableName_ != this->dimensionedInternalField().name())
785     {
786         os.writeKeyword("fieldTableName") << fieldTableName_ << token::END_STATEMENT << nl;
787     }
789     this->writeEntry("value", os);
793 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
795 } // End namespace Foam
797 // ************************************************************************* //