Forward compatibility: flex
[foam-extend-3.2.git] / src / foam / db / Time / foamTime.C
blobe46a8492b10b617edd8751614fee4c32310aa479
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 \*---------------------------------------------------------------------------*/
26 #include "objectRegistry.H"
27 #include "foamTime.H"
28 #include "PstreamReduceOps.H"
30 #include "profilingPool.H"
31 #include "profiling.H"
33 #include <sstream>
35 // * * * * * * * * * * * * * Static Member Data  * * * * * * * * * * * * * * //
37 defineTypeNameAndDebug(Foam::Time, 0);
39 template<>
40 const char* Foam::NamedEnum<Foam::Time::stopAtControls, 4>::names[] =
42     "endTime",
43     "noWriteNow",
44     "writeNow",
45     "nextWrite"
48 const Foam::NamedEnum<Foam::Time::stopAtControls, 4>
49     Foam::Time::stopAtControlNames_;
51 template<>
52 const char* Foam::NamedEnum<Foam::Time::writeControls, 5>::names[] =
54     "timeStep",
55     "runTime",
56     "adjustableRunTime",
57     "clockTime",
58     "cpuTime"
61 const Foam::NamedEnum<Foam::Time::writeControls, 5>
62     Foam::Time::writeControlNames_;
64 Foam::Time::fmtflags Foam::Time::format_(Foam::Time::general);
65 int Foam::Time::precision_(6);
67 Foam::word Foam::Time::controlDictName("controlDict");
70 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
72 void Foam::Time::adjustDeltaT()
74     if (writeControl_ == wcAdjustableRunTime)
75     {
76         scalar timeToNextWrite = max
77         (
78             scalar(0),
79             (outputTimeIndex_ + 1)*writeInterval_ - (value() - startTime_)
80         );
82         label nStepsToNextWrite = label(timeToNextWrite/deltaT_ - SMALL) + 1;
83         scalar newDeltaT = timeToNextWrite/nStepsToNextWrite;
85         // Control the increase of the time step to within a factor of 2
86         // and the decrease within a factor of 5.
87         if (newDeltaT >= deltaT_)
88         {
89             deltaT_ = min(newDeltaT, 2.0*deltaT_);
90         }
91         else
92         {
93             deltaT_ = max(newDeltaT, 0.2*deltaT_);
94         }
95     }
99 void Foam::Time::setControls()
101     // default is to resume calculation from "latestTime"
102     word startFrom = controlDict_.lookupOrDefault<word>
103     (
104         "startFrom",
105         "latestTime"
106     );
108     if (startFrom == "startTime")
109     {
110         controlDict_.lookup("startTime") >> startTime_;
111     }
112     else
113     {
114         // Search directory for valid time directories
115         instantList timeDirs = findTimes(path());
117         if (startFrom == "firstTime")
118         {
119             if (timeDirs.size())
120             {
121                 startTime_ = timeDirs[0].value();
122             }
123         }
124         else if (startFrom == "latestTime")
125         {
126             if (timeDirs.size())
127             {
128                 startTime_ = timeDirs[timeDirs.size()-1].value();
129             }
130         }
131         else
132         {
133             FatalIOErrorIn("Time::setControls()", controlDict_)
134                 << "expected startTime, firstTime or latestTime"
135                 << " found '" << startFrom << "'"
136                 << exit(FatalIOError);
137         }
138     }
140     setTime(startTime_, 0);
142     readDict();
143     deltaTSave_ = deltaT_;
144     deltaT0_ = deltaTSave_;
146     if (Pstream::parRun())
147     {
148         scalar sumStartTime = startTime_;
149         reduce(sumStartTime, sumOp<scalar>());
150         if
151         (
152             mag(Pstream::nProcs()*startTime_ - sumStartTime)
153           > Pstream::nProcs()*deltaT_/10.0
154         )
155         {
156             FatalIOErrorIn("Time::setControls()", controlDict_)
157                 << "Start time is not the same for all processors" << nl
158                 << "processor " << Pstream::myProcNo() << " has startTime "
159                 << startTime_ << exit(FatalIOError);
160         }
161     }
163     IOdictionary timeDict
164     (
165         IOobject
166         (
167             "time",
168             timeName(),
169             "uniform",
170             *this,
171             IOobject::READ_IF_PRESENT,
172             IOobject::NO_WRITE,
173             false
174         )
175     );
177     if (timeDict.readIfPresent("deltaT", deltaTSave_))
178     {
179         deltaT0_ = deltaTSave_;
180     }
182     if (timeDict.readIfPresent("index", startTimeIndex_))
183     {
184         timeIndex_ = startTimeIndex_;
185     }
189 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
191 Foam::Time::Time
193     const word& controlDictName,
194     const fileName& rootPath,
195     const fileName& caseName,
196     const word& systemName,
197     const word& constantName,
198     const bool enableFunctionObjects
201     TimePaths
202     (
203         rootPath,
204         caseName,
205         systemName,
206         constantName
207     ),
209     objectRegistry(*this),
211     controlDict_
212     (
213         IOobject
214         (
215             controlDictName,
216             system(),
217             *this,
218             IOobject::MUST_READ,
219             IOobject::NO_WRITE,
220             false
221         )
222     ),
224     startTimeIndex_(0),
225     startTime_(0),
226     endTime_(0),
228     stopAt_(saEndTime),
229     writeControl_(wcTimeStep),
230     writeInterval_(GREAT),
231     purgeWrite_(0),
232     subCycling_(false),
234     writeFormat_(IOstream::ASCII),
235     writeVersion_(IOstream::currentVersion),
236     writeCompression_(IOstream::UNCOMPRESSED),
237     graphFormat_("raw"),
238     runTimeModifiable_(true),
240     readLibs_(controlDict_, "libs"),
241     functionObjects_(*this, enableFunctionObjects)
243     setControls();
245     profilingPool::initProfiling
246     (
247         IOobject
248         (
249             "profilingInfo",
250             timeName(),
251             "uniform",
252             *this,
253             IOobject::NO_READ,
254             IOobject::AUTO_WRITE
255         ),
256         *this
257     );
261 Foam::Time::Time
263     const dictionary& dict,
264     const fileName& rootPath,
265     const fileName& caseName,
266     const word& systemName,
267     const word& constantName,
268     const bool enableFunctionObjects
271     TimePaths
272     (
273         rootPath,
274         caseName,
275         systemName,
276         constantName
277     ),
279     objectRegistry(*this),
281     controlDict_
282     (
283         IOobject
284         (
285             controlDictName,
286             system(),
287             *this,
288             IOobject::NO_READ,
289             IOobject::NO_WRITE,
290             false
291         ),
292         dict
293     ),
295     startTimeIndex_(0),
296     startTime_(0),
297     endTime_(0),
299     stopAt_(saEndTime),
300     writeControl_(wcTimeStep),
301     writeInterval_(GREAT),
302     purgeWrite_(0),
303     subCycling_(false),
305     writeFormat_(IOstream::ASCII),
306     writeVersion_(IOstream::currentVersion),
307     writeCompression_(IOstream::UNCOMPRESSED),
308     graphFormat_("raw"),
309     runTimeModifiable_(true),
311     readLibs_(controlDict_, "libs"),
312     functionObjects_(*this, enableFunctionObjects)
314     setControls();
316     profilingPool::initProfiling
317     (
318         IOobject
319         (
320             "profilingInfo",
321             timeName(),
322             "uniform",
323             *this,
324             IOobject::NO_READ,
325             IOobject::AUTO_WRITE
326         ),
327         *this
328     );
332 Foam::Time::Time
334     const fileName& rootPath,
335     const fileName& caseName,
336     const word& systemName,
337     const word& constantName,
338     const bool enableFunctionObjects
341     TimePaths
342     (
343         rootPath,
344         caseName,
345         systemName,
346         constantName
347     ),
349     objectRegistry(*this),
351     controlDict_
352     (
353         IOobject
354         (
355             controlDictName,
356             system(),
357             *this,
358             IOobject::NO_READ,
359             IOobject::NO_WRITE,
360             false
361         )
362     ),
364     startTimeIndex_(0),
365     startTime_(0),
366     endTime_(0),
368     stopAt_(saEndTime),
369     writeControl_(wcTimeStep),
370     writeInterval_(GREAT),
371     purgeWrite_(0),
372     subCycling_(false),
374     writeFormat_(IOstream::ASCII),
375     writeVersion_(IOstream::currentVersion),
376     writeCompression_(IOstream::UNCOMPRESSED),
377     graphFormat_("raw"),
378     runTimeModifiable_(true),
380     readLibs_(controlDict_, "libs"),
381     functionObjects_(*this, enableFunctionObjects)
383     profilingPool::initProfiling
384     (
385         IOobject
386         (
387             "profilingInfo",
388             timeName(),
389             "uniform",
390             *this,
391             IOobject::NO_READ,
392             IOobject::AUTO_WRITE
393         ),
394         *this
395     );
399 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
401 Foam::Time::~Time()
403     // destroy function objects first
404     functionObjects_.clear();
406     profilingPool::stopProfiling(*this);
410 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
412 Foam::word Foam::Time::timeName(const scalar t)
414     std::ostringstream buf;
415     buf.setf(ios_base::fmtflags(format_), ios_base::floatfield);
416     buf.precision(precision_);
417     buf << t;
418     return buf.str();
422 Foam::word Foam::Time::timeName() const
424     return dimensionedScalar::name();
428 // Search the construction path for times
429 Foam::instantList Foam::Time::times() const
431     return findTimes(path());
435 Foam::word Foam::Time::findInstancePath(const instant& t) const
437     instantList timeDirs = findTimes(path());
439     forAllReverse(timeDirs, timeI)
440     {
441         if (timeDirs[timeI] == t)
442         {
443             return timeDirs[timeI].name();
444         }
445     }
447     return word::null;
451 Foam::instant Foam::Time::findClosestTime(const scalar t) const
453     instantList timeDirs = findTimes(path());
455     // there is only one time (likely "constant") so return it
456     if (timeDirs.size() == 1)
457     {
458         return timeDirs[0];
459     }
461     if (t < timeDirs[1].value())
462     {
463         return timeDirs[1];
464     }
465     else if (t > timeDirs[timeDirs.size()-1].value())
466     {
467         return timeDirs[timeDirs.size()-1];
468     }
470     label nearestIndex = -1;
471     scalar deltaT = GREAT;
473     for (label timeI=1; timeI < timeDirs.size(); ++timeI)
474     {
475         scalar diff = mag(timeDirs[timeI].value() - t);
476         if (diff < deltaT)
477         {
478             deltaT = diff;
479             nearestIndex = timeI;
480         }
481     }
483     return timeDirs[nearestIndex];
487 // This should work too,
488 // if we don't worry about checking "constant" explicitly
490 // Foam::instant Foam::Time::findClosestTime(const scalar t) const
491 // {
492 //     instantList timeDirs = findTimes(path());
493 //     label timeIndex = min(findClosestTimeIndex(timeDirs, t), 0);
494 //     return timeDirs[timeIndex];
495 // }
497 Foam::label Foam::Time::findClosestTimeIndex
499     const instantList& timeDirs,
500     const scalar t
503     label nearestIndex = -1;
504     scalar deltaT = GREAT;
506     forAll(timeDirs, timeI)
507     {
508         if (timeDirs[timeI].name() == "constant") continue;
510         scalar diff = mag(timeDirs[timeI].value() - t);
511         if (diff < deltaT)
512         {
513             deltaT = diff;
514             nearestIndex = timeI;
515         }
516     }
518     return nearestIndex;
522 Foam::label Foam::Time::startTimeIndex() const
524     return startTimeIndex_;
528 Foam::dimensionedScalar Foam::Time::startTime() const
530     return dimensionedScalar("startTime", dimTime, startTime_);
534 Foam::dimensionedScalar Foam::Time::endTime() const
536     return dimensionedScalar("endTime", dimTime, endTime_);
540 bool Foam::Time::run() const
542     bool running = value() < (endTime_ - 0.5*deltaT_);
544     if (!subCycling_)
545     {
546         // only execute when the condition is no longer true
547         // ie, when exiting the control loop
548         if (!running && timeIndex_ != startTimeIndex_)
549         {
550             addProfile2(fo,"functionObjects_.end()");
552             // Note, end() also calls an indirect start() as required
553             functionObjects_.end();
554         }
555     }
557     return running;
561 bool Foam::Time::loop()
563     bool running = run();
565     if (running)
566     {
567         operator++();
568     }
570     return running;
574 bool Foam::Time::end() const
576     return value() > (endTime_ + 0.5*deltaT_);
580 void Foam::Time::setTime(const Time& t)
582     value() = t.value();
583     dimensionedScalar::name() = t.dimensionedScalar::name();
584     timeIndex_ = t.timeIndex_;
588 void Foam::Time::setTime(const instant& inst, const label newIndex)
590     value() = inst.value();
591     dimensionedScalar::name() = inst.name();
592     timeIndex_ = newIndex;
594     IOdictionary timeDict
595     (
596         IOobject
597         (
598             "time",
599             timeName(),
600             "uniform",
601             *this,
602             IOobject::READ_IF_PRESENT,
603             IOobject::NO_WRITE,
604             false
605         )
606     );
608     timeDict.readIfPresent("deltaT", deltaT_);
609     timeDict.readIfPresent("deltaT0", deltaT0_);
610     timeDict.readIfPresent("index", timeIndex_);
614 void Foam::Time::setTime
616     const dimensionedScalar& newTime,
617     const label newIndex
620     setTime(newTime.value(), newIndex);
624 void Foam::Time::setTime(const scalar newTime, const label newIndex)
626     value() = newTime;
627     dimensionedScalar::name() = timeName(timeToUserTime(newTime));
628     timeIndex_ = newIndex;
632 void Foam::Time::setStopAt(const stopAtControls& sa)
634     stopAt_ = sa;
638 void Foam::Time::setEndTime(const dimensionedScalar& endTime)
640     setEndTime(endTime.value());
644 void Foam::Time::setEndTime(const scalar endTime)
646     endTime_ = endTime;
650 void Foam::Time::setDeltaT
652     const dimensionedScalar& deltaT,
653     const bool bAdjustDeltaT
656     setDeltaT(deltaT.value(), bAdjustDeltaT);
660 void Foam::Time::setDeltaT(const scalar deltaT, const bool bAdjustDeltaT)
662     deltaT_ = deltaT;
663     deltaTchanged_ = true;
665     if (bAdjustDeltaT)
666     {
667         adjustDeltaT();
668     }
672 void Foam::Time::setWriteControl(const writeControls& wc)
674     writeControl_ = wc;
678 void Foam::Time::setWriteInterval(const scalar writeInterval)
680     writeInterval_ = writeInterval;
684 Foam::TimeState Foam::Time::subCycle(const label nSubCycles)
686     subCycling_ = true;
687     prevTimeState_.set(new TimeState(*this));
689     setTime(*this - deltaT(), (timeIndex() - 1)*nSubCycles);
690     deltaT_ /= nSubCycles;
691     deltaT0_ /= nSubCycles;
692     deltaTSave_ = deltaT0_;
694     return prevTimeState();
698 void Foam::Time::endSubCycle()
700     if (subCycling_)
701     {
702         subCycling_ = false;
703         TimeState::operator=(prevTimeState());
704         prevTimeState_.clear();
705     }
709 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
711 Foam::Time& Foam::Time::operator+=(const dimensionedScalar& deltaT)
713     return operator+=(deltaT.value());
717 Foam::Time& Foam::Time::operator+=(const scalar deltaT)
719     setDeltaT(deltaT);
720     return operator++();
724 Foam::Time& Foam::Time::operator++()
726     readModifiedObjects();
728     if (!subCycling_)
729     {
730         if (timeIndex_ == startTimeIndex_)
731         {
732             addProfile2(fo,"functionObjects_.start()");
734             functionObjects_.start();
735         }
736         else
737         {
738             addProfile2(fo,"functionObjects_.execute()");
740             functionObjects_.execute();
741         }
742     }
744     deltaT0_ = deltaTSave_;
745     deltaTSave_ = deltaT_;
747     const word oldTimeName = dimensionedScalar::name();
749     setTime(value() + deltaT_, timeIndex_ + 1);
751     // If the time is very close to zero reset to zero
752     if (mag(value()) < 10*SMALL*deltaT_)
753     {
754         setTime(0.0, timeIndex_);
755     }
757     // Check that new time representation differs from old one
758     if (dimensionedScalar::name() == oldTimeName)
759     {
760         int oldPrecision = precision_;
761         do
762         {
763             precision_++;
764             setTime(value(), timeIndex());
765         }
766         while (precision_ < 100 && dimensionedScalar::name() == oldTimeName);
768         WarningIn("Time::operator++()")
769             << "Increased the timePrecision from " << oldPrecision
770             << " to " << precision_
771             << " to distinguish between timeNames at time " << value()
772             << endl;
773     }
775     switch (writeControl_)
776     {
777         case wcTimeStep:
778             outputTime_ = !(timeIndex_ % label(writeInterval_));
779         break;
781         case wcRunTime:
782         case wcAdjustableRunTime:
783         {
784             label outputIndex =
785                 label(((value() - startTime_) + 0.5*deltaT_)/writeInterval_);
787             if (outputIndex > outputTimeIndex_)
788             {
789                 outputTime_ = true;
790                 outputTimeIndex_ = outputIndex;
791             }
792             else
793             {
794                 outputTime_ = false;
795             }
796         }
797         break;
799         case wcCpuTime:
800         {
801             label outputIndex = label(elapsedCpuTime()/writeInterval_);
802             if (outputIndex > outputTimeIndex_)
803             {
804                 outputTime_ = true;
805                 outputTimeIndex_ = outputIndex;
806             }
807             else
808             {
809                 outputTime_ = false;
810             }
811         }
812         break;
814         case wcClockTime:
815         {
816             label outputIndex = label(elapsedClockTime()/writeInterval_);
817             if (outputIndex > outputTimeIndex_)
818             {
819                 outputTime_ = true;
820                 outputTimeIndex_ = outputIndex;
821             }
822             else
823             {
824                 outputTime_ = false;
825             }
826         }
827         break;
828     }
830     // see if endTime needs adjustment to stop at the next run()/end() check
831     if (!end())
832     {
833         if (stopAt_ == saNoWriteNow)
834         {
835             endTime_ = value();
836         }
837         else if (stopAt_ == saWriteNow)
838         {
839             endTime_ = value();
840             outputTime_ = true;
841         }
842         else if (stopAt_ == saNextWrite && outputTime_ == true)
843         {
844             endTime_ = value();
845         }
846     }
848     return *this;
852 Foam::Time& Foam::Time::operator++(int)
854     return operator++();
858 // ************************************************************************* //