|
| 1 | +#!/usr/bin/env bun |
| 2 | +// Example Bun script demonstrating readap-wasm for OpenDAP data analysis |
| 3 | +// Run with: bun run bun-example.js |
| 4 | + |
| 5 | +import init, { OpenDAPDataset } from '../pkg/readap_wasm.js'; |
| 6 | + |
| 7 | +const BASE_URL = 'https://compute.earthmover.io/v1/services/dap2/earthmover-demos/gfs/main/solar/opendap'; |
| 8 | + |
| 9 | +async function analyzeMeteorologyData() { |
| 10 | + console.log('🌊 ReadAP WASM + Bun Example - Meteorological Data Analysis'); |
| 11 | + console.log('='.repeat(60)); |
| 12 | + |
| 13 | + // Initialize the WASM module |
| 14 | + await init(); |
| 15 | + |
| 16 | + try { |
| 17 | + // Load the dataset |
| 18 | + console.log('📡 Loading dataset metadata...'); |
| 19 | + const dataset = await OpenDAPDataset.fromURL(BASE_URL); |
| 20 | + |
| 21 | + // Display available variables |
| 22 | + const variables = dataset.getVariableNames(); |
| 23 | + console.log(`📊 Found ${variables.length} variables:`); |
| 24 | + variables.forEach((name, i) => { |
| 25 | + console.log(` ${i + 1}. ${name}`); |
| 26 | + }); |
| 27 | + |
| 28 | + // Analyze a specific variable |
| 29 | + console.log('\n🔍 Analyzing temperature data (t2m)...'); |
| 30 | + const tempInfo = JSON.parse(dataset.getVariableInfo('t2m')); |
| 31 | + console.log(` - Dimensions: ${tempInfo.dimensions?.join(', ') || 'N/A'}`); |
| 32 | + console.log(` - Attributes: ${Object.keys(tempInfo.attributes || {}).length} found`); |
| 33 | + |
| 34 | + // Load coordinates for advanced selections |
| 35 | + console.log('\n📍 Loading coordinate data...'); |
| 36 | + const coords = ['time', 'latitude', 'longitude']; |
| 37 | + await Promise.all(coords.map(coord => dataset.loadCoordinates(coord))); |
| 38 | + console.log(' ✅ Coordinates loaded successfully'); |
| 39 | + |
| 40 | + // Perform different types of data selections |
| 41 | + console.log('\n🎯 Performing data selections...'); |
| 42 | + |
| 43 | + // 1. Simple index-based selection |
| 44 | + console.log(' → Index-based selection (first time, lat 10-20)'); |
| 45 | + const indexSelection = dataset.isel({ |
| 46 | + time: { type: "single", value: 0 }, |
| 47 | + latitude: { type: "range", start: 10, end: 20 } |
| 48 | + }); |
| 49 | + const tempIndexData = await dataset.getVariable('t2m', indexSelection); |
| 50 | + console.log(` Data shape: ${tempIndexData.length} elements`); |
| 51 | + console.log(` Temperature range: ${Math.min(...tempIndexData.data)} to ${Math.max(...tempIndexData.data)} K`); |
| 52 | + |
| 53 | + // 2. Value-based selection with nearest neighbor |
| 54 | + console.log(' → Value-based selection (NYC area)'); |
| 55 | + const valueSelection = dataset.sel({ |
| 56 | + latitude: [40.0, 41.0], // NYC latitude range |
| 57 | + longitude: [-75.0, -73.0] // NYC longitude range |
| 58 | + }); |
| 59 | + const tempValueData = await dataset.getVariable('t2m', valueSelection); |
| 60 | + console.log(` Data shape: ${tempValueData.length} elements`); |
| 61 | + |
| 62 | + // 3. Multi-variable analysis |
| 63 | + console.log(' → Multi-variable analysis'); |
| 64 | + const multiVars = ['t2m', 'tcc', 'gust']; |
| 65 | + const multiData = await dataset.getVariables(multiVars, indexSelection); |
| 66 | + |
| 67 | + console.log(' Variable statistics:'); |
| 68 | + Object.entries(multiData).forEach(([varName, data]) => { |
| 69 | + const min = Math.min(...data.data); |
| 70 | + const max = Math.max(...data.data); |
| 71 | + const avg = data.data.reduce((a, b) => a + b, 0) / data.data.length; |
| 72 | + console.log(` ${varName}: min=${min.toFixed(2)}, max=${max.toFixed(2)}, avg=${avg.toFixed(2)}`); |
| 73 | + }); |
| 74 | + |
| 75 | + // 4. Chained selections for complex analysis |
| 76 | + console.log(' → Chained selection (surface data for specific region)'); |
| 77 | + const chainedSelection = dataset |
| 78 | + .isel({ time: { type: "single", value: 0 } }) |
| 79 | + .sel({ latitude: [35.0, 45.0], longitude: [-80.0, -70.0] }); |
| 80 | + |
| 81 | + const surfaceTemp = await dataset.getVariable('t2m', chainedSelection); |
| 82 | + console.log(` Surface temperature data: ${surfaceTemp.length} grid points`); |
| 83 | + |
| 84 | + // Performance timing |
| 85 | + console.log('\n⏱️ Performance test - rapid data access:'); |
| 86 | + const startTime = performance.now(); |
| 87 | + |
| 88 | + const rapidSelections = await Promise.all([ |
| 89 | + dataset.getVariable('t2m', dataset.isel({ time: { type: "single", value: 0 } })), |
| 90 | + dataset.getVariable('tcc', dataset.isel({ time: { type: "single", value: 0 } })), |
| 91 | + dataset.getVariable('gust', dataset.isel({ time: { type: "single", value: 0 } })) |
| 92 | + ]); |
| 93 | + |
| 94 | + const endTime = performance.now(); |
| 95 | + console.log(` ✅ Fetched 3 variables in ${(endTime - startTime).toFixed(2)}ms`); |
| 96 | + |
| 97 | + // Summary |
| 98 | + console.log('\n📈 Analysis Summary:'); |
| 99 | + console.log(` • Dataset variables: ${variables.length}`); |
| 100 | + console.log(` • Total data points analyzed: ${rapidSelections.reduce((sum, data) => sum + data.length, 0)}`); |
| 101 | + console.log(` • Coordinate systems: ${coords.length} loaded`); |
| 102 | + console.log(' • Selection methods: index-based, value-based, chained'); |
| 103 | + |
| 104 | + } catch (error) { |
| 105 | + console.error('❌ Error during analysis:', error); |
| 106 | + process.exit(1); |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +// Run the analysis |
| 111 | +console.log('🚀 Starting Bun + ReadAP WASM analysis...\n'); |
| 112 | +analyzeMeteorologyData() |
| 113 | + .then(() => { |
| 114 | + console.log('\n✅ Analysis completed successfully!'); |
| 115 | + process.exit(0); |
| 116 | + }) |
| 117 | + .catch((error) => { |
| 118 | + console.error('\n❌ Analysis failed:', error); |
| 119 | + process.exit(1); |
| 120 | + }); |
0 commit comments