71 series = StationSeries{};
77 const auto is_missing = [missing_value] (
double v) {
78 return !std::isfinite(v) ||
79 std::abs(v -
static_cast<double>(missing_value)) <=
80 1.0e-6 * std::max(1.0, std::abs(
static_cast<double>(missing_value)));
85 bool have_header =
false;
89 while (std::getline(is, line))
92 if (!strip_comment(line)) {
continue; }
94 std::istringstream ls(line);
95 std::vector<std::string> tokens;
97 while (ls >> tok) { tokens.push_back(tok); }
101 for (
auto&
t : tokens) {
102 std::transform(
t.begin(),
t.end(),
t.begin(),
103 [](
unsigned char c) { return static_cast<char>(std::tolower(c)); });
105 for (
int c = 0; c < NColumns; ++c) {
106 if (
t == column_names[c]) { found = c;
break; }
109 error = where(source, line_no) +
"unknown column '" +
t +
"'; the columns are "
110 "time z u v w theta su sv sw stheta speed direction";
113 if (col_of[found] >= 0) {
114 error = where(source, line_no) +
"column '" +
t +
"' is named twice";
117 col_of[found] = ncols++;
120 const auto has = [&](
int c) {
return col_of[c] >= 0; };
121 if (!has(ColTime) || !has(ColZ)) {
122 error = where(source, line_no) +
"the header must name the columns time and z";
125 if (has(ColU) != has(ColV)) {
126 error = where(source, line_no) +
"u and v must be given together";
129 if (has(ColSpeed) != has(ColDirection)) {
130 error = where(source, line_no) +
"speed and direction must be given together";
133 if (has(ColU) && has(ColSpeed)) {
134 error = where(source, line_no) +
"give the wind as u v or as speed direction, not both";
137 const bool has_wind = has(ColU) || has(ColSpeed);
138 if ((has(ColSU) || has(ColSV)) && !has_wind) {
139 error = where(source, line_no) +
"su/sv need a wind column";
142 if (has(ColSW) && !has(ColW)) {
143 error = where(source, line_no) +
"sw needs the column w";
146 if (has(ColSTheta) && !has(ColTheta)) {
147 error = where(source, line_no) +
"stheta needs the column theta";
150 if (!has_wind && !has(ColW) && !has(ColTheta)) {
151 error = where(source, line_no) +
"the file has none of the nudged quantities "
152 "(u v, speed direction, w, theta)";
156 series.has[
U] = has_wind;
157 series.has[
V] = has_wind;
158 series.has[
W] = has(ColW);
159 series.has[
Theta] = has(ColTheta);
164 if (
static_cast<int>(tokens.size()) != ncols) {
165 error = where(source, line_no) +
"expected " + std::to_string(ncols) +
166 " entries, found " + std::to_string(tokens.size());
171 std::fill(v, v + NColumns, std::numeric_limits<double>::quiet_NaN());
172 for (
int c = 0; c < NColumns; ++c) {
173 if (col_of[c] < 0) {
continue; }
174 if (!parse_number(tokens[col_of[c]], v[c])) {
175 error = where(source, line_no) +
"'" + tokens[col_of[c]] +
"' in column " +
176 column_names[c] +
" is not a number";
181 if (is_missing(v[ColTime]) || is_missing(v[ColZ])) {
182 error = where(source, line_no) +
"time and z may not be missing";
187 const double time = v[ColTime];
188 const Real z =
static_cast<Real>(v[ColZ]);
189 if (series.records.empty() || time != series.records.back().time)
191 if (!series.records.empty()) {
192 if (time < series.records.back().time) {
193 error = where(source, line_no) +
"the times must increase down the file";
196 if (ih != nheights) {
197 error = where(source, line_no) +
"the record at time " +
198 std::to_string(series.records.back().time) +
" has " +
199 std::to_string(ih) +
" heights, but the first record has " +
200 std::to_string(nheights) +
"; every time needs the same heights";
206 series.records.push_back(rec);
210 StationRecord& rec = series.records.back();
212 if (series.records.size() == 1) {
213 if (!series.heights.empty() && z <= series.heights.back()) {
214 error = where(source, line_no) +
"the heights within a time must increase";
217 series.heights.push_back(z);
218 nheights =
static_cast<int>(series.heights.size());
219 }
else if (ih >= nheights || z != series.heights[ih]) {
220 error = where(source, line_no) +
"height " + std::to_string(z) +
" at time " +
221 std::to_string(time) +
" does not match the heights of the first time; "
222 "every time needs the same heights, in the same order";
227 const Real nan = std::numeric_limits<Real>::quiet_NaN();
231 if (col_of[ColU] >= 0 && !is_missing(v[ColU]) && !is_missing(v[ColV])) {
232 mean[
U] =
static_cast<Real>(v[ColU]);
233 mean[
V] =
static_cast<Real>(v[ColV]);
235 if (col_of[ColSpeed] >= 0 && !is_missing(v[ColSpeed]) && !is_missing(v[ColDirection])) {
236 const double speed = v[ColSpeed];
237 const double dir = v[ColDirection];
239 error = where(source, line_no) +
"the wind speed may not be negative";
242 if (dir < 0.0 || dir > 360.0) {
243 error = where(source, line_no) +
"the wind direction must be in [0, 360] degrees";
248 const double rad = dir *
static_cast<double>(
PI) / 180.0;
249 mean[
U] =
static_cast<Real>(-speed * std::sin(rad));
250 mean[
V] =
static_cast<Real>(-speed * std::cos(rad));
252 if (col_of[ColW] >= 0 && !is_missing(v[ColW])) {
253 mean[
W] =
static_cast<Real>(v[ColW]);
255 if (col_of[ColTheta] >= 0 && !is_missing(v[ColTheta])) {
256 if (v[ColTheta] <= 0.0) {
257 error = where(source, line_no) +
"theta must be positive (it is in kelvin)";
260 mean[
Theta] =
static_cast<Real>(v[ColTheta]);
263 const int scol[
NComp] = {ColSU, ColSV, ColSW, ColSTheta};
264 for (
int c = 0; c <
NComp; ++c) {
265 if (col_of[scol[c]] < 0 || is_missing(v[scol[c]])) {
continue; }
266 if (v[scol[c]] < 0.0) {
267 error = where(source, line_no) +
"the standard deviation " +
268 column_names[scol[c]] +
" may not be negative";
271 sigma[c] =
static_cast<Real>(v[scol[c]]);
274 for (
int c = 0; c <
NComp; ++c) {
275 rec.mean[c].push_back(mean[c]);
276 rec.sigma[c].push_back(
sigma[c]);
282 error = source +
": the file has no header line naming its columns";
285 if (series.records.empty()) {
286 error = source +
": the file has a header but no measurements";
289 if (ih != nheights) {
290 error = source +
": the last record has " + std::to_string(ih) +
291 " heights, but the first record has " + std::to_string(nheights) +
292 "; every time needs the same heights";
amrex::Real sigma
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:11
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:46
@ t
Definition: ERF_WSM6.H:272
void fill(MultiFab &dst, int temperature_comp, int mixing_ratio_comp, int source_comp, const Sources &sources, Real missing_value)
Definition: ERF_NearSurfaceDiagnostics.cpp:41