ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_NCWpsFile.H File Reference
#include <sstream>
#include <string>
#include <atomic>
#include "AMReX_FArrayBox.H"
#include "AMReX_IArrayBox.H"
#include "ERF_EpochTime.H"
#include "ERF_NCInterface.H"
Include dependency graph for ERF_NCWpsFile.H:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  NDArray< DataType >
 

Typedefs

using PlaneVector = amrex::Vector< amrex::FArrayBox >
 

Enumerations

enum class  NC_Data_Dims_Type {
  Time_SL_SN_WE , Time_BT_SN_WE , Time_SN_WE , Time_BT ,
  Time_SL , Time , Time_BdyWidth_BT_SN , Time_BdyWidth_BT_WE ,
  Time_BdyWidth_SN , Time_BdyWidth_WE
}
 

Functions

int BuildFABsFromWRFBdyFile (const std::string &fname, amrex::Vector< amrex::Vector< amrex::FArrayBox >> &bdy_data_xlo, amrex::Vector< amrex::Vector< amrex::FArrayBox >> &bdy_data_xhi, amrex::Vector< amrex::Vector< amrex::FArrayBox >> &bdy_data_ylo, amrex::Vector< amrex::Vector< amrex::FArrayBox >> &bdy_data_yhi)
 
template<typename DType >
void ReadTimeSliceFromNetCDFFile (const std::string &fname, const int tidx, amrex::Vector< std::string > names, amrex::Vector< NDArray< DType > > &arrays, amrex::Vector< int > &success)
 
template<typename DType >
void ReadNetCDFFile (const std::string &fname, amrex::Vector< std::string > names, amrex::Vector< NDArray< DType > > &arrays, amrex::Vector< int > &success)
 
template<class FAB , typename DType >
void fill_fab_from_arrays (int iv, const amrex::Box &domain, amrex::Vector< NDArray< float >> &nc_arrays, const std::string &var_name, NC_Data_Dims_Type &NC_dim_type, FAB &temp)
 
template<class FAB , typename DType >
void BuildFABsFromNetCDFFile (const amrex::Box &domain, const std::string &fname, amrex::Vector< std::string > nc_var_names, amrex::Vector< enum NC_Data_Dims_Type > NC_dim_types, amrex::Vector< FAB * > fab_vars, amrex::Vector< int > &success)
 

Typedef Documentation

◆ PlaneVector

using PlaneVector = amrex::Vector<amrex::FArrayBox>

Enumeration Type Documentation

◆ NC_Data_Dims_Type

enum NC_Data_Dims_Type
strong
Enumerator
Time_SL_SN_WE 
Time_BT_SN_WE 
Time_SN_WE 
Time_BT 
Time_SL 
Time 
Time_BdyWidth_BT_SN 
Time_BdyWidth_BT_WE 
Time_BdyWidth_SN 
Time_BdyWidth_WE 
32  {
33  Time_SL_SN_WE, // Time, Soil Layers, South-North, West-East
35  Time_SN_WE,
36  Time_BT,
37  Time_SL, // Time, Soil layers
38  Time,
43 };

Function Documentation

◆ BuildFABsFromNetCDFFile()

template<class FAB , typename DType >
void BuildFABsFromNetCDFFile ( const amrex::Box &  domain,
const std::string &  fname,
amrex::Vector< std::string >  nc_var_names,
amrex::Vector< enum NC_Data_Dims_Type NC_dim_types,
amrex::Vector< FAB * >  fab_vars,
amrex::Vector< int > &  success 
)

Function to read NetCDF variables and fill the corresponding Array4's

