const fs = require('fs'); const path = require('path'); const { parse } = require('csv-parse'); const readline = require('readline'); const { leftlon, rightlon, toplat, bottomlat } = require("./region"); // 仅导出中国区域数据 const JUST_EXPORT_CHINADATA = true; // 配置参数 const config = { outputDir: path.join(__dirname, `../model`), // 输出目录 sampleRate: 0.1, // 抽样率 (0.1 = 10%的数据) testMode: false, // 测试模式,只处理少量数据 testLimit: 1000, // 测试模式下的最大行数 outputDir: path.join(__dirname, `../model`), outputFile: 'windGridData.json', knownGridParams: { minLon: -179, maxLon: 180, minLat: -90, maxLat: 90, dx: 1.0, // 假设1度分辨率 dy: 1.0, // 假设1度分辨率 nx: 361, // 经度点数: 180*2 + 1 ny: 181 // 纬度点数: 90*2 + 1 } }; async function createWindData(uFile, vFile) { try { console.log('开始转换为网格JSON格式...'); // 并行解析U和V的CSV文件 const [uData, vData] = await Promise.all([ parseCSVFile(uFile, 'U'), parseCSVFile(vFile, 'V') ]); // 检查数据是否有效 if (uData.length === 0 || vData.length === 0) { throw new Error('U或V数据为空'); } // 使用已知的全球网格参数 const gridParams = config.knownGridParams; // 为U和V数据创建网格结构 const uGrid = createGridData(uData, gridParams, 'U'); const vGrid = createGridData(vData, gridParams, 'V'); if (!uGrid || !vGrid) { throw new Error('网格创建失败'); } // 组合成风场库需要的数组格式 const outputData = [uGrid, vGrid]; // 写入输出文件 const outputPath = path.join(config.outputDir, config.outputFile); fs.writeFileSync(outputPath, JSON.stringify(outputData)); console.log(`转换成功! 网格JSON已保存到: ${outputPath}`); console.log(`U网格信息: nx=${uGrid.header.nx}, ny=${uGrid.header.ny}`); console.log(`V网格信息: nx=${vGrid.header.nx}, ny=${vGrid.header.ny}`); } catch (error) { console.error('转换过程中出错:', error); } } // 确保输出目录存在 if (!fs.existsSync(config.outputDir)) { fs.mkdirSync(config.outputDir, { recursive: true }); } // 解析CSV文件的函数 async function parseCSVFile(filePath, component) { return new Promise((resolve, reject) => { const results = []; let lineCount = 0; const rl = readline.createInterface({ input: fs.createReadStream(filePath), crlfDelay: Infinity }); rl.on('line', (line) => { if (!line.trim()) return; try { const cleanedLine = line.replace(/"/g, ''); const parts = cleanedLine.split(','); if (parts.length < 7) return; const lon = parseFloat(parts[4]); const lat = parseFloat(parts[5]); const value = parseFloat(parts[6]); if (!isNaN(lon) && !isNaN(lat) && !isNaN(value)) { results.push({ lon, lat, value }); } } catch (e) { console.error('解析行时出错:', line, e); } lineCount++; }); rl.on('close', () => { console.log(`从 ${filePath} 解析了 ${results.length} 条 ${component} 记录`); resolve(results); }); rl.on('error', reject); }); } // 创建网格数据 - 使用已知的全球网格参数 function createGridData(parsedData, gridParams, component) { console.log(`开始创建 ${component} 网格数据...`); const { minLon, maxLon, minLat, maxLat, dx, dy, nx, ny } = gridParams; // 创建空网格(用null填充) const gridData = new Array(nx * ny).fill(null); // 将解析的数据填充到网格中 let filledCount = 0; let missingCount = 0; parsedData.forEach(point => { // 计算网格索引 const i = Math.round((point.lon - minLon) / dx); const j = Math.round((maxLat - point.lat) / dy); // 注意纬度是从上到下递减 const index = j * nx + i; if (index >= 0 && index < gridData.length) { gridData[index] = point.value; filledCount++; } else { missingCount++; console.warn(`点超出网格范围: (${point.lon}, ${point.lat}) -> 索引: ${index}`); } }); console.log(`${component} 网格填充了 ${filledCount} 个数据点,缺失 ${missingCount} 个点`); console.log(`${component} 数据非空比例: ${(filledCount / gridData.length * 100).toFixed(2)}%`); if (filledCount === 0) { console.error(`错误: ${component} 网格没有有效数据`); return null; } return { header: { parameterCategory: 2, parameterCategoryName: "Momentum", parameterNumber: component === 'U' ? 2 : 3, parameterNumberName: component === 'U' ? "U-component_of_wind" : "V-component_of_wind", nx: nx, ny: ny, lo1: minLon, la1: maxLat, dx: dx, dy: dy, numberPoints: nx * ny, refTime: "2025-09-10T00:00:00Z" }, data: gridData }; } async function main() { try { console.log('开始转换为网格JSON格式...'); // 并行解析U和V的CSV文件 const [uData, vData] = await Promise.all([ parseCSVFile(config.uCsvFile, 'U'), parseCSVFile(config.vCsvFile, 'V') ]); // 检查数据是否有效 if (uData.length === 0 || vData.length === 0) { throw new Error('U或V数据为空'); } // 使用已知的全球网格参数 const gridParams = config.knownGridParams; // 为U和V数据创建网格结构 const uGrid = createGridData(uData, gridParams, 'U'); const vGrid = createGridData(vData, gridParams, 'V'); if (!uGrid || !vGrid) { throw new Error('网格创建失败'); } // 组合成风场库需要的数组格式 const outputData = [uGrid, vGrid]; // 写入输出文件 const outputPath = path.join(config.outputDir, config.outputFile); fs.writeFileSync(outputPath, JSON.stringify(outputData)); console.log(`转换成功! 网格JSON已保存到: ${outputPath}`); console.log(`U网格信息: nx=${uGrid.header.nx}, ny=${uGrid.header.ny}`); console.log(`V网格信息: nx=${vGrid.header.nx}, ny=${vGrid.header.ny}`); } catch (error) { console.error('转换过程中出错:', error); } } module.exports = { createWindData };