Extension: Json and NetCDF utilities
#include "dg/file/file.h"
Loading...
Searching...
No Matches
easy_dims.h
Go to the documentation of this file.
1#pragma once
2
3#include <netcdf.h>
4#include "thrust/host_vector.h"
5
6#include "dg/runge_kutta.h" // for dg::is_same
7#include "dg/topology/grid.h"
8#include "dg/topology/gridX.h"
9#include "dg/topology/evaluation.h"
10#ifdef MPI_VERSION
11#include "dg/topology/mpi_grid.h"
12#include "dg/topology/mpi_evaluation.h"
13#endif //MPI_VERSION
14
15#include "nc_error.h"
16#include "easy_atts.h"
17
23namespace dg
24{
25namespace file
26{
27
29
30namespace detail
31{
32
33template<class real_type>
34std::vector<dg::RealGrid1d<real_type> > grids( const RealGrid0d<real_type>& ) { return {};}
35template<class real_type>
36std::vector<dg::RealGrid1d<real_type> > grids( const RealGrid1d<real_type>& g ) { return {g};}
37template<class real_type>
38std::vector<dg::RealGrid1d<real_type> > grids( const aRealTopology2d<real_type>& g ) { return {g.gy(), g.gx()};}
39template<class real_type>
40std::vector<dg::RealGrid1d<real_type> > grids( const aRealTopology3d<real_type>& g ) { return {g.gz(), g.gy(), g.gx()};}
41template<class real_type>
42std::vector<dg::RealGrid1d<real_type> > grids( const aRealTopologyX2d<real_type>& g ) { return grids(g.grid());}
43template<class real_type>
44std::vector<dg::RealGrid1d<real_type> > grids( const aRealTopologyX3d<real_type>& g ) { return grids(g.grid());;}
45
46template<class real_type>
47std::vector<std::string> dim_names( const RealGrid0d<real_type>& ) { return {};}
48template<class real_type>
49std::vector<std::string> dim_names( const RealGrid1d<real_type>& g ) { return {"x"};}
50template<class real_type>
51std::vector<std::string> dim_names( const aRealTopology2d<real_type>& g ) { return {"y", "x"};}
52template<class real_type>
53std::vector<std::string> dim_names( const aRealTopology3d<real_type>& g ) { return {"z", "y", "x"};}
54template<class real_type>
55std::vector<std::string> dim_names( const aRealTopologyX2d<real_type>& g ) { return {"y", "x"};}
56template<class real_type>
57std::vector<std::string> dim_names( const aRealTopologyX3d<real_type>& g ) { return {"z", "y", "x"};}
58template<class real_type>
59std::vector<std::string> axis_names( const RealGrid0d<real_type>& ) { return {};}
60template<class real_type>
61std::vector<std::string> axis_names( const RealGrid1d<real_type>& g ) { return {"X"};}
62template<class real_type>
63std::vector<std::string> axis_names( const aRealTopology2d<real_type>& g ) { return {"Y", "X"};}
64template<class real_type>
65std::vector<std::string> axis_names( const aRealTopology3d<real_type>& g ) { return {"Z", "Y", "X"};}
66template<class real_type>
67std::vector<std::string> axis_names( const aRealTopologyX2d<real_type>& g ) { return {"Y", "X"};}
68template<class real_type>
69std::vector<std::string> axis_names( const aRealTopologyX3d<real_type>& g ) { return {"Z", "Y", "X"};}
70
71
72inline void assign_defaults( std::vector<std::string>& name_dims, const std::vector<std::string>& default_names)
73{
74 if( name_dims.empty())
75 name_dims = default_names;
76 if( name_dims.size() != default_names.size())
77 throw std::runtime_error( "Number of given dimension names "+std::to_string(name_dims.size())+"does not match required number "+std::to_string(default_names.size())+"\n");
78}
79} // namespace detail
81
84
106template<class T>
107bool check_real_time( int ncid, const char* name, int* dimID, int* tvarID)
108{
109 // TODO Axis attribute check is still missing
111 // Check that it exists
112 int retval = nc_inq_dimid( ncid, name, dimID);
113 if( retval)
114 return false;
115 // Check that it is unlimited
116 int num_unlim;
117 err = nc_inq_unlimdims( ncid, &num_unlim, NULL);
118 std::vector<int> unlim_dims(num_unlim);
119 err = nc_inq_unlimdims( ncid, &num_unlim, &unlim_dims[0]);
120 if( std::find( unlim_dims.begin(), unlim_dims.end(), *dimID) == std::end( unlim_dims))
121 throw std::runtime_error( "Dimension "+std::string(name)+" already defined but not unlimited!\n");
123 //size_t length;
124 //err = nc_inq_dimlen( ncid, *dimID, &length);
125 //if( length != 0)
126 // throw std::runtime_error( "Unlimited dimension "+std::string(name)+" already has values!\n");
127 // Now check if the dimension variable exists already
128 err = nc_inq_varid( ncid, name, tvarID);
129 int xtype;
130 int ndims;
131 int dimids[10];
132 err = nc_inq_var( ncid, *tvarID, NULL, &xtype, &ndims, dimids, NULL);
133 if( xtype != detail::getNCDataType<T>() || ndims != 1 || dimids[0] != *dimID)
134 throw std::runtime_error( "Unlimited variable "+std::string(name)+" has wrong type or wrong dimensions!\n");
135 return true;
136}
137
156template<class T>
157inline int define_real_time( int ncid, const char* name, int* dimID, int* tvarID, bool full_check = false)
158{
159 if( full_check)
160 if( check_real_time<T>( ncid, name, dimID, tvarID))
161 return NC_NOERR;
162 int retval;
163 if( (retval = nc_def_dim( ncid, name, NC_UNLIMITED, dimID)) ){ return retval;}
164 if( (retval = nc_def_var( ncid, name, detail::getNCDataType<T>(), 1, dimID, tvarID))){return retval;}
165 std::string t = "time since start"; //needed for paraview to recognize timeaxis
166 // Update: Actually paraview also recognizes time from the "T" "axis" without "unit"
167 std::string axis = "T";
168 if( (retval = nc_put_att_text(ncid, *tvarID, "axis", axis.size(), axis.data())) ){return retval;}
169 if( (retval = nc_put_att_text(ncid, *tvarID, "units", t.size(), t.data())) ){ return retval;}
170 return retval;
171}
172
174inline int define_time( int ncid, const char* name, int* dimID, int* tvarID)
175{
176 return define_real_time<double>( ncid, name, dimID, tvarID);
177}
178
179
197inline int define_limited_time( int ncid, const char* name, int size, int* dimID, int* tvarID)
198{
199 int retval;
200 if( (retval = nc_def_dim( ncid, name, size, dimID)) ){ return retval;}
201 if( (retval = nc_def_var( ncid, name, NC_DOUBLE, 1, dimID, tvarID))){return retval;}
202 std::string t = "time since start"; //needed for paraview to recognize timeaxis
203 std::string axis = "T";
204 if( (retval = nc_put_att_text(ncid, *tvarID, "axis", axis.size(), axis.data())) ){return retval;}
205 if( (retval = nc_put_att_text(ncid, *tvarID, "units", t.size(), t.data())) ){ return retval;}
206 return retval;
207}
208
232template<class T>
233bool check_dimension( int ncid, int* dimID, const dg::RealGrid1d<T>& g, std::string name_dim = "x", std::string axis = "X")
234{
235 // TODO Axis attribute check is still missing
237 // check if the dimension exists already:
238 int retval = nc_inq_dimid( ncid, name_dim.data(), dimID);
239 if( retval)
240 return false;
241 size_t length;
242 retval = nc_inq_dimlen( ncid, *dimID, &length);
243 thrust::host_vector<T> points = g.abscissas();
244 if( length != points.size())
245 throw std::runtime_error( "Length of dimension "+name_dim+" does not match grid!\n");
246 // Now check if the dimension variable exists already
247 int varID;
248 err = nc_inq_varid( ncid, name_dim.data(), &varID);
249 int xtype;
250 int ndims;
251 int dimids[10];
252 err = nc_inq_var( ncid, varID, NULL, &xtype, &ndims, dimids, NULL);
253 if( xtype != detail::getNCDataType<T>() || ndims != 1 || dimids[0] != *dimID)
254 throw std::runtime_error( "Dimension variable "+name_dim+" has wrong type or wrong dimensions!\n");
255 thrust::host_vector<T> data( points);
256 err = nc_get_var( ncid, varID, data.data());
257 for( unsigned i=0; i<data.size(); i++)
258 if( !dg::is_same( data[i], points[i]))
259 throw std::runtime_error( "Dimension variable "+name_dim+" has values different from grid!\n");
260 return true;
261}
262
279template<class T>
280inline int define_dimension( int ncid, int* dimID, const dg::RealGrid1d<T>& g, std::string name_dim = "x", std::string axis = "X", bool full_check = false)
281{
282 if( full_check)
283 if( check_dimension( ncid, dimID, g, name_dim, axis))
284 return NC_NOERR;
285 int retval;
286 std::string long_name = name_dim+"-coordinate in Computational coordinate system";
287 thrust::host_vector<T> points = g.abscissas();
288 if( (retval = nc_def_dim( ncid, name_dim.data(), points.size(), dimID))){ return retval;}
289 int varID;
290 if( (retval = nc_def_var( ncid, name_dim.data(), detail::getNCDataType<T>(), 1, dimID, &varID))){return retval;}
291 if( (retval = nc_put_var( ncid, varID, points.data())) ){ return retval;}
292 if( (retval = nc_put_att_text( ncid, varID, "axis", axis.size(), axis.data())) ){return retval;}
293 retval = nc_put_att_text( ncid, varID, "long_name", long_name.size(), long_name.data());
294 return retval;
295}
296
316template<class Topology, std::enable_if_t<dg::is_vector_v<typename Topology::host_vector, dg::SharedVectorTag>,bool > = true>
317int define_dimensions( int ncid, int *dimsIDs, const Topology& g, std::vector<std::string> name_dims = {}, bool full_check = false)
318{
319 int retval = NC_NOERR;
320 auto grids = detail::grids( g);
321 auto default_names = detail::dim_names(g);
322 auto axis_names = detail::axis_names(g);
323 detail::assign_defaults( name_dims, default_names);
324 for ( unsigned i=0; i<grids.size(); i++)
325 {
326 retval = define_dimension( ncid, &dimsIDs[i], grids[i], name_dims[i], axis_names[i], full_check);
327 if( retval)
328 return retval;
329 }
330 return retval;
331}
332
361template<class Topology, std::enable_if_t<dg::is_vector_v<typename Topology::host_vector, dg::SharedVectorTag>,bool > = true>
362int define_dimensions( int ncid, int *dimsIDs, int* tvarID, const Topology& g, std::vector<std::string> name_dims = {}, bool full_check = false)
363{
364 auto default_names = detail::dim_names(g);
365 default_names.insert( default_names.begin(), "time");
366 detail::assign_defaults( name_dims, default_names);
367
368 int retval = define_real_time<typename Topology::value_type>( ncid, name_dims[0].data(), &dimsIDs[0], tvarID, full_check);
369 if(retval)
370 return retval;
371 return define_dimensions( ncid, &dimsIDs[1], g, {name_dims.begin()+1, name_dims.end()}, full_check);
372}
373
391template<class Topology, std::enable_if_t<dg::is_vector_v<typename Topology::host_vector, dg::SharedVectorTag>,bool > = true>
392bool check_dimensions( int ncid, int *dimsIDs, const Topology& g, std::vector<std::string> name_dims = {})
393{
394 auto grids = detail::grids( g);
395 auto default_names = detail::dim_names(g);
396 auto axis_names = detail::axis_names(g);
397 detail::assign_defaults( name_dims, default_names);
398 for ( unsigned i=0; i<grids.size(); i++)
399 {
400 if (!check_dimension( ncid, &dimsIDs[i], grids[i], name_dims[i], axis_names[i]))
401 return false;
402 }
403 return true;
404}
405
429template<class Topology, std::enable_if_t<dg::is_vector_v<typename Topology::host_vector, dg::SharedVectorTag>,bool > = true>
430bool check_dimensions( int ncid, int *dimsIDs, int* tvarID, const Topology& g, std::vector<std::string> name_dims = {})
431{
432 auto default_names = detail::dim_names(g);
433 default_names.insert( default_names.begin(), "time");
434 detail::assign_defaults( name_dims, default_names);
435 if ( !check_real_time<typename Topology::value_type>( ncid, name_dims[0].data(), &dimsIDs[0], tvarID))
436 return false;
437 return check_dimensions( ncid, &dimsIDs[1], g, {name_dims.begin()+1, name_dims.end()});
438}
439
440
441
442
467template<class T>
468inline int define_limtime_xy( int ncid, int* dimsIDs, int size, int* tvarID, const dg::aRealTopology2d<T>& g, std::vector<std::string> name_dims = {"time", "y", "x"})
469{
470 int retval;
471 retval = define_limited_time( ncid, name_dims[0].data(), size, &dimsIDs[0], tvarID);
472 if(retval)
473 return retval;
474 return define_dimensions( ncid, &dimsIDs[1], g, {name_dims[1], name_dims[2]});
475}
476
477
478#ifdef MPI_VERSION
480template<class MPITopology, std::enable_if_t<dg::is_vector_v<typename MPITopology::host_vector, dg::MPIVectorTag>,bool > = true>
481inline int define_dimensions( int ncid, int* dimsIDs, const MPITopology& g, std::vector<std::string> name_dims = {}, bool full_check = false)
482{
483 int rank;
484 MPI_Comm_rank( MPI_COMM_WORLD, &rank);
485 if( rank==0) return define_dimensions( ncid, dimsIDs, g.global(), name_dims, full_check);
486 else
487 return NC_NOERR;
488}
490template<class MPITopology, std::enable_if_t<dg::is_vector_v<typename MPITopology::host_vector, dg::MPIVectorTag>,bool > = true>
491inline int define_dimensions( int ncid, int* dimsIDs, int* tvarID, const MPITopology& g, std::vector<std::string> name_dims = {}, bool full_check = false)
492{
493 int rank;
494 MPI_Comm_rank( MPI_COMM_WORLD, &rank);
495 if( rank==0) return define_dimensions( ncid, dimsIDs, tvarID, g.global(), name_dims, full_check);
496 else
497 return NC_NOERR;
498}
500template<class MPITopology, std::enable_if_t<dg::is_vector_v<typename MPITopology::host_vector, dg::MPIVectorTag>,bool > = true>
501inline bool check_dimensions( int ncid, int* dimsIDs, const MPITopology& g, std::vector<std::string> name_dims = {})
502{
503 // all processes can read NetCDF in parallel by default
504 return check_dimensions( ncid, dimsIDs, g.global(), name_dims);
505}
507template<class MPITopology, std::enable_if_t<dg::is_vector_v<typename MPITopology::host_vector, dg::MPIVectorTag>,bool > = true>
508inline bool check_dimensions( int ncid, int* dimsIDs, int* tvarID, const MPITopology& g, std::vector<std::string> name_dims = {})
509{
510 // all processes can read NetCDF in parallel by default
511 return check_dimensions( ncid, dimsIDs, tvarID, g.global(), name_dims);
512}
513#endif //MPI_VERSION
514
516} //namespace file
517} //namespace dg
int define_limtime_xy(int ncid, int *dimsIDs, int size, int *tvarID, const dg::aRealTopology2d< T > &g, std::vector< std::string > name_dims={"time", "y", "x"})
DEPRECATED Define a limited time and 2 dimensions and associated coordinate variables.
Definition easy_dims.h:468
int define_dimension(int ncid, int *dimID, const dg::RealGrid1d< T > &g, std::string name_dim="x", std::string axis="X", bool full_check=false)
DEPRECATED Define a 1d dimension and associated coordinate variable.
Definition easy_dims.h:280
int define_time(int ncid, const char *name, int *dimID, int *tvarID)
DEPRECATED An alias for define_real_time<double>
Definition easy_dims.h:174
int define_dimensions(int ncid, int *dimsIDs, const Topology &g, std::vector< std::string > name_dims={}, bool full_check=false)
DEPRECATED Define dimensions and associated coordiante variables.
Definition easy_dims.h:317
bool check_dimensions(int ncid, int *dimsIDs, const Topology &g, std::vector< std::string > name_dims={})
DEPRECATED Check if dimensions exist as if define_dimensions was called.
Definition easy_dims.h:392
int define_limited_time(int ncid, const char *name, int size, int *dimID, int *tvarID)
DEPRECATED Define a limited time dimension and coordinate variable.
Definition easy_dims.h:197
bool check_real_time(int ncid, const char *name, int *dimID, int *tvarID)
DEPRECATED Check if an unlimited dimension exists as if define_real_time was called.
Definition easy_dims.h:107
int define_real_time(int ncid, const char *name, int *dimID, int *tvarID, bool full_check=false)
DEPRECATED Define an unlimited time dimension and coordinate variable.
Definition easy_dims.h:157
bool check_dimension(int ncid, int *dimID, const dg::RealGrid1d< T > &g, std::string name_dim="x", std::string axis="X")
DEPRECATED Check if a dimension exists as if define_dimension was called.
Definition easy_dims.h:233
Definition easy_atts.h:15
DEPRECATED Empty utitlity class that handles return values of netcdf functions and throws NC_Error(st...
Definition nc_error.h:70