Parameters
domainBox specifying the domain covered by the NetCDF fields
fnameName of the NetCDF file to be read
nc_var_namesVariable names in the NetCDF file
NC_dim_typesNetCDF data dimension types
fab_varsFab data we are to fill
successSuccess flags for each requested variable
351 {
352  int ioproc = amrex::ParallelDescriptor::IOProcessorNumber(); // I/O rank
353 
354  amrex::Vector<NDArray<float>> nc_arrays(nc_var_names.size());
355 
356  if (amrex::ParallelDescriptor::IOProcessor())
357  {
358  ReadNetCDFFile(fname, nc_var_names, nc_arrays, success);
359  }
360 
361  amrex::ParallelDescriptor::Bcast(success.dataPtr(), success.size(), ioproc);
362 
363  for (int iv = 0; iv < nc_var_names.size(); iv++)
364  {
365  if (success[iv] == 1) {
366  FAB tmp;
367  if (amrex::ParallelDescriptor::IOProcessor()) {
368  fill_fab_from_arrays<FAB,DType>(iv, domain, nc_arrays, nc_var_names[iv], NC_dim_types[iv], tmp);
369  }
370 
371  int ncomp = tmp.nComp();
372  amrex::Box box = tmp.box();
373 
374  amrex::ParallelDescriptor::Bcast(&box, 1, ioproc);
375  amrex::ParallelDescriptor::Bcast(&ncomp, 1, ioproc);
376 
377  if (!amrex::ParallelDescriptor::IOProcessor()) {
378 #ifdef AMREX_USE_GPU
379  tmp.resize(box,ncomp,amrex::The_Pinned_Arena());
380 #else
381  tmp.resize(box,ncomp);
382 #endif
383  }
384 
385  amrex::ParallelDescriptor::Bcast(tmp.dataPtr(), tmp.size(), ioproc);
386 
387  // Shift box by the domain lower corner
388  amrex::Box fab_bx = tmp.box();
389  amrex::Dim3 dom_lb = lbound(domain);
390  fab_bx += amrex::IntVect(dom_lb.x,dom_lb.y,dom_lb.z);
391  // fab_vars points to data on device
392  fab_vars[iv]->resize(fab_bx,1);
393 #ifdef AMREX_USE_GPU
394  amrex::Gpu::copy(amrex::Gpu::hostToDevice,
395  tmp.dataPtr(), tmp.dataPtr() + tmp.size(),
396  fab_vars[iv]->dataPtr());
397 #else
398  // Provided by BaseFab inheritance through FArrayBox
399  fab_vars[iv]->copy(tmp,tmp.box(),0,fab_bx,0,1);
400 #endif
401  } // success
402  } // iv
403 }
void ReadNetCDFFile(const std::string &fname, amrex::Vector< std::string > names, amrex::Vector< NDArray< DType > > &arrays, amrex::Vector< int > &success)
Definition: ERF_NCWpsFile.H:155
@ tmp
Definition: ERF_AdvanceWSM6.cpp:114
Here is the call graph for this function:

◆ BuildFABsFromWRFBdyFile()

int BuildFABsFromWRFBdyFile ( const std::string &  fname,
amrex::Vector< amrex::Vector< amrex::FArrayBox >> &  bdy_data_xlo,
amrex::Vector< amrex::Vector< amrex::FArrayBox >> &  bdy_data_xhi,
amrex::Vector< amrex::Vector< amrex::FArrayBox >> &  bdy_data_ylo,
amrex::Vector< amrex::Vector< amrex::FArrayBox >> &  bdy_data_yhi 
)

◆ fill_fab_from_arrays()

template<class FAB , typename DType >
void fill_fab_from_arrays ( int  iv,
const amrex::Box &  domain,
amrex::Vector< NDArray< float >> &  nc_arrays,
const std::string &  var_name,
NC_Data_Dims_Type NC_dim_type,
FAB &  temp 
)

Helper function for reading data from NetCDF file into a provided FAB.

