ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_StationSampler.H
Go to the documentation of this file.
1 /**
2  * \file ERF_StationSampler.H
3  */
4 #ifndef ERF_STATIONSAMPLER_H_
5 #define ERF_STATIONSAMPLER_H_
6 
7 #include <algorithm>
8 #include <cmath>
9 #include <string>
10 
11 #include <AMReX_BoxArray.H>
12 #include <AMReX_REAL.H>
13 #include <AMReX_Vector.H>
14 
15 // invert_latlon_offset, used to place stations given by latitude/longitude
16 #include "ERF_LatLonMap.H"
17 
18 //
19 // Station time-series output.
20 //
21 // A station is a named set of geographic points at which a user-chosen set of
22 // variables is written to an ASCII time series, for comparison against
23 // meteorological tower and surface-station observations. The inputs follow the
24 // same shape as erf.refinement_indicators:
25 //
26 // erf.station_names = Lake1 Forests
27 // erf.Lake1.field = rain_accum
28 // erf.Lake1.lat = 45.13
29 // erf.Lake1.long = -122.34
30 // erf.Forests.field = magvel local_helicity
31 // erf.Forests.lat = 45.20 45.41
32 // erf.Forests.long = -122.10 -122.02
33 // erf.Forests.height_agl = 10.0 80.0
34 //
35 // lat/long are paired positionally, so the example above is two locations, not
36 // four. A station may instead be placed with .x/.y in domain coordinates, which
37 // is the only option for a run that has no lat/lon arrays. The heights apply to
38 // every location of the station and are given one way or the other, never both:
39 // .height_agl is metres above the local terrain, .height_abs is metres in the
40 // model's own vertical coordinate, the same z as geometry.prob_lo/prob_hi.
41 //
42 // The variable names accepted are the 3D plotfile variables and the built-in 2D
43 // diagnostics, and the values come from the same fill routines
44 // (ERF::FillPlot3DVars / ERF::FillPlot2DVars), so a station column and the
45 // corresponding plotfile component cannot disagree. A 2D plotfile can also
46 // carry sampled-level fields, named for the field and the level such as
47 // 'theta_z100m'; those are not accepted here, since a station asks for the 3D
48 // variable and a height directly.
49 //
50 
51 struct StationVar
52 {
53  std::string name;
54  std::string units;
55  bool is_2d = false; // comes from the 2D diagnostic catalog
56  bool is_missing = false; // valid 2D name, inactive in this run
58  int comp = -1; // component in the filled MultiFab
59 };
60 
61 struct StationLoc
62 {
63  bool use_latlon = false;
64 
65  // As requested in the inputs file
68 
69  // Domain coordinates of the station, resolved once at setup
72 
73  // lat/lon actually reached by (x,y); equals the request to within the
74  // accuracy of the inverse map, and is reported in the file header
77 
78  // Resolved against the current grids at every output step
79  int lev = 0;
80  int ic = 0; // cell containing (x,y)
81  int jc = 0;
82  int i0 = 0; // lower-left corner of the interpolation stencil
83  int j0 = 0;
84  int i1 = 0; // upper-right corner; equals i0 where the
85  int j1 = 0; // stencil collapses at a physical boundary
86  amrex::Real wx = amrex::Real(0.0); // weight of i1 relative to i0
88  int ktop = 0; // highest cell the vertical interpolation
89  // reads, which is as high as the chosen
90  // level is known to cover the stencil
91 
92  // Index into the owning station's column list of this location's first column
93  int col_begin = 0;
94 };
95 
96 //
97 // One scalar written every output step: one variable, at one location, at one
98 // height. Heights do not apply to 2D variables, whose height index is -1.
99 //
101 {
102  int station = 0;
103  int loc = 0;
104  int height = -1;
105  int var = 0;
106 };
107 
108 struct Station
109 {
110  std::string name;
111  amrex::Vector<StationVar> vars;
112  amrex::Vector<StationLoc> locs;
113  // The requested heights, in metres, and what they are measured from. The
114  // two input keys collapse to one list here: which one was given only decides
115  // where the column's zero is, and that is a single flag rather than two
116  // lists everything downstream would have to choose between.
117  amrex::Vector<amrex::Real> heights;
118  bool heights_are_agl = true; // .height_agl, else .height_abs
119 
120  // Global column indices owned by this station, in file column order
121  amrex::Vector<int> columns;
122 
123  bool has_3d_vars () const {
124  for (const auto& v : vars) { if (!v.is_2d) { return true; } }
125  return false;
126  }
127 };
128 
130 {
131 public:
132  // Parses erf.station_names and the per-station keys. Name validation needs
133  // the run's variable catalogs and is done by ERF::init_stations.
134  explicit StationSampler (const std::string& pp_prefix);
135 
136  [[nodiscard]] bool empty () const { return m_stations.empty(); }
137 
138  amrex::Vector<Station>& stations () { return m_stations; }
139  [[nodiscard]] const amrex::Vector<Station>& stations () const { return m_stations; }
140 
141  [[nodiscard]] int numColumns () const { return m_ncolumns; }
142 
143  // Assigns the global column index of every (location, height, variable)
144  // triple. Called by ERF::init_stations once the variables are resolved.
145  void buildColumns ();
146 
147  // Buffer one row of values. Writes through to disk once the buffer is full.
148  void appendRow (amrex::Real time, amrex::Real epoch_time, const amrex::Vector<amrex::Real>& values);
149 
150  // Write any buffered rows. Safe to call from any rank; only the IO rank writes.
151  void flush ();
152 
153  // A run that is not restarting starts its station files afresh; a restart
154  // appends to what the earlier run wrote.
155  void setRestart (bool is_restart) { m_is_restart = is_restart; }
156 
157  // On a restart, stop now if a file this run would append to describes a
158  // different set of columns. Called by ERF::init_stations once the columns
159  // are resolved, so that a setup error costs a setup rather than a run.
160  void checkRestartFiles () const;
161 
162  void setWriteTimestamp (bool write_timestamp, const std::string& datetime_format) {
163  m_write_timestamp = write_timestamp;
164  m_datetime_format = datetime_format;
165  }
166 
167  [[nodiscard]] int bufferSteps () const { return m_buffer_steps; }
168 
169  // A height below the first cell centre is honored by clamping, which is
170  // worth saying once and not once per output step.
171  [[nodiscard]] bool lowHeightWarned () const { return m_low_height_warned; }
173 
174  // Which level each location was resolved to is reported once, since it is
175  // the thing about a station that is least obvious from the inputs file.
176  [[nodiscard]] bool levelsReported () const { return m_levels_reported; }
178 
179  // Resolving which level and which cells a station is read from costs a
180  // ParallelCopy, a stream synchronization and a broadcast, and the answer is a
181  // function of the grids and of the terrain under the station. With terrain
182  // that does not move, grids that have not changed give the answer already
183  // stored in the locations, so the work can be skipped: these remember which
184  // grids that was, and report whether it is still those.
185  [[nodiscard]] bool stencilsValidFor (const amrex::Vector<amrex::BoxArray>& ba,
186  int finest_level) const;
187  void rememberStencilGrids (const amrex::Vector<amrex::BoxArray>& ba, int finest_level);
188 
189 private:
190  void writeHeader (const Station& station, std::ostream& os) const;
191 
192  // The format tag and a hash of what the columns are: the variables, their
193  // units, the requested locations, the heights and their order. This is what
194  // a restart compares, rather than the header as a whole, so that rewording
195  // the header or resolving a coordinate to a slightly different value does
196  // not make an existing series un-restartable.
197  [[nodiscard]] std::string columnSignature (const Station& station) const;
198 
199  // Stops a restart that would append columns the file's header does not
200  // describe, which would otherwise pass unnoticed until the file was read.
201  void checkHeaderMatches (const Station& station, const std::string& filename) const;
202 
203  amrex::Vector<Station> m_stations;
204  int m_ncolumns = 0;
205  int m_buffer_steps = 100;
206 
207  // m_rows[irow] holds the values of every column at m_times[irow]
208  amrex::Vector<amrex::Real> m_times;
209  amrex::Vector<amrex::Real> m_epoch_times;
210  amrex::Vector<amrex::Real> m_rows;
211 
212  // The grids the stencils currently stored in the locations were resolved
213  // against; empty until the first resolve.
214  amrex::Vector<amrex::BoxArray> m_stencil_grids;
215 
216  bool m_is_restart = false;
217  bool m_low_height_warned = false;
218  bool m_levels_reported = false;
219  bool m_write_timestamp = false;
220  std::string m_datetime_format;
221 
222  std::string m_dir = "Output_Stations";
223  bool m_opened = false;
224 };
225 
226 #endif
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_StationSampler.H:130
StationSampler(const std::string &pp_prefix)
Definition: ERF_StationSampler.cpp:222
bool m_write_timestamp
Definition: ERF_StationSampler.H:219
bool m_levels_reported
Definition: ERF_StationSampler.H:218
int m_ncolumns
Definition: ERF_StationSampler.H:204
bool m_is_restart
Definition: ERF_StationSampler.H:216
amrex::Vector< Station > m_stations
Definition: ERF_StationSampler.H:203
std::string columnSignature(const Station &station) const
Definition: ERF_StationSampler.cpp:403
void buildColumns()
Definition: ERF_StationSampler.cpp:356
amrex::Vector< Station > & stations()
Definition: ERF_StationSampler.H:138
void setRestart(bool is_restart)
Definition: ERF_StationSampler.H:155
amrex::Vector< amrex::BoxArray > m_stencil_grids
Definition: ERF_StationSampler.H:214
int m_buffer_steps
Definition: ERF_StationSampler.H:205
bool m_low_height_warned
Definition: ERF_StationSampler.H:217
amrex::Vector< amrex::Real > m_epoch_times
Definition: ERF_StationSampler.H:209
void writeHeader(const Station &station, std::ostream &os) const
Definition: ERF_StationSampler.cpp:441
amrex::Vector< amrex::Real > m_rows
Definition: ERF_StationSampler.H:210
void flush()
Definition: ERF_StationSampler.cpp:616
bool empty() const
Definition: ERF_StationSampler.H:136
const amrex::Vector< Station > & stations() const
Definition: ERF_StationSampler.H:139
void setLevelsReported()
Definition: ERF_StationSampler.H:177
void checkHeaderMatches(const Station &station, const std::string &filename) const
Definition: ERF_StationSampler.cpp:503
void checkRestartFiles() const
Definition: ERF_StationSampler.cpp:581
std::string m_datetime_format
Definition: ERF_StationSampler.H:220
void rememberStencilGrids(const amrex::Vector< amrex::BoxArray > &ba, int finest_level)
Definition: ERF_StationSampler.cpp:609
bool stencilsValidFor(const amrex::Vector< amrex::BoxArray > &ba, int finest_level) const
Definition: ERF_StationSampler.cpp:599
void appendRow(amrex::Real time, amrex::Real epoch_time, const amrex::Vector< amrex::Real > &values)
Definition: ERF_StationSampler.cpp:376
void setWriteTimestamp(bool write_timestamp, const std::string &datetime_format)
Definition: ERF_StationSampler.H:162
int numColumns() const
Definition: ERF_StationSampler.H:141
std::string m_dir
Definition: ERF_StationSampler.H:222
amrex::Vector< amrex::Real > m_times
Definition: ERF_StationSampler.H:208
void setLowHeightWarned()
Definition: ERF_StationSampler.H:172
int bufferSteps() const
Definition: ERF_StationSampler.H:167
bool lowHeightWarned() const
Definition: ERF_StationSampler.H:171
bool m_opened
Definition: ERF_StationSampler.H:223
bool levelsReported() const
Definition: ERF_StationSampler.H:176
Definition: ERF_StationSampler.H:101
int height
Definition: ERF_StationSampler.H:104
int station
Definition: ERF_StationSampler.H:102
int loc
Definition: ERF_StationSampler.H:103
int var
Definition: ERF_StationSampler.H:105
Definition: ERF_StationSampler.H:62
amrex::Real req_lat
Definition: ERF_StationSampler.H:66
amrex::Real wx
Definition: ERF_StationSampler.H:86
int j1
Definition: ERF_StationSampler.H:85
amrex::Real wy
Definition: ERF_StationSampler.H:87
amrex::Real req_lon
Definition: ERF_StationSampler.H:67
int jc
Definition: ERF_StationSampler.H:81
int i0
Definition: ERF_StationSampler.H:82
int ktop
Definition: ERF_StationSampler.H:88
amrex::Real got_lat
Definition: ERF_StationSampler.H:75
int col_begin
Definition: ERF_StationSampler.H:93
amrex::Real x
Definition: ERF_StationSampler.H:70
int ic
Definition: ERF_StationSampler.H:80
int i1
Definition: ERF_StationSampler.H:84
bool use_latlon
Definition: ERF_StationSampler.H:63
amrex::Real y
Definition: ERF_StationSampler.H:71
amrex::Real got_lon
Definition: ERF_StationSampler.H:76
int j0
Definition: ERF_StationSampler.H:83
int lev
Definition: ERF_StationSampler.H:79
Definition: ERF_StationSampler.H:52
std::string units
Definition: ERF_StationSampler.H:54
amrex::Real missing_value
Definition: ERF_StationSampler.H:57
int comp
Definition: ERF_StationSampler.H:58
std::string name
Definition: ERF_StationSampler.H:53
bool is_missing
Definition: ERF_StationSampler.H:56
bool is_2d
Definition: ERF_StationSampler.H:55
Definition: ERF_StationSampler.H:109
amrex::Vector< StationLoc > locs
Definition: ERF_StationSampler.H:112
bool has_3d_vars() const
Definition: ERF_StationSampler.H:123
bool heights_are_agl
Definition: ERF_StationSampler.H:118
std::string name
Definition: ERF_StationSampler.H:110
amrex::Vector< amrex::Real > heights
Definition: ERF_StationSampler.H:117
amrex::Vector< StationVar > vars
Definition: ERF_StationSampler.H:111
amrex::Vector< int > columns
Definition: ERF_StationSampler.H:121