REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_NCFile.cpp
Go to the documentation of this file.
1#include <string>
2
3#include "REMORA_NCFile.H"
5#include "REMORA_TimeUnits.H"
6
7
8/**
9 * @param fname Name of NetCDF file
10 * @param var_name Name of variable
11 * @param attr_name Name of attribute to read
12 * @returns attribute value
13 */
14std::string ReadNetCDFVarAttrStr (const std::string& fname,
15 const std::string& var_name,
16 const std::string& attr_name)
17{
18 std::string attr_val;
21 if (amrex::ParallelDescriptor::IOProcessor())
22 {
23 if (!ncf.has_var(var_name)) {
24 amrex::Print() << "Trying to read attribute " << attr_name << " from variable " << var_name << " that does not exist!" << std::endl;
25 }
26 if (!ncf.var(var_name).has_attr(attr_name)) {
27 amrex::Print() << "Trying to read attribute " << attr_name << " that does not exist from variable " << var_name << "!" << std::endl;
28 }
29 attr_val = ncf.var(var_name).get_attr(attr_name);
30 }
31 ncf.close();
32 return attr_val;
33}
34
35/**
36 * @param fname Name of NetCDF file
37 * @param var_name Name of variable
38 * @param attr_name Name of attribute to read
39 * @returns whether attribute was found
40 */
41bool QueryNetCDFVarAttrStr (const std::string& fname,
42 const std::string& var_name,
43 const std::string& attr_name)
44{
45 int has_var = 0;
48 if (amrex::ParallelDescriptor::IOProcessor())
49 {
50 if (!ncf.has_var(var_name)) {
51 amrex::Print() << "Trying to check for attribute " << attr_name << " from variable " << var_name << " that does not exist!" << std::endl;
52 }
53 has_var = ncf.var(var_name).has_attr(attr_name) ? 1 : 0;
54 }
55 ncf.close();
56 int ioproc = amrex::ParallelDescriptor::IOProcessorNumber();
57 amrex::ParallelDescriptor::Bcast(&has_var, 1, ioproc);
58 return (has_var != 0);
59}
60
61double ReadNetCDFTimeOffsetDays (const std::string& fname,
62 const std::string& time_name,
63 double time_ref,
64 bool units_required,
65 bool announce)
66{
67 double offset_days = 0.0;
70 if (amrex::ParallelDescriptor::IOProcessor())
71 {
72 if (!ncf.has_var(time_name)) {
73 amrex::Abort("Time variable '" + time_name + "' not found in " + fname);
74 }
75 auto time_var = ncf.var(time_name);
76 const std::string where = "time variable '" + time_name + "' in " + fname;
77 const std::string ref_date = remora_ref_date_string(time_ref);
78
79 if (!time_var.has_attr("units")) {
80 if (units_required) {
81 amrex::Abort("No units attribute on " + where +
82 ". Expected 'days since yyyy-mm-dd hh:mm:ss'.");
83 }
84 amrex::Warning("Units attribute not found on time variable " + time_name +
85 ". Assuming days on the model clock");
86 } else {
87 const std::string units = time_var.get_attr("units");
89 std::string error;
91 amrex::Abort("Could not read units '" + units + "' of " + where + ": " + error);
92 }
93 if (parsed.unit != "days" && parsed.unit != "day") {
94 amrex::Print() << "Units of " << time_name << " given as: " << units << std::endl;
95 amrex::Abort("Units must be in days.");
96 }
97
98 // A file on another calendar counts days differently, and no shift
99 // would put it on this clock.
100 if (time_var.has_attr("calendar")) {
101 const std::string calendar = time_var.get_attr("calendar");
103 amrex::Abort("The calendar of " + where + " is '" + calendar +
104 "', but remora.time_ref selects the " +
105 remora_ref_calendar(time_ref) + " calendar. Convert the " +
106 "file, or choose a remora.time_ref on its calendar.");
107 }
108 }
109
110 if (parsed.has_reference) {
112 if (announce) {
113 amrex::Print() << "Time variable '" << time_name << "' in " << fname
114 << " counts days since "
116 if (offset_days == 0.0) {
117 amrex::Print() << ", the remora.time_ref reference date" << std::endl;
118 } else {
119 amrex::Print() << "; shifting by " << offset_days
120 << " days to count from the remora.time_ref reference date "
121 << ref_date << std::endl;
122 }
123 }
124 } else if (announce) {
125 amrex::Print() << "Time variable '" << time_name << "' in " << fname
126 << " has units '" << units << "' with no reference date;"
127 << " taking its times as days since the remora.time_ref"
128 << " reference date " << ref_date << std::endl;
129 }
130 }
131 }
132 ncf.close();
133
134 // Every rank places the times, so every rank needs the same offset.
135 const int ioproc = amrex::ParallelDescriptor::IOProcessorNumber();
136 amrex::ParallelDescriptor::Bcast(&offset_days, 1, ioproc);
137 return offset_days;
138}
139
140/**
141 * @param fname Name of NetCDF file
142 * @param var_names Names of the variables to test for
143 * @returns whether every named variable is present in the file
144 *
145 * Use this before calling BuildFABsFromNetCDFFile() on optional variables:
146 * ReadNetCDFFile() calls ncf.var(name) unconditionally, so a missing variable
147 * is a hard failure rather than a recoverable one. The answer is broadcast so
148 * every rank agrees before any collective read is attempted.
149 */
150bool QueryNetCDFHasVars (const std::string& fname,
151 const amrex::Vector<std::string>& var_names)
152{
153 int has_all = 1;
156 if (amrex::ParallelDescriptor::IOProcessor())
157 {
158 for (const auto& var_name : var_names) {
159 if (!ncf.has_var(var_name)) { has_all = 0; break; }
160 }
161 }
162 ncf.close();
163 amrex::ParallelDescriptor::Bcast(&has_all, 1, amrex::ParallelDescriptor::IOProcessorNumber());
164 return (has_all != 0);
165}
AMREX_FORCE_INLINE std::string remora_ref_date_string(double time_ref)
Reference date as YYYY-MM-DD hh:mm:ss. ROMS ref_clock's Rclockstring.
AMREX_FORCE_INLINE std::string remora_ref_calendar(double time_ref)
CF calendar name for time_ref. ROMS ref_clock's Rclockcalendar.
mf_h setVal(geomdata.ProbHi(2))
bool QueryNetCDFHasVars(const std::string &fname, const amrex::Vector< std::string > &var_names)
Helper function for testing whether a file carries every named variable.
bool QueryNetCDFVarAttrStr(const std::string &fname, const std::string &var_name, const std::string &attr_name)
Helper function for testing for the presence of a single variable attribute.
double ReadNetCDFTimeOffsetDays(const std::string &fname, const std::string &time_name, double time_ref, bool units_required, bool announce)
Offset, in days, that puts a file's time variable onto the model clock.
std::string ReadNetCDFVarAttrStr(const std::string &fname, const std::string &var_name, const std::string &attr_name)
Helper function for reading a single variable attribute.
bool remora_calendar_matches_time_ref(const std::string &calendar, double time_ref)
Whether a CF calendar attribute names the calendar time_ref selects.
bool remora_parse_time_units(const std::string &units, REMORATimeUnits &out, std::string &error)
Parse a CF time-units attribute.
std::string remora_time_units_date_string(const REMORATimeUnits &units)
The reference date of units as YYYY-MM-DD hh:mm:ss.
double remora_time_units_offset_days(const REMORATimeUnits &units, double time_ref)
Days to add to a time counted from units' reference date to count it from the date time_ref names ins...
static NCFile open(const std::string &name, const int cmode=NC_NOWRITE, MPI_Comm comm=MPI_COMM_WORLD, MPI_Info info=MPI_INFO_NULL)
Open an existing file.
A parsed CF time-units attribute.