Parameters
ivIndex for which variable we are going to fill
domainBox specifying the horizontal and vertical extent to read
nc_arraysArrays of data from NetCDF file
var_nameVariable name
NC_dim_typeDimension type for the variable as stored in the NetCDF file
tempFAB where we store the variable data from the NetCDF Arrays
248 {
249  int ns1, ns2, ns3; // bottom_top, south_north, west_east (these can be staggered or unstaggered)
250  if (NC_dim_type == NC_Data_Dims_Type::Time_BT) {
251  ns1 = nc_arrays[iv].get_vshape()[1];
252  ns2 = 1;
253  ns3 = 1;
254  // amrex::Print() << "TYPE BT " << ns1 << std::endl;
255  } else if (NC_dim_type == NC_Data_Dims_Type::Time_SN_WE) {
256  ns1 = 1;
257  ns2 = nc_arrays[iv].get_vshape()[1];
258  ns3 = nc_arrays[iv].get_vshape()[2];
259  // amrex::Print() << "TYPE SN WE " << ns2 << " " << ns3 << std::endl;
260  } else if (NC_dim_type == NC_Data_Dims_Type::Time_BT_SN_WE) {
261  ns1 = nc_arrays[iv].get_vshape()[1];
262  ns2 = nc_arrays[iv].get_vshape()[2];
263  ns3 = nc_arrays[iv].get_vshape()[3];
264  // amrex::Print() << "TYPE BT SN WE " << ns1 << " " << ns2 << " " << ns3 << std::endl;
265  } else if (NC_dim_type == NC_Data_Dims_Type::Time_SL_SN_WE) {
266  ns1 = nc_arrays[iv].get_vshape()[1];
267  ns2 = nc_arrays[iv].get_vshape()[2];
268  ns3 = nc_arrays[iv].get_vshape()[3];
269  // amrex::Print() << "TYPE SL SN WE " << ns1 << " " << ns2 << " " << ns3 << std::endl;
270  } else if (NC_dim_type == NC_Data_Dims_Type::Time_SL) {
271  ns1 = nc_arrays[iv].get_vshape()[1];
272  ns2 = 1;
273  ns3 = 1;
274  // amrex::Print() << "TYPE SL " << ns1 << std::endl;
275  }
276  else {
277  amrex::Abort("Dont know this NC_Data_Dims_Type");
278  }
279 
280  // allow fewer z levels to be read in
281  // - ns1 may be the bottom_top or bottom_top_stag dim
282  // - domain.bigEnd(2) is the input number of cells in z
283  // - khi may be nz==bottom_top, nz < bottom_top, or 0 for 2D fields
284  int khi = std::min(domain.bigEnd(2), ns1-1);
285 
286  // TODO: The box will only start at (0,0,0) at level 0 -- we need to generalize this
287  amrex::Box in_box(amrex::IntVect(0,0,0), amrex::IntVect(ns3-1,ns2-1,ns1-1)); // ns1 may or may not be staggered
288  amrex::Box my_box(amrex::IntVect(0,0,0), amrex::IntVect(ns3-1,ns2-1,khi));
289 
290  if (var_name == "PH" || var_name == "PHB") {
291  my_box.setType(amrex::IndexType(amrex::IntVect(0,0,1)));
292  my_box.setBig(2, khi+1);
293  }
294  else if (var_name == "U" || var_name == "UU" || var_name == "MAPFAC_U") {
295  my_box.setType(amrex::IndexType(amrex::IntVect(1,0,0)));
296  }
297  else if (var_name == "V" || var_name == "VV" || var_name == "MAPFAC_V") {
298  my_box.setType(amrex::IndexType(amrex::IntVect(0,1,0)));
299  }
300  else if (var_name == "W" || var_name == "WW") {
301  my_box.setType(amrex::IndexType(amrex::IntVect(0,0,1)));
302  my_box.setBig(2, khi+1);
303  }
304  else if (var_name == "TSLB" || var_name == "SMOIS" || var_name == "SH2O" || var_name == "ZS" || var_name == "DZS") {
305  // soil variables are staggered in z
306  my_box.setType(amrex::IndexType(amrex::IntVect(0,0,1)));
307  }
308 
309  amrex::Arena* Arena_Used = amrex::The_Arena();
310 #ifdef AMREX_USE_GPU
311  // Make sure temp lives on CPU since nc_arrays lives on CPU only
312  Arena_Used = amrex::The_Pinned_Arena();
313 #endif
314  temp.resize(my_box,1, Arena_Used);
315  amrex::Array4<DType> fab_arr = temp.array();
316 
317  int ioff = temp.box().smallEnd()[0];
318  int joff = temp.box().smallEnd()[1];
319  int kmax = temp.box().bigEnd()[2]; // highest z level to be read in
320  //amrex::Print() << var_name << " domain khi, kmax, ns1 = " << khi << " " << kmax << " " << ns1 << std::endl;
321 
322  auto num_pts = in_box.numPts();
323 
324  for (int n(0); n < num_pts; ++n) {
325  int k = n / (ns2*ns3);
326  if (k > kmax) continue;
327  int j = (n - k*(ns2*ns3)) / ns3 + joff;
328  int i = n - k*(ns2*ns3) - (j-joff) * ns3 + ioff;
329  fab_arr(i,j,k,0) = static_cast<DType>(*(nc_arrays[iv].get_data()+n));
330  }
331 }
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
Arena * Arena_Used
Definition: ERF_Morrison_Advance_F.H:23

◆ ReadNetCDFFile()

