Manual-Labeling-Tool/Manual-Labeling-Client/WindDataOperator/Wind2ERANc.cpp

306 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "Wind2ERANc.h"
#include "WindDataFileOperator.h"
DataFileInfo get_data_file_info(const std::string& filepath) {
DataFileInfo info;
// 这里需要实现从二进制文件读取头信息的逻辑
std::ifstream file(filepath, std::ios::binary);
if (file) {
file.read(reinterpret_cast<char*>(&info), sizeof(DataFileInfo));
file.close();
}
return info;
}
std::vector<int64_t> get_wind_data_file_time_arr(const std::string& filepath, const DataFileInfo& info) {
std::vector<int64_t> time_arr(info.Num);
if (get_WindDataFileTimeArr(filepath.c_str(), info, time_arr.data()) == 0) {
return time_arr;
}
else {
std::vector<int64_t> time_arra(0);
return time_arra;
}
}
bool read_wind_data_file(const std::string& filepath, const DataFileInfo& info,
int64_t time_id, std::vector<double>& u_arr, std::vector<double>& v_arr) {
if (Read_WindDataFile(filepath.c_str(),
info,
time_id, u_arr.data(), v_arr.data()) == 0) {
return true;
}
return false;
}
// 处理NetCDF错误
void ERA5NetCDFConverter::handle_netcdf_error(int status, const std::string& operation) {
if (status != NC_NOERR) {
std::cerr << "NetCDF错误 " << operation << ": " << nc_strerror(status) << std::endl;
throw std::runtime_error("NetCDF操作失败");
}
}
// 将Unix时间戳转换为ERA5使用的时间格式
std::vector<double> ERA5NetCDFConverter::convert_to_era5_time(const std::vector<int64_t>& unix_timestamps) {
std::vector<double> era5_times;
era5_times.reserve(unix_timestamps.size());
// ERA5时间通常是从1900-01-01开始的小时数
const auto era5_epoch = std::chrono::system_clock::from_time_t(-2208988800); // 1900-01-01
for (auto timestamp : unix_timestamps) {
auto time_point = std::chrono::system_clock::from_time_t(timestamp);
auto duration = std::chrono::duration_cast<std::chrono::hours>(time_point - era5_epoch);
era5_times.push_back(static_cast<double>(duration.count()));
}
return era5_times;
}
// 创建经纬度坐标数组
std::vector<double> ERA5NetCDFConverter::create_coordinate_array(double min, double max, size_t size) {
std::vector<double> coord(size);
double step = (max - min) / (size - 1);
for (size_t i = 0; i < size; ++i) {
coord[i] = min + i * step;
}
return coord;
}
bool ERA5NetCDFConverter::convert_to_era5_netcdf(const std::string& input_bin_file, const std::string& output_nc_file) {
try {
// 1. 读取二进制文件信息
DataFileInfo info = getDataFileInfo(input_bin_file.c_str());
std::cout << "文件信息: " << info.Height << "x" << info.Width
<< " 网格, " << info.Num << " 个时间步" << std::endl;
// 2. 获取时间数组
std::vector<int64_t> time_arr = get_wind_data_file_time_arr(input_bin_file.c_str(), info);
if (time_arr.empty()) {
std::cerr << "无法读取时间数组" << std::endl;
return false;
}
// 3. 创建NetCDF文件
int ncid, status;
status = nc_create(output_nc_file.c_str(), NC_NETCDF4, &ncid);
handle_netcdf_error(status, "创建文件");
// 4. 定义维度
int lon_dim, lat_dim, time_dim;
status = nc_def_dim(ncid, "longitude", info.Width, &lon_dim);
handle_netcdf_error(status, "定义经度维度");
status = nc_def_dim(ncid, "latitude", info.Height, &lat_dim);
handle_netcdf_error(status, "定义纬度维度");
status = nc_def_dim(ncid, "time", NC_UNLIMITED, &time_dim);
handle_netcdf_error(status, "定义时间维度");
// 5. 定义坐标变量
int lon_var, lat_var, time_var;
int dims_coord[1] = { lon_dim };
status = nc_def_var(ncid, "longitude", NC_DOUBLE, 1, dims_coord, &lon_var);
handle_netcdf_error(status, "定义经度变量");
dims_coord[0] = lat_dim;
status = nc_def_var(ncid, "latitude", NC_DOUBLE, 1, dims_coord, &lat_var);
handle_netcdf_error(status, "定义纬度变量");
dims_coord[0] = time_dim;
status = nc_def_var(ncid, "time", NC_DOUBLE, 1, dims_coord, &time_var);
handle_netcdf_error(status, "定义时间变量");
// 6. 定义数据变量U和V分量
int u10_var, v10_var;
int dims_data[3] = { time_dim, lat_dim, lon_dim };
status = nc_def_var(ncid, "u10", NC_DOUBLE, 3, dims_data, &u10_var);
handle_netcdf_error(status, "定义u10变量");
status = nc_def_var(ncid, "v10", NC_DOUBLE, 3, dims_data, &v10_var);
handle_netcdf_error(status, "定义v10变量");
// 7. 添加属性
std::string time_units = "hours since 1900-01-01 00:00:00.0";
status = nc_put_att_text(ncid, time_var, "units", time_units.length(), time_units.c_str());
handle_netcdf_error(status, "添加时间单位属性");
status = nc_put_att_text(ncid, lon_var, "units", 12, "degrees_east");
status = nc_put_att_text(ncid, lat_var, "units", 13, "degrees_north");
status = nc_put_att_text(ncid, u10_var, "units", 6, "m s**-1");
status = nc_put_att_text(ncid, v10_var, "units", 6, "m s**-1");
status = nc_put_att_text(ncid, u10_var, "long_name", 25, "10 metre U wind component");
status = nc_put_att_text(ncid, v10_var, "long_name", 25, "10 metre V wind component");
// 8. 结束定义模式
status = nc_enddef(ncid);
handle_netcdf_error(status, "结束定义模式");
// 9. 写入坐标数据
std::vector<double> lon_data = create_coordinate_array(info.minLon, info.maxLon, info.Width);
std::vector<double> lat_data = create_coordinate_array(info.minLat, info.maxLat, info.Height);
std::reverse(lat_data.begin(), lat_data.end());
std::vector<double> era5_time = convert_to_era5_time(time_arr);
status = nc_put_var_double(ncid, lon_var, lon_data.data());
handle_netcdf_error(status, "写入经度数据");
status = nc_put_var_double(ncid, lat_var, lat_data.data());
handle_netcdf_error(status, "写入纬度数据");
status = nc_put_var_double(ncid, time_var, era5_time.data());
handle_netcdf_error(status, "写入时间数据");
// 10. 写入风场数据
std::vector<double> u_data(info.Height * info.Width);
std::vector<double> v_data(info.Height * info.Width);
size_t start[3] = { 0, 0, 0 };
size_t count[3] = { 1, info.Height, info.Width };
for (int64_t t = 0; t < info.Num; ++t) {
if (read_wind_data_file(input_bin_file, info, t, u_data, v_data)) {
start[0] = t;
status = nc_put_vara_double(ncid, u10_var, start, count, u_data.data());
handle_netcdf_error(status, "写入u10数据");
status = nc_put_vara_double(ncid, v10_var, start, count, v_data.data());
handle_netcdf_error(status, "写入v10数据");
if (t % 10 == 0) {
std::cout << "已处理 " << t + 1 << "/" << info.Num << " 个时间步" << std::endl;
}
}
}
// 11. 关闭文件
status = nc_close(ncid);
handle_netcdf_error(status, "关闭文件");
std::cout << "转换完成!输出文件: " << output_nc_file << std::endl;
return true;
}
catch (const std::exception& e) {
std::cerr << "转换过程出错: " << e.what() << std::endl;
return false;
}
}
bool ERA5NetCDFConverter::convert_to_era5_netcdf(const std::string& input_bin_file, const std::string& output_nc_file, int64_t tid)
{
try {
// 1. 读取二进制文件信息
DataFileInfo info = getDataFileInfo(input_bin_file.c_str());
std::cout << "文件信息: " << info.Height << "x" << info.Width
<< " 网格, " << info.Num << " 个时间步" << std::endl;
// 2. 获取时间数组
std::vector<int64_t> time_arr = get_wind_data_file_time_arr(input_bin_file.c_str(), info);
if (time_arr.empty()) {
std::cerr << "无法读取时间数组" << std::endl;
return false;
}
// 3. 创建NetCDF文件
int ncid, status;
status = nc_create(output_nc_file.c_str(), NC_NETCDF4, &ncid);
handle_netcdf_error(status, "创建文件");
// 4. 定义维度
int lon_dim, lat_dim, time_dim;
status = nc_def_dim(ncid, "longitude", info.Width, &lon_dim);
handle_netcdf_error(status, "定义经度维度");
status = nc_def_dim(ncid, "latitude", info.Height, &lat_dim);
handle_netcdf_error(status, "定义纬度维度");
status = nc_def_dim(ncid, "time", NC_UNLIMITED, &time_dim);
handle_netcdf_error(status, "定义时间维度");
// 5. 定义坐标变量
int lon_var, lat_var, time_var;
int dims_coord[1] = { lon_dim };
status = nc_def_var(ncid, "longitude", NC_DOUBLE, 1, dims_coord, &lon_var);
handle_netcdf_error(status, "定义经度变量");
dims_coord[0] = lat_dim;
status = nc_def_var(ncid, "latitude", NC_DOUBLE, 1, dims_coord, &lat_var);
handle_netcdf_error(status, "定义纬度变量");
dims_coord[0] = time_dim;
status = nc_def_var(ncid, "time", NC_DOUBLE, 1, dims_coord, &time_var);
handle_netcdf_error(status, "定义时间变量");
// 6. 定义数据变量U和V分量
int u10_var, v10_var;
int dims_data[3] = { time_dim, lat_dim, lon_dim };
status = nc_def_var(ncid, "u10", NC_DOUBLE, 3, dims_data, &u10_var);
handle_netcdf_error(status, "定义u10变量");
status = nc_def_var(ncid, "v10", NC_DOUBLE, 3, dims_data, &v10_var);
handle_netcdf_error(status, "定义v10变量");
// 7. 添加属性
std::string time_units = "hours since 1900-01-01 00:00:00.0";
status = nc_put_att_text(ncid, time_var, "units", time_units.length(), time_units.c_str());
handle_netcdf_error(status, "添加时间单位属性");
status = nc_put_att_text(ncid, lon_var, "units", 12, "degrees_east");
status = nc_put_att_text(ncid, lat_var, "units", 13, "degrees_north");
status = nc_put_att_text(ncid, u10_var, "units", 6, "m s**-1");
status = nc_put_att_text(ncid, v10_var, "units", 6, "m s**-1");
status = nc_put_att_text(ncid, u10_var, "long_name", 25, "10 metre U wind component");
status = nc_put_att_text(ncid, v10_var, "long_name", 25, "10 metre V wind component");
// 8. 结束定义模式
status = nc_enddef(ncid);
handle_netcdf_error(status, "结束定义模式");
// 9. 写入坐标数据
std::vector<double> lon_data = create_coordinate_array(info.minLon, info.maxLon, info.Width);
std::vector<double> lat_data = create_coordinate_array(info.minLat, info.maxLat, info.Height);
std::vector<double> era5_time = convert_to_era5_time(time_arr);
std::reverse(lat_data.begin(), lat_data.end());
status = nc_put_var_double(ncid, lon_var, lon_data.data());
handle_netcdf_error(status, "写入经度数据");
status = nc_put_var_double(ncid, lat_var, lat_data.data());
handle_netcdf_error(status, "写入纬度数据");
status = nc_put_var_double(ncid, time_var, era5_time.data());
handle_netcdf_error(status, "写入时间数据");
// 10. 写入风场数据
std::vector<double> u_data(info.Height * info.Width);
std::vector<double> v_data(info.Height * info.Width);
size_t start[3] = { 0, 0, 0 };
size_t count[3] = { 1, info.Height, info.Width };
for (int64_t t = 0; t < info.Num; ++t) {
if (t != tid) { continue; }
if (read_wind_data_file(input_bin_file, info, t, u_data, v_data)) {
start[0] = t;
status = nc_put_vara_double(ncid, u10_var, start, count, u_data.data());
handle_netcdf_error(status, "写入u10数据");
status = nc_put_vara_double(ncid, v10_var, start, count, v_data.data());
handle_netcdf_error(status, "写入v10数据");
if (t % 10 == 0) {
std::cout << "已处理 " << t + 1 << "/" << info.Num << " 个时间步" << std::endl;
}
}
}
// 11. 关闭文件
status = nc_close(ncid);
handle_netcdf_error(status, "关闭文件");
std::cout << "转换完成!输出文件: " << output_nc_file << std::endl;
return true;
}
catch (const std::exception& e) {
std::cerr << "转换过程出错: " << e.what() << std::endl;
return false;
}
}