void read_netcdf_grid(std::string filename, array &out_x, array
&out_y, matrix &out_data, std::string xname = "x", std::string yname = "y", std::string dataname = "z")
{
array tmpdata;
read_netcdf_axis(filename, out_x, xname);
read_netcdf_axis(filename, out_y, yname);
read_netcdf_grid(filename, tmpdata, xname, yname, dataname);
out_data.resize(tmpdata, out_y.size(), out_x.size());
tmpdata.clear();
return;
}
/**
* @brief 保存 Netcdf 格式的规则网格数据文件
*
* @param[in] filename 输出文件名(无后缀)
* @param[in] out_data 输出数组(注意需将网格数据保存为一个一维数据,左下到右上,行优先排序)
* @param[in] xnum 网格的 x 方向顶点数量
* @param[in] ynum 网格的 y 方向顶点数量
* @param[in] xmin 网格的 x 方向最小值
* @param[in] dx 网格的 x 方向的顶点间隔
* @param[in] ymin 网格的 y 方向最小值
* @param[in] dy 网格的 y 方向的顶点间隔
* @param[in] zmin 网格数据的最小值,默认为 NAN 。 此时函数会自动计算数组的最小值
* @param[in] zmax 网格数据的最大值,默认为 NAN 。 此时函数会自动计算数组的最大值
* @param[in] xname 文件中 x 坐标轴的变量名,默认为 x
* @param[in] yname 文件中 y 坐标轴的变量名,默认为 y
* @param[in] dataname 文件中网格数据的变量名,默认为 z
*/
template
void save_netcdf_grid(std::string filename, const array &out_data, int xnum, int ynum,
P xmin, P dx, P ymin, P dy, std::string xname = "x", std::string yname = "y",
std::string dataname = "z", T zmin = NAN, T zmax = NAN)
{
// 准备写出数据
if (out_data.empty())
{
throw runtime_error("The output data is empty. From save_netcdf_grid(...)");
}
if (filename == "")
{
throw domain_error("The input filename is empty. From save_netcdf_grid(...)");
}
// 判断文件名结尾是否为.nc如果不是则添加.nc结尾
std::string full_name;
if (filename.length() <= 3 || filename.substr(filename.length()-3, filename.length()) != ".nc")
{
full_name = filename + ".nc";
}
else full_name = filename;
NcFile nc_outfile(full_name.c_str(), NcFile::Replace);
if (!nc_outfile.is_valid())
{
throw runtime_error("Can't not open file: " + full_name + ". From save_netcdf_grid(...)");
}
if (std::isnan(zmin))
{
zmin = GCTL_BDL_MAX;
for (int j = 0; j < out_data.size(); j++)
{
if (!std::isnan(out_data[j]) && out_data[j] != GCTL_BDL_MAX)
zmin = GCTL_MIN(zmin, out_data[j]);
}
}
if (std::isnan(zmax))
{
zmax = GCTL_BDL_MIN;
for (int j = 0; j < out_data.size(); j++)
{
if (!std::isnan(out_data[j]) && out_data[j] != GCTL_BDL_MAX)
zmax = GCTL_MAX(zmax, out_data[j]);
}
}
T data_range[2] = {zmin, zmax};
P x_range[2] = {xmin, xmin+(xnum-1)*dx};
P y_range[2] = {ymin, ymin+(ynum-1)*dy};
array xs(xnum), ys(ynum);
for (int i = 0; i < xnum; i++)
{
xs[i] = xmin + i*dx;
}
for (int i = 0; i < ynum; i++)
{
ys[i] = ymin + i*dy;
}
time_t now = time(0);
char* dt_char = ctime(&now);
dt_char[strlen(dt_char)-1] = 0; // 删除换行符
std::string dt = dt_char;
std::string his_str = "Generated by gctl::save_netcdf_grid() on " + dt;
//nc_outfile.add_att("title", "Topography data.");
nc_outfile.add_att("history", his_str.c_str());
NcDim *xDim = nc_outfile.add_dim(xname.c_str(), xnum);
NcDim *yDim = nc_outfile.add_dim(yname.c_str(), ynum);
NcType axis_type, val_type;
if (typeid(P).name() == typeid(signed char).name()) axis_type = ncByte;
else if (typeid(P).name() == typeid(char).name()) axis_type = ncChar;
else if (typeid(P).name() == typeid(short).name()) axis_type = ncShort;
else if (typeid(P).name() == typeid(int).name()) axis_type = ncInt;
else if (typeid(P).name() == typeid(float).name()) axis_type = ncFloat;
else if (typeid(P).name() == typeid(double).name()) axis_type = ncDouble;
else axis_type = ncDouble;
if (typeid(T).name() == typeid(signed char).name()) val_type = ncByte;
else if (typeid(T).name() == typeid(char).name()) val_type = ncChar;
else if (typeid(T).name() == typeid(short).name()) val_type = ncShort;
else if (typeid(T).name() == typeid(int).name()) val_type = ncInt;
else if (typeid(T).name() == typeid(float).name()) val_type = ncFloat;
else if (typeid(T).name() == typeid(double).name()) val_type = ncDouble;
else val_type = ncDouble;
NcVar *xVar = nc_outfile.add_var(xname.c_str(), axis_type, xDim);
//xVar->add_att("units", 'm');
xVar->add_att("valid_range", 2, &x_range[0]);
xVar->put(xs.get(), xnum);
NcVar *yVar = nc_outfile.add_var(yname.c_str(), axis_type, yDim);
//yVar->add_att("units", 'm');
yVar->add_att("valid_range", 2, &y_range[0]);
yVar->put(ys.get(), ynum);
NcVar *dVar = nc_outfile.add_var(dataname.c_str(), val_type, yDim, xDim);
//dVar->add_att("units", 'm');
dVar->add_att("valid_range", 2, &data_range[0]);
dVar->add_att("missing_value", GCTL_BDL_MAX);
array tmp_data(out_data);
for (int i = 0; i < tmp_data.size(); i++)
{
if (tmp_data[i] < zmin || tmp_data[i] > zmax)
tmp_data[i] = GCTL_BDL_MAX;
}
dVar->put(tmp_data.get(), ynum, xnum);
return;
}
/**
* @brief 保存 Netcdf 格式的规则网格数据文件
*
* @param[in] filename 输出文件名(无后缀)
* @param[in] out_data 输出二维数组
* @param[in] xmin 网格的 x 方向最小值
* @param[in] dx 网格的 x 方向的顶点间隔
* @param[in] ymin 网格的 y 方向最小值
* @param[in] dy 网格的 y 方向的顶点间隔
* @param[in] zmin 网格数据的最小值,默认为 NAN 。 此时函数会自动计算数组的最小值
* @param[in] zmax 网格数据的最大值,默认为 NAN 。 此时函数会自动计算数组的最大值
* @param[in] xname 文件中 x 坐标轴的变量名,默认为 x
* @param[in] yname 文件中 y 坐标轴的变量名,默认为 y
* @param[in] dataname 文件中网格数据的变量名,默认为 z
*/
template
void save_netcdf_grid(std::string filename, const matrix &out_data,
P xmin, P dx, P ymin, P dy, std::string xname = "x", std::string yname = "y",
std::string dataname = "z", T zmin = NAN, T zmax = NAN)
{
// 准备写出数据
if (out_data.empty())
{
throw runtime_error("The output data is empty. From save_netcdf_grid(...)");
}
gctl::array tmpdata;
out_data.reform(tmpdata);
save_netcdf_grid(filename, tmpdata, out_data.col_size(), out_data.row_size(),
xmin, dx, ymin, dy, xname, yname, dataname, zmin, zmax);
return;
}
/**
* @brief 保存 Netcdf 格式的规则网格数据文件
*
* @param[in] filename 输出文件名(无后缀)
* @param[in] out_data 输出数组(注意需将网格数据保存为一个一维数据,左下到右上,行优先排序)
* @param[in] out_x 输出的 x 坐标数组
* @param[in] out_y 输出的 y 坐标数组
* @param[in] zmin 网格数据的最小值,默认为 NAN 。 此时函数会自动计算数组的最小值
* @param[in] zmax 网格数据的最大值,默认为 NAN 。 此时函数会自动计算数组的最大值
* @param[in] xname 文件中 x 坐标轴的变量名,默认为 x
* @param[in] yname 文件中 y 坐标轴的变量名,默认为 y
* @param[in] dataname 文件中网格数据的变量名,默认为 z
*/
template
void save_netcdf_grid(std::string filename, const array &out_data, const array &out_x,
const array
&out_y, std::string xname = "x", std::string yname = "y", std::string dataname = "z",
T zmin = NAN, T zmax = NAN)
{
// 准备写出数据
if (out_data.empty())
{
throw runtime_error("The output data is empty. From save_netcdf_grid(...)");
}
if (filename == "")
{
throw domain_error("The input filename is empty. From save_netcdf_grid(...)");
}
// 判断文件名结尾是否为.nc如果不是则添加.nc结尾
std::string full_name;
if (filename.length() <= 3 || filename.substr(filename.length()-3, filename.length()) != ".nc")
{
full_name = filename + ".nc";
}
else full_name = filename;
NcFile nc_outfile(full_name.c_str(), NcFile::Replace);
if (!nc_outfile.is_valid())
{
throw runtime_error("Can't not open file: " + full_name + ". From save_netcdf_grid(...)");
}
if (std::isnan(zmin))
{
zmin = GCTL_BDL_MAX;
for (int j = 0; j < out_data.size(); j++)
{
if (!std::isnan(out_data[j]) && out_data[j] != GCTL_BDL_MAX)
zmin = GCTL_MIN(zmin, out_data[j]);
}
}
if (std::isnan(zmax))
{
zmax = GCTL_BDL_MIN;
for (int j = 0; j < out_data.size(); j++)
{
if (!std::isnan(out_data[j]) && out_data[j] != GCTL_BDL_MAX)
zmax = GCTL_MAX(zmax, out_data[j]);
}
}
int xnum = out_x.size(), ynum = out_y.size();
T data_range[2] = {zmin, zmax};
P x_range[2] = {out_x[0], out_x[xnum-1]};
P y_range[2] = {out_y[0], out_y[ynum-1]};
time_t now = time(0);
char* dt_char = ctime(&now);
dt_char[strlen(dt_char)-1] = 0; // 删除换行符
std::string dt = dt_char;
std::string his_str = "Generated by gctl::save_netcdf_grid() on " + dt;
//nc_outfile.add_att("title", "Topography data.");
nc_outfile.add_att("history", his_str.c_str());
NcDim *xDim = nc_outfile.add_dim(xname.c_str(), xnum);
NcDim *yDim = nc_outfile.add_dim(yname.c_str(), ynum);
NcType axis_type = ncDouble, val_type = ncDouble;
if (typeid(P).name() == typeid(signed char).name()) axis_type = ncByte;
else if (typeid(P).name() == typeid(char).name()) axis_type = ncChar;
else if (typeid(P).name() == typeid(short).name()) axis_type = ncShort;
else if (typeid(P).name() == typeid(int).name()) axis_type = ncInt;
else if (typeid(P).name() == typeid(float).name()) axis_type = ncFloat;
else if (typeid(P).name() == typeid(double).name()) axis_type = ncDouble;
if (typeid(T).name() == typeid(signed char).name()) val_type = ncByte;
else if (typeid(T).name() == typeid(char).name()) val_type = ncChar;
else if (typeid(T).name() == typeid(short).name()) val_type = ncShort;
else if (typeid(T).name() == typeid(int).name()) val_type = ncInt;
else if (typeid(T).name() == typeid(float).name()) val_type = ncFloat;
else if (typeid(T).name() == typeid(double).name()) val_type = ncDouble;
NcVar *xVar = nc_outfile.add_var(xname.c_str(), axis_type, xDim);
//xVar->add_att("units", 'm');
xVar->add_att("valid_range", 2, &x_range[0]);
xVar->put(out_x.get(), xnum);
NcVar *yVar = nc_outfile.add_var(yname.c_str(), axis_type, yDim);
//yVar->add_att("units", 'm');
yVar->add_att("valid_range", 2, &y_range[0]);
yVar->put(out_y.get(), ynum);
NcVar *dVar = nc_outfile.add_var(dataname.c_str(), val_type, yDim, xDim);
//dVar->add_att("units", 'm');
dVar->add_att("valid_range", 2, &data_range[0]);
dVar->add_att("missing_value", GCTL_BDL_MAX);
array tmp_data(out_data.get(), out_data.size());
for (int i = 0; i < tmp_data.size(); i++)
{
if (tmp_data[i] < zmin || tmp_data[i] > zmax)
tmp_data[i] = GCTL_BDL_MAX;
}
dVar->put(tmp_data.get(), ynum, xnum);
return;
}
/**
* @brief 保存 Netcdf 格式的规则网格数据文件
*
* @param[in] filename 输出文件名(无后缀)
* @param[in] out_data 输出二维数组
* @param[in] out_x 输出的 x 坐标数组
* @param[in] out_y 输出的 y 坐标数组
* @param[in] zmin 网格数据的最小值,默认为 NAN 。 此时函数会自动计算数组的最小值
* @param[in] zmax 网格数据的最大值,默认为 NAN 。 此时函数会自动计算数组的最大值
* @param[in] xname 文件中 x 坐标轴的变量名,默认为 x
* @param[in] yname 文件中 y 坐标轴的变量名,默认为 y
* @param[in] dataname 文件中网格数据的变量名,默认为 z
*/
template
void save_netcdf_grid(std::string filename, const matrix &out_data, const array &out_x,
const array
&out_y, std::string xname = "x", std::string yname = "y", std::string dataname = "z",
T zmin = NAN, T zmax = NAN)
{
// 准备写出数据
if (out_data.empty())
{
throw runtime_error("The output data is empty. From save_netcdf_grid(...)");
}
gctl::array tmpdata;
out_data.reform(tmpdata);
save_netcdf_grid(filename, tmpdata, out_x, out_y, xname, yname, dataname, zmin, zmax);
return;
}
/**
* @brief 追加保存 Netcdf 格式的规则网格数据文件
*
* @warning 追加的网格数据大小必须与已有网格一致
*
* @param[in] filename 输出文件名(无后缀)
* @param[in] out_data 输出数组(注意需将网格数据保存为一个一维数据,左下到右上,行优先排序)
* @param[in] xname 保存到的 x 维度名称
* @param[in] yname 保存到的 y 维度名称
* @param[in] dataname 保存的数据名称,注意不要与已有数据重名
* @param[in] zmin 网格数据的最小值,默认为 NAN 。 此时函数会自动计算数组的最小值
* @param[in] zmax 网格数据的最大值,默认为 NAN 。 此时函数会自动计算数组的最大值
*/
template
void append_netcdf_grid(std::string filename, const array &out_data, std::string xname,
std::string yname, std::string dataname, T zmin = NAN, T zmax = NAN)
{
// 准备写出数据
if (out_data.empty())
{
throw runtime_error("The output data is empty. From append_netcdf_grid(...)");
}
if (filename == "")
{
throw domain_error("The input filename is empty. From append_netcdf_grid(...)");
}
// 判断文件名结尾是否为.nc如果不是则添加.nc结尾
std::string full_name;
if (filename.length() <= 3 || filename.substr(filename.length()-3, filename.length()) != ".nc")
{
full_name = filename + ".nc";
}
else full_name = filename;
NcFile nc_outfile(full_name.c_str(), NcFile::Write);
if (!nc_outfile.is_valid())
{
throw runtime_error("Can't not open file: " + full_name + ". From append_netcdf_grid(...)");
}
NcVar *tmp_var;
std::string tmp_name;
for (int i = 0; i < nc_outfile.num_vars(); i++)
{
tmp_var = nc_outfile.get_var(i);
tmp_name = tmp_var->name();
if (tmp_name == dataname)
{
throw runtime_error("Variable already existed: " + dataname + ". From append_netcdf_grid(...)");
}
}
if (std::isnan(zmin))
{
zmin = GCTL_BDL_MAX;
for (int j = 0; j < out_data.size(); j++)
{
if (!std::isnan(out_data[j]) && out_data[j] != GCTL_BDL_MAX)
zmin = GCTL_MIN(zmin, out_data[j]);
}
}
if (std::isnan(zmax))
{
zmax = GCTL_BDL_MIN;
for (int j = 0; j < out_data.size(); j++)
{
if (!std::isnan(out_data[j]) && out_data[j] != GCTL_BDL_MAX)
zmax = GCTL_MAX(zmax, out_data[j]);
}
}
T data_range[2] = {zmin, zmax};
time_t now = time(0);
char* dt_char = ctime(&now);
dt_char[strlen(dt_char)-1] = 0; // 删除换行符
std::string dt = dt_char;
std::string his_str = "Edited by gctl::append_netcdf_grid() on " + dt;
//nc_outfile.add_att("title", "Topography data.");
nc_outfile.add_att("history", his_str.c_str());
NcDim *xDim = nc_outfile.get_dim(xname.c_str());
NcDim *yDim = nc_outfile.get_dim(yname.c_str());
if (!xDim->is_valid())
{
throw runtime_error("Dimension not found: " + xname + ". From append_netcdf_grid(...)");
}
if (!yDim->is_valid())
{
throw runtime_error("Dimension not found: " + yname + ". From append_netcdf_grid(...)");
}
int xnum = xDim->size();
int ynum = yDim->size();
if (xnum * ynum != out_data.size())
{
throw runtime_error("Grid size does not match. From append_netcdf_grid(...)");
}
NcType val_type = ncDouble;
if (typeid(T).name() == typeid(signed char).name()) val_type = ncByte;
else if (typeid(T).name() == typeid(char).name()) val_type = ncChar;
else if (typeid(T).name() == typeid(short).name()) val_type = ncShort;
else if (typeid(T).name() == typeid(int).name()) val_type = ncInt;
else if (typeid(T).name() == typeid(float).name()) val_type = ncFloat;
else if (typeid(T).name() == typeid(double).name()) val_type = ncDouble;
NcVar *dVar = nc_outfile.add_var(dataname.c_str(), val_type, yDim, xDim);
//dVar->add_att("units", 'm');
dVar->add_att("valid_range", 2, &data_range[0]);
dVar->add_att("missing_value", GCTL_BDL_MAX);
array tmp_data(out_data.get(), out_data.size());
for (int i = 0; i < tmp_data.size(); i++)
{
if (tmp_data[i] < zmin || tmp_data[i] > zmax)
tmp_data[i] = GCTL_BDL_MAX;
}
dVar->put(tmp_data.get(), ynum, xnum);
return;
}
/**
* @brief 追加保存 Netcdf 格式的规则网格数据文件
*
* @warning 追加的网格数据大小必须与已有网格一致
*
* @param[in] filename 输出文件名(无后缀)
* @param[in] out_data 输出二维数组
* @param[in] xname 保存到的 x 维度名称
* @param[in] yname 保存到的 y 维度名称
* @param[in] dataname 保存的数据名称,注意不要与已有数据重名
* @param[in] zmin 网格数据的最小值,默认为 NAN 。 此时函数会自动计算数组的最小值
* @param[in] zmax 网格数据的最大值,默认为 NAN 。 此时函数会自动计算数组的最大值
*/
template
void append_netcdf_grid(std::string filename, const matrix &out_data, std::string xname,
std::string yname, std::string dataname, T zmin = NAN, T zmax = NAN)
{
// 准备写出数据
if (out_data.empty())
{
throw runtime_error("The output data is empty. From append_netcdf_grid(...)");
}
gctl::array tmpdata;
out_data.reform(tmpdata);
append_netcdf_grid(filename, tmpdata, xname, yname, dataname, zmin, zmax);
return;
}
};
#endif // GCTL_NETCDF
#endif // _GCTL_NETCDF_IO_H