criptic v1
Cosmic Ray Interstellar Propagation Tool using Itô Calculus
Loading...
Searching...
No Matches
TimeInterp.H
Go to the documentation of this file.
1
11#ifndef _TIMEINTERP_H_
12#define _TIMEINTERP_H_
13
14#include <vector>
15#include <string>
16#include <regex>
17#include <algorithm>
18#include <filesystem>
19#include <type_traits>
20#include "CartesianGrid.H"
21#include "GizmoGas.H"
22#include "Gas.H"
23#include "GasData.H"
24
25namespace criptic {
26 namespace gas {
27
40 template <typename T> class TimeInterp : public Gas {
41
42 static_assert(std::is_base_of<Gas, T>::value,
43 "Template class of TimeInterp must be derived from Gas");
44
45 public:
46
58 const Geometry& geom_,
59 const IdxType nBB,
60 const int nGhost,
61 std::vector<Real> TBB_ = {},
62 std::vector<Real> WBB_ = {}) {
63
64 // Save verbosity
65 verbosity = 1;
66 pp.query("verbosity", verbosity);
67
68 std::string dirName, tempName;
69 if (pp.query("gas.slice_dir", dirName) &&
70 pp.query("gas.slice_filename", tempName)) {
71 std::regex reg(tempName);
72
73 // Find all the file names that match the template; these are files
74 // in the directory dirName with names that are regex matches to
75 // slice_filename
76 for (auto const& file : std::filesystem::directory_iterator(dirName)) {
77 if (!file.is_regular_file()) continue; // Skip non-files
78 std::string fname = file.path().filename().string(); // Extract file name
79 if (std::regex_search(fname, reg)) // Check for match
80 //snapFiles.push_back(dirName + file.path().string());
81 snapFiles.push_back(file.path().string());
82 }
83 };
84
85
86 // Read the time slices available; this can be specified either by
87 // just giving the time between slices and the total number
88 // available, or by giving a list of all times available
89 // Read in gas.times to get tSlice. If it is not supplied, continue
90 if (!pp.query("gas.times", tSlice)) {
91 Real dt;
92 int nSlice;
93 // Handle case where nSlice and dt are supplied. Snapshot times will
94 // be an integer number times dt
95 if (pp.query("gas.dt", dt) && pp.query("gas.nSlice", nSlice)) {
96 if (nSlice < 2) {
97 MPIUtil::haltRun("TimeInterp: need >= 2 slice times for gas.nSlice",
99 }
100 tSlice.resize(nSlice);
101 for (int i=0; i < nSlice; i++) tSlice[i] = i*dt;
102 } else {
103 tSlice.resize(snapFiles.size());
104 for (IdxType i=0; i < snapFiles.size(); i++) {
105 // Find times of snapshot files individually.
106 // NOTE: T::loadTime must be supplied in the definition of T
107 tSlice[i] = T::loadTime(snapFiles[i]);
108 }
109 }
110 }
111 // Sort snapshot files and time slices
113 std::sort(tSlice.begin(), tSlice.end());
114
115 // Supply an offset time to start the simulation at
116 Real slice_t0 = 0;
117 bool t0_supplied = pp.query("gas.slice_t0", slice_t0);
118
119 if (slice_t0<0) {
120 MPIUtil::haltRun("TimeInterp: gas.slice_t0 is negative", errBadInputFile);
121 }
122
123 if (t0_supplied) {
124 // Ensure t0 is before the last snapshot
125 if (slice_t0 > tSlice[tSlice.size()-1]) {
126 MPIUtil::haltRun("TimeInterp: gas.slice_t0 exceeds the time of the final snapshot file",
128 }
129 // Aim: find the index of a file whose next file is immediately before t0
130 IdxType firstIdx = -1;
131 for (IdxType i=0; i<tSlice.size(); i++) {
132 if (tSlice[i] < slice_t0) {
133 firstIdx += 1; // Slice time is below t0; shift index
134 } else {
135 tSlice[i] += -slice_t0; // Shift time on slices after t0
136 }
137 }
138 if (firstIdx > 0) { // Only delete files if the second file's time is less than t0
139 // Delete times until before the last file before t0
140 tSlice.erase(begin(tSlice), begin(tSlice) + firstIdx);
141 snapFiles.erase(begin(snapFiles), begin(snapFiles) + firstIdx);
142 }
143 // Shift the first time. This may be negative, but this is necessary
144 // for interpolation to work at the first pair of snapshots
145 tSlice[0] += -slice_t0;
146 };
147
148 // Make sure the first time slice is time zero, and that times are
149 // monotonically increasing
150 if (!t0_supplied && tSlice[0] != 0.0)
151 MPIUtil::haltRun("TimeInterp: first time slice must be at t = 0",
153 for (IdxType i = 0; i < tSlice.size()-1; i++) {
154 if (tSlice[i+1] <= tSlice[i])
155 MPIUtil::haltRun("TimeInterp: slice times must be "
156 "monotonically increasing",
158 }
159
160 // Make sure initial time step is less than time of first slice; it
161 // is an error if not
162 Real dt = 0.0;
163 pp.query("dt_init", dt);
164 if (dt >= tSlice[1])
165 MPIUtil::haltRun("TimeInterp: initial simulation "
166 "time step must be < time of second slice",
168 //Store maximum smoothing length and leaf size
169 if (!pp.query("gas.tree.maxH", hLim)) {hLim = 0;}
170 if (!pp.query("gas.tree.leafSize", leafSize)) {leafSize = 32;}
171
172 // Store uniform radiation field data
173 if (TBB_.size() != WBB_.size()) {
174 MPIUtil::haltRun("TimeInterp: Radiation field temperatures and "
175 "dilution factors must be vectors of the same size",
177 }
178 if (TBB_.size()>0) {
179 // Uniform radiation field data is supplied
180 uniformRadField = true;
181 } else {
182 // Radiation fields are not supplied: either no fields are necessary
183 // or they are defined in T::gasData
184 uniformRadField = false;
185 }
186 TBB = TBB_;
187 WBB = WBB_;
188
189 // Initialise old and new gas data objects as empty; they will be filled
190 // using T::loadData during TimeInterp<T>::updateState
191 gasOld = nullptr;
192 gasNew = nullptr;
193 // Flag that no data have been loaded yet
194 dataLoaded = false;
195 }
196
197
201 virtual ~TimeInterp() {
202 delete gasOld;
203 delete gasNew;
204 }
205
215 virtual GasData gasData(const RealVec &x,
216 const Real t) const override {
217 Real w = (t - tSlice[tPtr-1]) / (tSlice[tPtr] - tSlice[tPtr-1]);
218 GasData gdOld = gasOld->gasData(x, t);
219 GasData gdNew = gasNew->gasData(x, t);
220 GasData gd_interp = (1 - w) * gdOld + w * gdNew;
221 if (uniformRadField) {
222 gd_interp.TBB = TBB;
223 gd_interp.WBB = WBB;
224 }
225 return gd_interp;
226 }
227
234 virtual Real dxGhost() const override {
235 return gasOld->dxGhost();
236 }
237
247 void updateState(const Real t,
248 Real& tNext) {
249 // Safety check
250 if (t >= tSlice.back())
251 MPIUtil::haltRun("TimeInterp: simulation time has "
252 "exceeded time of last time slice",
254
255 // Handle special case of the first time this method is called, at
256 // which point no data are loaded and tPtr does not yet point to the
257 // right location.
258 if (!dataLoaded) {
259
260 // Move pointer so tSlice[tPtr] <= t < tSlice[tPtr+1]
261 tPtr = 0;
262 while (tSlice[tPtr+1] < t) tPtr++;
263
264 // Load old and new data. Boundary conditions on cartesian snapshots
265 // must be set inside of the class declaration itself and not here
266 if (verbosity > 1 && MPIUtil::IOProc) {
267 std::cout << "TimeInterp: loading file " << snapFiles[tPtr] <<
268 " at t = " << tSlice[tPtr] << std::endl;
269 }
270
271 gasOld = T::loadData(snapFiles[tPtr], hLim, leafSize);
272
273 if (verbosity > 1 && MPIUtil::IOProc) {
274 std::cout << "TimeInterp: loading file " << snapFiles[tPtr+1] <<
275 " at t = " << tSlice[tPtr+1] << std::endl;
276 }
277 tPtr++;
278 gasNew = T::loadData(snapFiles[tPtr], hLim, leafSize);
279 // Flag that data are now loaded
280 dataLoaded = true;
281
282 // Return
283 return;
284 }
285
286 // General case on second and subsequent calls to this method: check
287 // if we have hit the time when we need to load a new snapshot, or
288 // if we need to reduce the time step to hit the next load time
289 if (t == tSlice[tPtr]) {
290
291 std::swap(gasOld, gasNew); // std::swap old and new data
292 tPtr++; // Increment pointer
293 if (verbosity > 1 && MPIUtil::IOProc) {
294 std::cout << "TimeInterp: loading file " << snapFiles[tPtr] <<
295 " at t = " << tSlice[tPtr] << std::endl;
296 }
297
298 // Replace gasNew with new data
299 delete gasNew;
300 gasNew = T::loadData(snapFiles[tPtr], hLim, leafSize);
301 } else if (tNext > tSlice[tPtr]) {
302 tNext = tSlice[tPtr]; // Throttle time step
303 }
304 }
305
311 static std::vector<std::string> sortSnapFiles(std::vector<std::string> files,
312 std::vector<Real> times) {
313
314 std::vector<std::pair<double, IdxType>> indexedTimes;
315 for (IdxType i=0; i<times.size(); i++) {
316 indexedTimes.emplace_back(times[i], i);
317 }
318 std::sort(indexedTimes.begin(), indexedTimes.end());
319 std::vector<std::string> sortedFiles(files.size());
320 for (IdxType i=0; i<files.size(); i++) {
321 sortedFiles[i] = files[indexedTimes[i].second];
322 }
323 return sortedFiles;
324 }
325
326 protected:
327 // Data
328 std::vector<Real> tSlice;
329 std::vector<std::string> snapFiles;
335 std::vector<Real> TBB;
336 std::vector<Real> WBB;
338 private:
339 // Data
341 T * gasOld;
342 T * gasNew;
344 };
345 }
346}
347
348#endif
349// _TIMEINTERP_H_
A class to describe a gas with properties stored on a Cartesian grid.
Interface used to describe background gas.
Class to describe the background gas at a single point.
Gas class which describes a GIZMO snapshot file.
A class that describes the geometry of a calculation.
Definition Geometry.H:32
Class to parse the criptic input deck.
Definition ParmParser.H:37
bool query(const std::string &name, T &val) const
Return a keyword, or return false if not available.
Definition ParmParser.cpp:299
Trivial class to hold gas data.
Definition GasData.H:29
std::vector< Real > WBB
Definition GasData.H:58
std::vector< Real > TBB
Definition GasData.H:57
Interface class to describe background gas.
Definition Gas.H:44
Gas model stored with snapshots.
Definition TimeInterp.H:40
int leafSize
Definition TimeInterp.H:332
std::vector< Real > WBB
Definition TimeInterp.H:336
std::vector< Real > TBB
Definition TimeInterp.H:335
virtual Real dxGhost() const override
Size of the ghost region in the gas data.
Definition TimeInterp.H:234
bool uniformRadField
Definition TimeInterp.H:334
T * gasNew
Definition TimeInterp.H:342
std::vector< std::string > snapFiles
Definition TimeInterp.H:329
int verbosity
Definition TimeInterp.H:340
virtual ~TimeInterp()
Destructor.
Definition TimeInterp.H:201
Real hLim
Definition TimeInterp.H:331
bool dataLoaded
Definition TimeInterp.H:343
virtual GasData gasData(const RealVec &x, const Real t) const override
Return background gas state.
Definition TimeInterp.H:215
static std::vector< std::string > sortSnapFiles(std::vector< std::string > files, std::vector< Real > times)
Sort snapshot files by their associated times.
Definition TimeInterp.H:311
std::vector< Real > tSlice
Definition TimeInterp.H:328
void updateState(const Real t, Real &tNext)
Update the gas data.
Definition TimeInterp.H:247
TimeInterp(const ParmParser &pp, const Geometry &geom_, const IdxType nBB, const int nGhost, std::vector< Real > TBB_={}, std::vector< Real > WBB_={})
Constructor.
Definition TimeInterp.H:57
IdxType tPtr
Definition TimeInterp.H:330
T * gasOld
Definition TimeInterp.H:341
void haltRun(std::string msg, errCodes errcode)
Halt a run because an error has occurred.
Definition MPIUtil.cpp:287
bool IOProc
Definition MPIUtil.cpp:18
The primary namespace for criptic objects.
Definition AdvancePacket.H:25
@ errBadInputFile
Definition ErrCodes.H:25
std::vector< Real >::size_type IdxType
Definition Types.H:45
double Real
Definition Types.H:38