#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(&info), sizeof(DataFileInfo)); file.close(); } return info; } std::vector get_wind_data_file_time_arr(const std::string& filepath, const DataFileInfo& info) { std::vector time_arr(info.Num); if (get_WindDataFileTimeArr(filepath.c_str(), info, time_arr.data()) == 0) { return time_arr; } else { std::vector time_arra(0); return time_arra; } } bool read_wind_data_file(const std::string& filepath, const DataFileInfo& info, int64_t time_id, std::vector& u_arr, std::vector& 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 ERA5NetCDFConverter::convert_to_era5_time(const std::vector& unix_timestamps) { std::vector 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(time_point - era5_epoch); era5_times.push_back(static_cast(duration.count())); } return era5_times; } // 创建经纬度坐标数组 std::vector ERA5NetCDFConverter::create_coordinate_array(double min, double max, size_t size) { std::vector 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 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 lon_data = create_coordinate_array(info.minLon, info.maxLon, info.Width); std::vector lat_data = create_coordinate_array(info.minLat, info.maxLat, info.Height); std::reverse(lat_data.begin(), lat_data.end()); std::vector 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 u_data(info.Height * info.Width); std::vector 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 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 lon_data = create_coordinate_array(info.minLon, info.maxLon, info.Width); std::vector lat_data = create_coordinate_array(info.minLat, info.maxLat, info.Height); std::vector 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 u_data(info.Height * info.Width); std::vector 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; } }