template<typename DType >
void ReadNetCDFFile ( const std::string &  fname,
amrex::Vector< std::string >  names,
amrex::Vector< NDArray< DType > > &  arrays,
amrex::Vector< int > &  success 
)
157 {
158  AMREX_ASSERT(arrays.size() == names.size());
159 
160  if (amrex::ParallelDescriptor::IOProcessor())
161  {
162  auto ncf = ncutils::NCFile::open(fname, NC_CLOBBER | NC_NETCDF4);
163 
164  /*
165  // get the dimension information
166  int Time = static_cast<int>(ncf.dim("Time").len());
167  int DateStrLen = static_cast<int>(ncf.dim("DateStrLen").len());
168  int west_east = static_cast<int>(ncf.dim("west_east").len());
169  int south_north = static_cast<int>(ncf.dim("south_north").len());
170  int bottom_top = static_cast<int>(ncf.dim("bottom_top").len());
171  int bottom_top_stag = static_cast<int>(ncf.dim("bottom_top_stag").len());
172  int west_east_stag = static_cast<int>(ncf.dim("west_east_stag").len());
173  int south_north_stag = static_cast<int>(ncf.dim("south_north_stag").len());
174  int bdy_width = static_cast<int>(ncf.dim("bdy_width").len());
175  */
176 
177  // amrex::Print() << "Reading the dimensions from the netcdf file " << "\n";
178 
179  for (auto n=0; n<arrays.size(); ++n)
180  {
181  std::string vname_to_write = names[n];
182  std::string vname_to_read = names[n];
183 
184  if (vname_to_read.substr(0,2) == "R_") {
185  vname_to_read = names[n+4]; // This allows us to read "T" instead -- we will over-write this later
186  }
187 
188  success[n] = ncf.has_var(vname_to_read);
189  if (success[n] == 0) {
190  amrex::Print() << " Skipping " << vname_to_read << std::endl;
191  } else {
192  amrex::Print() << " Reading " << vname_to_read << std::endl;
193  }
194 
195  if (success[n] == 1) {
196 
197  std::vector<std::string> dimnames = ncf.var(vname_to_read).dimnames();
198  AMREX_ALWAYS_ASSERT(dimnames[0] == "Time" || dimnames[0] == "time");
199 
200  std::vector<size_t> shape = ncf.var(vname_to_read).shape();
201  arrays[n] = NDArray<DType>(vname_to_read,shape);
202  DType* dataPtr = arrays[n].get_data();
203 
204  std::vector<size_t> start(shape.size(), 0);
205 
206 #if 0
207  auto numPts = arrays[n].ndim();
208  amrex::Print() << "NetCDF Variable name = " << vname_to_read << std::endl;
209  amrex::Print() << "numPts read from NetCDF file/var = " << numPts << std::endl;
210  amrex::Print() << "Dims in var = " << ncf.var(vname_to_read).ndim() << std::endl;
211  amrex::Print() << "Dim names = (";
212  for (auto &dim:dimnames)
213  amrex::Print() << dim << ", " ;
214  amrex::Print() << ")" << std::endl;
215  amrex::Print() << "Dims of the variable = (";
216  for (auto &dim:shape)
217  amrex::Print() << dim << ", " ;
218  amrex::Print() << ")" << std::endl;
219 #endif
220 
221  ncf.var(vname_to_read).get(dataPtr, start, shape);
222 
223  } // has_var
224  }
225  ncf.close();
226  }
227 }
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
Definition: ERF_NCWpsFile.H:55

Referenced by BuildFABsFromNetCDFFile().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadTimeSliceFromNetCDFFile()

template<typename DType >
void ReadTimeSliceFromNetCDFFile ( const std::string &  fname,
const int  tidx,
amrex::Vector< std::string >  names,
amrex::Vector< NDArray< DType > > &  arrays,
amrex::Vector< int > &  success 
)
113 {
114  amrex::Print() << "Reading time slice " << tidx << " from " << fname << std::endl;
115  AMREX_ASSERT(arrays.size() == names.size());
116 
117  if (amrex::ParallelDescriptor::IOProcessor())
118  {
119  auto ncf = ncutils::NCFile::open(fname, NC_CLOBBER | NC_NETCDF4);
120 
121  int ntimes = ncf.dim("Time").len();
122  AMREX_ALWAYS_ASSERT((tidx >= 0) && (tidx < ntimes));
123 
124  for (auto n=0; n<arrays.size(); ++n)
125  {
126  std::string vname_to_write = names[n];
127  std::string vname_to_read = names[n];
128  if (vname_to_read.substr(0,2) == "R_") {
129  vname_to_read = names[n+4]; // This allows us to read "T" instead -- we will over-write this later
130  }
131 
132  success[n] = ncf.has_var(vname_to_read);
133 
134  if (success[n] == 1)
135  {
136  std::vector<std::string> dimnames = ncf.var(vname_to_read).dimnames();
137  AMREX_ALWAYS_ASSERT(dimnames[0] == "Time");
138 
139  std::vector<size_t> count = ncf.var(vname_to_read).shape();
140  std::vector<size_t> start(count.size(), 0);
141  start[0] = tidx;
142  count[0] = 1;
143 
144  arrays[n] = NDArray<DType>(vname_to_read, count);
145  DType* dataPtr = arrays[n].get_data();
146 
147  ncf.var(vname_to_read).get(dataPtr, start, count);
148  } // has_var
149  }
150  ncf.close();
151  }
152 }
Here is the call graph for this function: