gctl_toolkits/xyz2nc/xyz2nc.cpp
2025-02-11 10:43:28 +08:00

339 lines
11 KiB
C++

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* Geophysical Computational Tools & Library (GCTL)
*
* Copyright (c) 2022 Yi Zhang (yizhang-geo@zju.edu.cn)
*
* GCTL is distributed under a dual licensing scheme. You can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version. You should have
* received a copy of the GNU Lesser General Public License along with this
* program. If not, see <http://www.gnu.org/licenses/>.
*
* If the terms and conditions of the LGPL v.2. would prevent you from using
* the GCTL, please consider the option to obtain a commercial license for a
* fee. These licenses are offered by the GCTL's original author. As a rule,
* licenses are provided "as-is", unlimited in time for a one time fee. Please
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
* to include some description of your company and the realm of its activities.
* Also add information on how to contact you by electronic and paper mail.
******************************************************/
#include "gctl/core.h"
#include "gctl/io.h"
#include "gctl/utility.h"
int main(int argc, char *argv[]) try
{
std::string v_str = "Treate all input columns as grid values. Set exact specification of incoming column value table(s). \
Append two chars that indicate file organization: (1) If data is in row format, state if first row is at T(op) or B(ottom). \
Then, append L or R to indicate starting point in row. (2) If data is in column format, state if first columns is \
L(left) or R(ight). Then, append T or B to indicate starting point in column.";
gctl::flags_parser fp;
fp.set_proname("xyz2nc");
fp.set_proinfo("Read xyz data table and write the Netcdf .nc grid files. \
This program is a toolkit of the GCTL package. The GCTL comes with ABSOLUTE NO WARRANTY. \
Please see instructions or contact the author for more information.");
fp.add_opt('t', "table", required_argument, NULL, "Input data table.", "<table>", true);
fp.add_opt('r', "range", required_argument, NULL, "Range of the output grid.", "<xmin>/<xmax>/<ymin>/<ymax>", true);
fp.add_opt('i', "interval", required_argument, NULL, "Intervals of output grid", "<dx>/<dy>", false);
fp.add_opt('s', "size", required_argument, NULL, "Size of the output grid.", "<x-size>/<y-size>", false);
fp.add_opt('g', "grid", required_argument, NULL, "Output grid file. The input table name will be used if not set.", "<grid>", false);
fp.add_opt('c', "column", required_argument, NULL, "Column index of x, y and data. The defaults are 0,1,2. Append extra columns to save multiple grids in one file.", "<x-col>,<y-col>,<z-col>,...", false);
fp.add_opt('v', "value-only", required_argument, NULL, v_str.c_str(), "T|B|L|R", false);
fp.add_opt('l', "label", required_argument, NULL, "Labels of x, y and data. The defaults are 'x', 'y' and 'z'.", "<x-label>,<y-label>,<z-label>,...", false);
fp.add_opt('e', "head-record", required_argument, NULL, "Input file has [0] Header record(s).", "<size>", false);
fp.add_opt('a', "annotate", required_argument, NULL, "The starting symbol of an annotate line. The default is '#'.", "<sym>", false);
fp.add_opt('d', "delimeter", required_argument, NULL, "Delimeter between different columns. The default is space.", "<sym>", false);
fp.add_opt('h', "help", no_argument, NULL, "Show help information.", 0, false);
fp.configure(argc, argv);
if (argc == 1 || fp.set_opt('h'))
{
fp.show_help_page();
return 0;
}
std::string table_name, range_str, interval_str, size_str, grid_name, col_str, label_str, head_str, ant_str, del_str, format_str;
fp.get_argv({'t', 'r', 'i', 's', 'g', 'c', 'l', 'e', 'a', 'd', 'v'},
{&table_name, &range_str, &interval_str, &size_str, &grid_name, &col_str, &label_str, &head_str, &ant_str, &del_str, &format_str});
// 查看是否通过强制参数检查
if (!fp.pass_mandatory()) return 0;
if (grid_name == "NULL")
{
size_t dpos = table_name.find_last_of('.');
if (dpos != std::string::npos) grid_name = table_name.substr(0, dpos);
else grid_name = table_name;
}
if (col_str == "NULL") col_str = "0,1,2";
bool custom_label = false;
if (label_str == "NULL") label_str = "x,y,z";
else custom_label = true;
bool value_only = false;
if (format_str != "NULL") value_only = true;
std::string file_ext;
size_t dpos = table_name.find_last_of('.');
if (dpos != std::string::npos)
{
file_ext = table_name.substr(dpos);
table_name = table_name.substr(0, dpos);
}
else file_ext = ".txt";
gctl::text_descriptor desc;
desc.file_name_ = table_name;
desc.file_ext_ = file_ext;
if (head_str != "NULL") gctl::str2type(head_str, desc.head_num_);
if (ant_str != "NULL") gctl::str2type(ant_str, desc.att_sym_);
if (del_str != "NULL") gctl::str2type(del_str, desc.delimiter_);
if (grid_name == "NULL") grid_name = table_name;
if (interval_str == "NULL" && size_str == "NULL")
{
throw gctl::runtime_error("Either the data intervals or table sizes must be set. See the instructions for more information.");
}
int tmp_int, maxi_col = -1;
std::string tmp_str;
gctl::_1i_vector col_index;
std::stringstream tmp_ss;
gctl::str2ss(col_str, tmp_ss, ",");
while (tmp_ss >> tmp_int)
{
col_index.push_back(tmp_int);
maxi_col = GCTL_MAX(maxi_col, tmp_int);
}
gctl::_1s_vector label_index;
gctl::str2ss(label_str, tmp_ss, ",");
while (tmp_ss >> tmp_str)
{
label_index.push_back(tmp_str);
}
if (!value_only && col_index.size() < 3)
{
GCTL_ShowWhatError("Not enough column index found:", GCTL_ERROR_ERROR,
col_str.c_str(), "Use -h option to see the instruction.", 0);
return 0;
}
if (label_index.size() < 3)
{
GCTL_ShowWhatError("Not enough column labels found:", GCTL_ERROR_ERROR,
label_str.c_str(), "Use -h option to see the instruction.", 0);
return 0;
}
if (custom_label && col_index.size() != label_index.size())
{
GCTL_ShowWhatError("Number of index and labels not match.", GCTL_ERROR_ERROR,
0, "Use -h option to see the instruction.", 0);
return 0;
}
gctl::_2d_vector table_data;
gctl::read_text2vector2d(desc, table_data);
// check data
for (int i = 0; i < table_data.size(); i++)
{
if (table_data[i].size() < maxi_col+1)
{
GCTL_ShowWhatError("Incomplete data set found in:", GCTL_ERROR_ERROR, table_name.c_str(), 0, 0);
return 0;
}
}
int xnum, ynum;
double xmin, xmax, ymin, ymax, dx, dy;
gctl::parse_string_to_value(range_str, '/', true, xmin, xmax, ymin, ymax);
if (interval_str != "NULL")
{
gctl::parse_string_to_value(interval_str, '/', true, dx, dy);
xnum = round((xmax - xmin)/dx) + 1;
ynum = round((ymax - ymin)/dy) + 1;
}
else
{
gctl::parse_string_to_value(size_str, '/', true, xnum, ynum);
dx = (xmax - xmin)/(xnum - 1.0);
dy = (ymax - ymin)/(ynum - 1.0);
}
gctl::array<double> out_data(xnum*ynum, GCTL_BDL_MAX);
int tmp_M, tmp_N;
if (value_only)
{
gctl::array<int> val_idx(table_data.size());
if (format_str == "TL")
{
for (int i = 0; i < ynum; i++)
{
for (int j = 0; j < xnum; j++)
{
val_idx[j + xnum*i] = xnum*(ynum - 1 - i) + j;
}
}
}
else if (format_str == "TR")
{
for (int i = 0; i < ynum; i++)
{
for (int j = 0; j < xnum; j++)
{
val_idx[j + xnum*i] = xnum*(ynum - 1 - i) + xnum - 1 - j;
}
}
}
else if (format_str == "BL")
{
for (int i = 0; i < val_idx.size(); i++)
{
val_idx[i] = i;
}
}
else if (format_str == "BR")
{
for (int i = 0; i < ynum; i++)
{
for (int j = 0; j < xnum; j++)
{
val_idx[j + xnum*i] = xnum*i + xnum - 1 - j;
}
}
}
else if (format_str == "LT")
{
for (int j = 0; j < xnum; j++)
{
for (int i = 0; i < ynum; i++)
{
val_idx[i + ynum*j] = xnum*(ynum - 1 - i) + j;
}
}
}
else if (format_str == "RT")
{
for (int j = 0; j < xnum; j++)
{
for (int i = 0; i < ynum; i++)
{
val_idx[i + ynum*j] = xnum*(ynum - 1 - i) + xnum - 1 - j;
}
}
}
else if (format_str == "LB")
{
for (int j = 0; j < xnum; j++)
{
for (int i = 0; i < ynum; i++)
{
val_idx[i + ynum*j] = xnum*i + j;
}
}
}
else if (format_str == "RB")
{
for (int j = 0; j < xnum; j++)
{
for (int i = 0; i < ynum; i++)
{
val_idx[i + ynum*j] = xnum*i + xnum - 1 - j;
}
}
}
for (int i = 0; i < table_data.size(); i++)
{
out_data[val_idx[i]] = table_data[i][col_index[0]];
}
gctl::save_netcdf_grid(grid_name, out_data, xnum, ynum, xmin, dx, ymin, dy,
label_index[0], label_index[1], label_index[2]);
std::string save_dataname;
if (col_index.size() > 1)
{
for (int c = 1; c < col_index.size(); c++)
{
out_data.assign(GCTL_BDL_MAX);
for (int i = 0; i < table_data.size(); i++)
{
out_data[val_idx[i]] = table_data[i][col_index[c]];
}
if (custom_label)
save_dataname = label_index[c];
else
save_dataname = label_index[2] + "_" + std::to_string(c-1);
gctl::append_netcdf_grid(grid_name, out_data, label_index[0], label_index[1], save_dataname);
}
}
}
else
{
for (int i = 0; i < table_data.size(); i++)
{
if (table_data[i][col_index[0]] >= xmin && table_data[i][col_index[0]] <= xmax &&
table_data[i][col_index[1]] >= ymin && table_data[i][col_index[1]] <= ymax)
{
tmp_N = round((table_data[i][col_index[0]] - xmin)/dx);
tmp_M = round((table_data[i][col_index[1]] - ymin)/dy);
out_data[tmp_M*xnum + tmp_N] = table_data[i][col_index[2]];
}
}
gctl::save_netcdf_grid(grid_name, out_data, xnum, ynum, xmin, dx, ymin, dy,
label_index[0], label_index[1], label_index[2]);
std::string save_dataname;
if (col_index.size() > 3)
{
for (int c = 3; c < col_index.size(); c++)
{
out_data.assign(GCTL_BDL_MAX);
for (int i = 0; i < table_data.size(); i++)
{
if (table_data[i][col_index[0]] >= xmin && table_data[i][col_index[0]] <= xmax &&
table_data[i][col_index[1]] >= ymin && table_data[i][col_index[1]] <= ymax)
{
tmp_N = round((table_data[i][col_index[0]] - xmin)/dx);
tmp_M = round((table_data[i][col_index[1]] - ymin)/dy);
out_data[tmp_M*xnum + tmp_N] = table_data[i][col_index[c]];
}
}
if (custom_label)
save_dataname = label_index[c];
else
save_dataname = label_index[2] + "_" + std::to_string(c-1);
gctl::append_netcdf_grid(grid_name, out_data, label_index[0], label_index[1], save_dataname);
}
}
}
return 0;
}
catch(std::exception &e)
{
GCTL_ShowWhatError(e.what(), GCTL_ERROR_ERROR, 0, 0, 0);
}