@earthyscience/netcdf4-wasm 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +26 -3
- package/dist/constants.js.map +1 -1
- package/dist/group.d.ts +3 -1
- package/dist/group.d.ts.map +1 -1
- package/dist/group.js +45 -4
- package/dist/group.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/netcdf-getters.d.ts +87 -8
- package/dist/netcdf-getters.d.ts.map +1 -1
- package/dist/netcdf-getters.js +441 -104
- package/dist/netcdf-getters.js.map +1 -1
- package/dist/netcdf-worker.js +63 -68
- package/dist/netcdf-worker.js.map +1 -1
- package/dist/netcdf4-wasm.js +1 -1
- package/dist/netcdf4-wasm.wasm +0 -0
- package/dist/netcdf4.d.ts +139 -12
- package/dist/netcdf4.d.ts.map +1 -1
- package/dist/netcdf4.js +422 -36
- package/dist/netcdf4.js.map +1 -1
- package/dist/types.d.ts +106 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +1 -1
- package/dist/wasm-module.d.ts.map +1 -1
- package/dist/wasm-module.js +337 -5
- package/dist/wasm-module.js.map +1 -1
- package/package.json +17 -7
package/dist/netcdf-getters.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { NC_CONSTANTS, DATA_TYPE_SIZE, CONSTANT_DTYPE_MAP } from './constants.js';
|
|
2
|
-
export function
|
|
2
|
+
export function getGroupVariables(module, ncid, groupPath) {
|
|
3
|
+
const workingNcid = groupPath ? getGroupNCID(module, ncid, groupPath) : ncid;
|
|
3
4
|
const variables = {};
|
|
4
|
-
const varCount = getVarCount(module,
|
|
5
|
-
const dimIds = getDimIDs(module, ncid);
|
|
5
|
+
const varCount = getVarCount(module, workingNcid);
|
|
6
6
|
for (let varid = 0; varid < varCount; varid++) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (result.result !== NC_CONSTANTS.NC_NOERR || !result.name) {
|
|
11
|
-
console.warn(`Failed to get variable name for varid ${varid} (error: ${result.result})`);
|
|
7
|
+
const nameResult = module.nc_inq_varname(workingNcid, varid);
|
|
8
|
+
if (nameResult.result !== NC_CONSTANTS.NC_NOERR || !nameResult.name) {
|
|
9
|
+
console.warn(`Failed to get variable name for varid ${varid} (error: ${nameResult.result})`);
|
|
12
10
|
continue;
|
|
13
11
|
}
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
// A coordinate variable is one whose name matches a dimension.
|
|
13
|
+
const isCoordinate = findDimInHierarchy(module, workingNcid, nameResult.name);
|
|
14
|
+
if (isCoordinate)
|
|
15
|
+
continue;
|
|
16
|
+
variables[nameResult.name] = {
|
|
17
|
+
id: varid,
|
|
18
|
+
ncid: workingNcid // CRITICAL: Store the ncid where this variable lives!
|
|
16
19
|
};
|
|
17
20
|
}
|
|
18
21
|
return variables;
|
|
@@ -31,73 +34,104 @@ export function getDimCount(module, ncid) {
|
|
|
31
34
|
}
|
|
32
35
|
return result.ndims || 0;
|
|
33
36
|
}
|
|
34
|
-
export function getDims(module, ncid) {
|
|
35
|
-
const
|
|
37
|
+
export function getDims(module, ncid, groupPath) {
|
|
38
|
+
const workingNcid = groupPath ? getGroupNCID(module, ncid, groupPath) : ncid;
|
|
39
|
+
const dimIDs = getDimIDs(module, workingNcid);
|
|
36
40
|
const dims = {};
|
|
37
41
|
for (const dimid of dimIDs) {
|
|
38
|
-
const dim = getDim(module,
|
|
42
|
+
const dim = getDim(module, workingNcid, dimid);
|
|
39
43
|
dims[dim.name] = {
|
|
40
44
|
size: dim.len,
|
|
41
|
-
units: dim.units,
|
|
45
|
+
units: dim.units ?? null,
|
|
42
46
|
id: dim.id
|
|
43
47
|
};
|
|
44
48
|
}
|
|
45
49
|
return dims;
|
|
46
50
|
}
|
|
47
|
-
export function getDimIDs(module, ncid) {
|
|
48
|
-
const result = module.nc_inq_dimids(ncid, 0);
|
|
51
|
+
export function getDimIDs(module, ncid, includeParents = false) {
|
|
52
|
+
const result = module.nc_inq_dimids(ncid, includeParents ? 1 : 0);
|
|
49
53
|
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
50
54
|
throw new Error(`Failed to get dimension IDs (error: ${result.result})`);
|
|
51
55
|
}
|
|
52
|
-
return result.dimids
|
|
56
|
+
return result.dimids ?? [];
|
|
57
|
+
}
|
|
58
|
+
function findCoordinateVariable(module, startNcid, name) {
|
|
59
|
+
let current = startNcid;
|
|
60
|
+
while (current !== null) {
|
|
61
|
+
const result = module.nc_inq_varid(current, name);
|
|
62
|
+
if (result.result === NC_CONSTANTS.NC_NOERR) {
|
|
63
|
+
return {
|
|
64
|
+
ncid: current,
|
|
65
|
+
varid: result.varid
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
current = getGroupParent(module, current);
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
53
71
|
}
|
|
54
72
|
export function getDim(module, ncid, dimid) {
|
|
55
73
|
const result = module.nc_inq_dim(ncid, dimid);
|
|
56
74
|
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
57
75
|
throw new Error(`Failed to get dim (error: ${result.result})`);
|
|
58
76
|
}
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
77
|
+
const { result: _r, ...dim } = result;
|
|
78
|
+
let varID = null;
|
|
79
|
+
let units = null;
|
|
80
|
+
let coordNcid = null;
|
|
81
|
+
// Search upward for coordinate variable
|
|
82
|
+
const coord = findCoordinateVariable(module, ncid, dim.name);
|
|
83
|
+
if (coord) {
|
|
84
|
+
varID = coord.varid;
|
|
85
|
+
coordNcid = coord.ncid;
|
|
86
|
+
units = getAttributeValues(module, coordNcid, varID, "units");
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
...dim,
|
|
90
|
+
id: varID,
|
|
91
|
+
units,
|
|
92
|
+
coordNcid // useful for debugging
|
|
93
|
+
};
|
|
64
94
|
}
|
|
65
95
|
export function getAttributeValues(module, ncid, varid, attname) {
|
|
66
96
|
const attInfo = module.nc_inq_att(ncid, varid, attname);
|
|
67
97
|
if (attInfo.result !== NC_CONSTANTS.NC_NOERR) {
|
|
68
98
|
console.warn(`Failed to get attribute info for ${attname} (error: ${attInfo.result})`);
|
|
69
|
-
return;
|
|
99
|
+
return null;
|
|
70
100
|
}
|
|
71
101
|
const attType = attInfo.type;
|
|
72
102
|
if (!attType)
|
|
73
103
|
throw new Error("Failed to allocate memory for attribute type.");
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
104
|
+
// Dispatch table: maps NetCDF type -> module getter
|
|
105
|
+
const getterMap = {
|
|
106
|
+
[NC_CONSTANTS.NC_CHAR]: module.nc_get_att_text,
|
|
107
|
+
[NC_CONSTANTS.NC_SHORT]: module.nc_get_att_short,
|
|
108
|
+
[NC_CONSTANTS.NC_INT]: module.nc_get_att_int,
|
|
109
|
+
[NC_CONSTANTS.NC_FLOAT]: module.nc_get_att_float,
|
|
110
|
+
[NC_CONSTANTS.NC_DOUBLE]: module.nc_get_att_double,
|
|
111
|
+
[NC_CONSTANTS.NC_UBYTE]: module.nc_get_att_uchar,
|
|
112
|
+
[NC_CONSTANTS.NC_UINT]: module.nc_get_att_uint,
|
|
113
|
+
[NC_CONSTANTS.NC_USHORT]: module.nc_get_att_ushort,
|
|
114
|
+
[NC_CONSTANTS.NC_LONGLONG]: module.nc_get_att_longlong,
|
|
115
|
+
[NC_CONSTANTS.NC_UINT64]: module.nc_get_att_ulonglong,
|
|
116
|
+
[NC_CONSTANTS.NC_STRING]: module.nc_get_att_string
|
|
117
|
+
};
|
|
118
|
+
const getter = getterMap[attType];
|
|
119
|
+
if (!getter)
|
|
120
|
+
throw new Error(`Unsupported attribute type ${attType}`);
|
|
121
|
+
const attValue = getter(ncid, varid, attname, attInfo.len);
|
|
89
122
|
return attValue.data;
|
|
90
123
|
}
|
|
91
|
-
export function getGlobalAttributes(module, ncid) {
|
|
124
|
+
export function getGlobalAttributes(module, ncid, groupPath) {
|
|
125
|
+
const workingNcid = groupPath ? getGroupNCID(module, ncid, groupPath) : ncid;
|
|
92
126
|
const attributes = {};
|
|
93
|
-
const nattsResult = module.nc_inq_natts(
|
|
127
|
+
const nattsResult = module.nc_inq_natts(workingNcid);
|
|
94
128
|
if (nattsResult.result !== NC_CONSTANTS.NC_NOERR) {
|
|
95
129
|
throw new Error(`Failed to get number of global attributes (error: ${nattsResult.result})`);
|
|
96
130
|
}
|
|
97
131
|
const nAtts = nattsResult.natts;
|
|
98
132
|
const attNames = [];
|
|
99
133
|
for (let i = 0; i < nAtts; i++) {
|
|
100
|
-
const name = getAttributeName(module,
|
|
134
|
+
const name = getAttributeName(module, workingNcid, NC_CONSTANTS.NC_GLOBAL, i);
|
|
101
135
|
attNames.push(name);
|
|
102
136
|
}
|
|
103
137
|
if (attNames.length === 0)
|
|
@@ -105,7 +139,7 @@ export function getGlobalAttributes(module, ncid) {
|
|
|
105
139
|
for (const attname of attNames) {
|
|
106
140
|
if (!attname)
|
|
107
141
|
continue;
|
|
108
|
-
attributes[attname] = getAttributeValues(module,
|
|
142
|
+
attributes[attname] = getAttributeValues(module, workingNcid, NC_CONSTANTS.NC_GLOBAL, attname);
|
|
109
143
|
}
|
|
110
144
|
return attributes;
|
|
111
145
|
}
|
|
@@ -116,11 +150,12 @@ export function getAttributeName(module, ncid, varid, attId) {
|
|
|
116
150
|
}
|
|
117
151
|
return result.name;
|
|
118
152
|
}
|
|
119
|
-
export function getFullMetadata(module, ncid) {
|
|
120
|
-
const
|
|
153
|
+
export function getFullMetadata(module, ncid, groupPath) {
|
|
154
|
+
const workingNcid = groupPath ? getGroupNCID(module, ncid, groupPath) : ncid;
|
|
155
|
+
const varIds = getVarIDs(module, workingNcid);
|
|
121
156
|
const metas = [];
|
|
122
157
|
for (const varid of varIds) {
|
|
123
|
-
const varMeta = getVariableInfo(module,
|
|
158
|
+
const varMeta = getVariableInfo(module, workingNcid, varid);
|
|
124
159
|
const { attributes, ...varDeets } = varMeta;
|
|
125
160
|
metas.push({ ...varDeets, ...attributes });
|
|
126
161
|
}
|
|
@@ -131,39 +166,44 @@ export function getVarIDs(module, ncid) {
|
|
|
131
166
|
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
132
167
|
throw new Error(`Failed to get variable IDs (error: ${result.result})`);
|
|
133
168
|
}
|
|
134
|
-
return result.varids
|
|
169
|
+
return result.varids ?? [];
|
|
135
170
|
}
|
|
136
|
-
export function getVariableInfo(module, ncid, variable) {
|
|
171
|
+
export function getVariableInfo(module, ncid, variable, groupPath) {
|
|
172
|
+
const workingNcid = groupPath ? getGroupNCID(module, ncid, groupPath) : ncid;
|
|
137
173
|
const info = {};
|
|
138
174
|
const isId = typeof variable === "number";
|
|
139
175
|
let varid = variable;
|
|
140
176
|
if (!isId) {
|
|
141
|
-
const result = module.nc_inq_varid(
|
|
177
|
+
const result = module.nc_inq_varid(workingNcid, variable);
|
|
142
178
|
varid = result.varid;
|
|
143
179
|
}
|
|
144
|
-
const result = module.nc_inq_var(
|
|
180
|
+
const result = module.nc_inq_var(workingNcid, varid);
|
|
145
181
|
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
146
182
|
throw new Error(`Failed to get variable info (error: ${result.result})`);
|
|
147
183
|
}
|
|
148
184
|
const typeMultiplier = DATA_TYPE_SIZE[result.type];
|
|
149
|
-
//Dim Info
|
|
185
|
+
// Dim Info - FIXED to preserve order
|
|
150
186
|
const dimids = result.dimids;
|
|
151
187
|
const dims = [];
|
|
152
188
|
const shape = [];
|
|
189
|
+
const dimensions = []; // Array to store dimension names in order
|
|
153
190
|
let size = 1;
|
|
154
191
|
if (dimids) {
|
|
155
|
-
|
|
156
|
-
|
|
192
|
+
// Iterate through dimids in order - this matches the shape order
|
|
193
|
+
for (let i = 0; i < dimids.length; i++) {
|
|
194
|
+
const dimid = dimids[i];
|
|
195
|
+
const dim = getDim(module, workingNcid, dimid);
|
|
157
196
|
size *= dim.len;
|
|
158
197
|
dims.push(dim);
|
|
159
198
|
shape.push(dim.len);
|
|
199
|
+
dimensions.push(dim.name); // Add dimension name in the same order
|
|
160
200
|
}
|
|
161
201
|
}
|
|
162
|
-
//Attribute Info
|
|
202
|
+
// Attribute Info
|
|
163
203
|
const attNames = [];
|
|
164
204
|
if (result.natts) {
|
|
165
205
|
for (let i = 0; i < result.natts; i++) {
|
|
166
|
-
const attname = getAttributeName(module,
|
|
206
|
+
const attname = getAttributeName(module, workingNcid, varid, i);
|
|
167
207
|
attNames.push(attname);
|
|
168
208
|
}
|
|
169
209
|
}
|
|
@@ -172,12 +212,12 @@ export function getVariableInfo(module, ncid, variable) {
|
|
|
172
212
|
for (const attname of attNames) {
|
|
173
213
|
if (!attname)
|
|
174
214
|
continue;
|
|
175
|
-
atts[attname] = getAttributeValues(module,
|
|
215
|
+
atts[attname] = getAttributeValues(module, workingNcid, varid, attname);
|
|
176
216
|
}
|
|
177
217
|
}
|
|
178
|
-
//Chunking Info
|
|
218
|
+
// Chunking Info
|
|
179
219
|
let chunks;
|
|
180
|
-
const chunkResult = module.nc_inq_var_chunking(
|
|
220
|
+
const chunkResult = module.nc_inq_var_chunking(workingNcid, varid);
|
|
181
221
|
const isChunked = chunkResult.chunking === NC_CONSTANTS.NC_CHUNKED;
|
|
182
222
|
if (isChunked) {
|
|
183
223
|
chunks = chunkResult.chunkSizes;
|
|
@@ -186,12 +226,13 @@ export function getVariableInfo(module, ncid, variable) {
|
|
|
186
226
|
chunks = shape;
|
|
187
227
|
}
|
|
188
228
|
const chunkElements = chunks.reduce((a, b) => a * b, 1);
|
|
189
|
-
//Output
|
|
229
|
+
// Output
|
|
190
230
|
info["name"] = result.name;
|
|
191
231
|
info["dtype"] = CONSTANT_DTYPE_MAP[result.type];
|
|
192
232
|
info['nctype'] = result.type;
|
|
193
233
|
info["shape"] = shape;
|
|
194
234
|
info['dims'] = dims;
|
|
235
|
+
info["dimensions"] = dimensions; // Add ordered dimension names array
|
|
195
236
|
info["size"] = size;
|
|
196
237
|
info["totalSize"] = size * typeMultiplier;
|
|
197
238
|
info["attributes"] = atts;
|
|
@@ -200,64 +241,360 @@ export function getVariableInfo(module, ncid, variable) {
|
|
|
200
241
|
info["chunkSize"] = chunkElements * typeMultiplier;
|
|
201
242
|
return info;
|
|
202
243
|
}
|
|
203
|
-
export function getVariableArray(module, ncid, variable) {
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
244
|
+
export function getVariableArray(module, ncid, variable, groupPath) {
|
|
245
|
+
const workingNcid = groupPath ? getGroupNCID(module, ncid, groupPath) : ncid;
|
|
246
|
+
// Resolve variable id
|
|
247
|
+
let varid;
|
|
248
|
+
if (typeof variable === "number") {
|
|
249
|
+
varid = variable;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const result = module.nc_inq_varid(workingNcid, variable);
|
|
253
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
254
|
+
throw new Error(`Failed to get variable id for '${variable}' (error: ${result.result})`);
|
|
255
|
+
}
|
|
208
256
|
varid = result.varid;
|
|
209
257
|
}
|
|
210
|
-
const info = getVariableInfo(module,
|
|
211
|
-
const arraySize = info.size;
|
|
258
|
+
const info = getVariableInfo(module, workingNcid, varid);
|
|
212
259
|
const arrayType = info.nctype;
|
|
213
|
-
|
|
214
|
-
|
|
260
|
+
const arraySize = info.size;
|
|
261
|
+
if (arrayType === undefined || arrayType === null) {
|
|
262
|
+
throw new Error("Failed to determine variable type");
|
|
263
|
+
}
|
|
264
|
+
if (arraySize === undefined || arraySize === null) {
|
|
265
|
+
throw new Error("Failed to determine variable size");
|
|
266
|
+
}
|
|
267
|
+
// Arrow wrappers = safe binding
|
|
268
|
+
const readers = {
|
|
269
|
+
[NC_CONSTANTS.NC_CHAR]: (...args) => module.nc_get_var_text(...args),
|
|
270
|
+
[NC_CONSTANTS.NC_SHORT]: (...args) => module.nc_get_var_short(...args),
|
|
271
|
+
[NC_CONSTANTS.NC_INT]: (...args) => module.nc_get_var_int(...args),
|
|
272
|
+
[NC_CONSTANTS.NC_FLOAT]: (...args) => module.nc_get_var_float(...args),
|
|
273
|
+
[NC_CONSTANTS.NC_DOUBLE]: (...args) => module.nc_get_var_double(...args),
|
|
274
|
+
[NC_CONSTANTS.NC_LONGLONG]: (...args) => module.nc_get_var_longlong(...args),
|
|
275
|
+
[NC_CONSTANTS.NC_BYTE]: (...args) => module.nc_get_var_schar(...args),
|
|
276
|
+
[NC_CONSTANTS.NC_UBYTE]: (...args) => module.nc_get_var_uchar(...args),
|
|
277
|
+
[NC_CONSTANTS.NC_USHORT]: (...args) => module.nc_get_var_ushort(...args),
|
|
278
|
+
[NC_CONSTANTS.NC_UINT]: (...args) => module.nc_get_var_uint(...args),
|
|
279
|
+
[NC_CONSTANTS.NC_INT64]: (...args) => module.nc_get_var_longlong(...args),
|
|
280
|
+
[NC_CONSTANTS.NC_UINT64]: (...args) => module.nc_get_var_ulonglong(...args),
|
|
281
|
+
[NC_CONSTANTS.NC_STRING]: (...args) => module.nc_get_var_string(...args),
|
|
282
|
+
};
|
|
283
|
+
const reader = readers[arrayType];
|
|
215
284
|
let arrayData;
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
else
|
|
221
|
-
arrayData =
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (!arrayData.data)
|
|
231
|
-
throw new Error("Failed to read array data");
|
|
285
|
+
if (!reader) {
|
|
286
|
+
console.warn(`Unknown NetCDF type ${arrayType}, falling back to double`);
|
|
287
|
+
arrayData = module.nc_get_var_double(workingNcid, varid, arraySize);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
arrayData = reader(workingNcid, varid, arraySize);
|
|
291
|
+
}
|
|
292
|
+
if (arrayData.result !== NC_CONSTANTS.NC_NOERR) {
|
|
293
|
+
throw new Error(`Failed to read array data (error: ${arrayData.result})`);
|
|
294
|
+
}
|
|
295
|
+
if (!arrayData.data) {
|
|
296
|
+
console.error("nc_get_var result:", arrayData);
|
|
297
|
+
throw new Error("nc_get_var returned no data");
|
|
298
|
+
}
|
|
232
299
|
return arrayData.data;
|
|
233
300
|
}
|
|
234
|
-
export function getSlicedVariableArray(module, ncid, variable, start, count) {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
301
|
+
export function getSlicedVariableArray(module, ncid, variable, start, count, groupPath) {
|
|
302
|
+
const workingNcid = groupPath ? getGroupNCID(module, ncid, groupPath) : ncid;
|
|
303
|
+
// Resolve variable id
|
|
304
|
+
let varid;
|
|
305
|
+
if (typeof variable === "number") {
|
|
306
|
+
varid = variable;
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
const result = module.nc_inq_varid(workingNcid, variable);
|
|
310
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
311
|
+
throw new Error(`Failed to get variable id for '${variable}' (error: ${result.result})`);
|
|
312
|
+
}
|
|
239
313
|
varid = result.varid;
|
|
240
314
|
}
|
|
241
|
-
const info = getVariableInfo(module,
|
|
315
|
+
const info = getVariableInfo(module, workingNcid, varid);
|
|
242
316
|
const arrayType = info.nctype;
|
|
243
|
-
if (
|
|
244
|
-
throw new Error("Failed to
|
|
317
|
+
if (arrayType === undefined || arrayType === null) {
|
|
318
|
+
throw new Error("Failed to determine variable type");
|
|
319
|
+
}
|
|
320
|
+
// Arrow wrappers keep module binding intact
|
|
321
|
+
const readers = {
|
|
322
|
+
[NC_CONSTANTS.NC_SHORT]: (...args) => module.nc_get_vara_short(...args),
|
|
323
|
+
[NC_CONSTANTS.NC_INT]: (...args) => module.nc_get_vara_int(...args),
|
|
324
|
+
[NC_CONSTANTS.NC_FLOAT]: (...args) => module.nc_get_vara_float(...args),
|
|
325
|
+
[NC_CONSTANTS.NC_DOUBLE]: (...args) => module.nc_get_vara_double(...args),
|
|
326
|
+
[NC_CONSTANTS.NC_BYTE]: (...args) => module.nc_get_vara_schar(...args),
|
|
327
|
+
[NC_CONSTANTS.NC_UBYTE]: (...args) => module.nc_get_vara_uchar(...args),
|
|
328
|
+
[NC_CONSTANTS.NC_USHORT]: (...args) => module.nc_get_vara_ushort(...args),
|
|
329
|
+
[NC_CONSTANTS.NC_UINT]: (...args) => module.nc_get_vara_uint(...args),
|
|
330
|
+
[NC_CONSTANTS.NC_INT64]: (...args) => module.nc_get_vara_longlong(...args),
|
|
331
|
+
[NC_CONSTANTS.NC_UINT64]: (...args) => module.nc_get_vara_ulonglong(...args),
|
|
332
|
+
[NC_CONSTANTS.NC_STRING]: (...args) => module.nc_get_vara_string(...args),
|
|
333
|
+
};
|
|
334
|
+
const reader = readers[arrayType];
|
|
245
335
|
let arrayData;
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
else
|
|
251
|
-
arrayData =
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
336
|
+
if (!reader) {
|
|
337
|
+
console.warn(`Unknown NetCDF type ${arrayType}, falling back to double`);
|
|
338
|
+
arrayData = module.nc_get_vara_double(workingNcid, varid, start, count);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
arrayData = reader(workingNcid, varid, start, count);
|
|
342
|
+
}
|
|
343
|
+
if (arrayData.result !== NC_CONSTANTS.NC_NOERR) {
|
|
344
|
+
throw new Error(`Failed to read sliced array data (error: ${arrayData.result})`);
|
|
345
|
+
}
|
|
256
346
|
if (!arrayData.data) {
|
|
257
|
-
console.
|
|
258
|
-
throw new Error("Failed to read array data");
|
|
347
|
+
console.error("nc_get_vara result:", arrayData);
|
|
348
|
+
throw new Error("Failed to read array data - no data returned");
|
|
259
349
|
}
|
|
260
350
|
return arrayData.data;
|
|
261
351
|
}
|
|
262
|
-
|
|
352
|
+
//---- Group Functions ----//
|
|
353
|
+
/**
|
|
354
|
+
* Get group ncid by path (supports nested groups)
|
|
355
|
+
* Uses nc_inq_grp_full_ncid for absolute paths and manual traversal for relative paths
|
|
356
|
+
* @param module - NetCDF4 module
|
|
357
|
+
* @param ncid - Current ncid (can be root or any group)
|
|
358
|
+
* @param groupPath - Can be absolute ("/group1/subgroup") or relative ("subgroup" or "group1/subgroup")
|
|
359
|
+
* @returns The ncid of the requested group
|
|
360
|
+
*/
|
|
361
|
+
export function getGroupNCID(module, ncid, groupPath) {
|
|
362
|
+
// Optimization: if path is root, return the ncid
|
|
363
|
+
if (groupPath === '/' || groupPath === '') {
|
|
364
|
+
return ncid;
|
|
365
|
+
}
|
|
366
|
+
// Try using nc_inq_grp_full_ncid for absolute paths (more efficient)
|
|
367
|
+
if (groupPath.startsWith('/')) {
|
|
368
|
+
const result = module.nc_inq_grp_full_ncid(ncid, groupPath);
|
|
369
|
+
if (result.result === NC_CONSTANTS.NC_NOERR) {
|
|
370
|
+
return result.grp_ncid;
|
|
371
|
+
}
|
|
372
|
+
// Get current path for better error message
|
|
373
|
+
const currentPath = getGroupPath(module, ncid);
|
|
374
|
+
throw new Error(`Failed to find group '${groupPath}' from '${currentPath}' (error: ${result.result})`);
|
|
375
|
+
}
|
|
376
|
+
// Manual traversal for relative paths
|
|
377
|
+
const parts = groupPath.split('/').filter(p => p.length > 0);
|
|
378
|
+
let currentNcid = ncid;
|
|
379
|
+
for (const part of parts) {
|
|
380
|
+
const result = module.nc_inq_grp_ncid(currentNcid, part);
|
|
381
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
382
|
+
const currentPath = getGroupPath(module, currentNcid);
|
|
383
|
+
throw new Error(`Failed to get group ncid for '${part}' in path '${groupPath}' from '${currentPath}' (error: ${result.result})`);
|
|
384
|
+
}
|
|
385
|
+
currentNcid = result.grp_ncid;
|
|
386
|
+
}
|
|
387
|
+
return currentNcid;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Alias for getGroupNCID (matches nc_inq_ncid API)
|
|
391
|
+
* @param module - NetCDF4 module
|
|
392
|
+
* @param ncid - Current ncid
|
|
393
|
+
* @param groupName - Group name or path
|
|
394
|
+
* @returns The ncid of the requested group
|
|
395
|
+
*/
|
|
396
|
+
export const getNCID = getGroupNCID;
|
|
397
|
+
/**
|
|
398
|
+
* Get immediate child groups (non-recursive)
|
|
399
|
+
* @param module - NetCDF4 module
|
|
400
|
+
* @param ncid - Group ncid to query
|
|
401
|
+
* @returns Object mapping group names to their ncids
|
|
402
|
+
*/
|
|
403
|
+
export function getGroups(module, ncid) {
|
|
404
|
+
const result = module.nc_inq_grps(ncid);
|
|
405
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
406
|
+
throw new Error(`Failed to get groups (error: ${result.result})`);
|
|
407
|
+
}
|
|
408
|
+
const groups = {};
|
|
409
|
+
const grpids = result.grpids || [];
|
|
410
|
+
for (const grpid of grpids) {
|
|
411
|
+
const nameResult = module.nc_inq_grpname(grpid);
|
|
412
|
+
if (nameResult.result === NC_CONSTANTS.NC_NOERR && nameResult.name) {
|
|
413
|
+
groups[nameResult.name] = grpid;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return groups;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Get all groups recursively (returns nested structure)
|
|
420
|
+
* @param module - NetCDF4 module
|
|
421
|
+
* @param ncid - Group ncid to start from (usually root)
|
|
422
|
+
* @returns Nested object structure with group names, ncids, and subgroups
|
|
423
|
+
*/
|
|
424
|
+
export function getGroupsRecursive(module, ncid) {
|
|
425
|
+
const result = module.nc_inq_grps(ncid);
|
|
426
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
427
|
+
throw new Error(`Failed to get groups (error: ${result.result})`);
|
|
428
|
+
}
|
|
429
|
+
const groups = {};
|
|
430
|
+
const grpids = result.grpids || [];
|
|
431
|
+
for (const grpid of grpids) {
|
|
432
|
+
const nameResult = module.nc_inq_grpname(grpid);
|
|
433
|
+
if (nameResult.result === NC_CONSTANTS.NC_NOERR && nameResult.name) {
|
|
434
|
+
groups[nameResult.name] = {
|
|
435
|
+
ncid: grpid,
|
|
436
|
+
subgroups: getGroupsRecursive(module, grpid) // Recursive call
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return groups;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Get the name of a group
|
|
444
|
+
* @param module - NetCDF4 module
|
|
445
|
+
* @param ncid - Group ncid
|
|
446
|
+
* @returns Group name
|
|
447
|
+
*/
|
|
448
|
+
export function getGroupName(module, ncid) {
|
|
449
|
+
const result = module.nc_inq_grpname(ncid);
|
|
450
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
451
|
+
throw new Error(`Failed to get group name (error: ${result.result})`);
|
|
452
|
+
}
|
|
453
|
+
return result.name || '';
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Get the full absolute path of a group
|
|
457
|
+
* Uses nc_inq_grpname_full for efficient path retrieval
|
|
458
|
+
* @param module - NetCDF4 module
|
|
459
|
+
* @param ncid - Group ncid
|
|
460
|
+
* @returns Full path like "/group1/subgroup"
|
|
461
|
+
*/
|
|
462
|
+
export function getGroupPath(module, ncid) {
|
|
463
|
+
// Use nc_inq_grpname_full to get the complete path efficiently
|
|
464
|
+
const result = module.nc_inq_grpname_full(ncid);
|
|
465
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
466
|
+
throw new Error(`Failed to get group full name (error: ${result.result})`);
|
|
467
|
+
}
|
|
468
|
+
return result.full_name || '/';
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Get the length of a group's full path name
|
|
472
|
+
* @param module - NetCDF4 module
|
|
473
|
+
* @param ncid - Group ncid
|
|
474
|
+
* @returns Length of the full group path name
|
|
475
|
+
*/
|
|
476
|
+
export function getGroupPathLength(module, ncid) {
|
|
477
|
+
const result = module.nc_inq_grpname_len(ncid);
|
|
478
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
479
|
+
throw new Error(`Failed to get group name length (error: ${result.result})`);
|
|
480
|
+
}
|
|
481
|
+
return result.lenp || 0;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Get the parent group ncid
|
|
485
|
+
* @param module - NetCDF4 module
|
|
486
|
+
* @param ncid - Group ncid
|
|
487
|
+
* @returns Parent group ncid, or null if this is the root group
|
|
488
|
+
*/
|
|
489
|
+
export function getGroupParent(module, ncid) {
|
|
490
|
+
const result = module.nc_inq_grp_parent(ncid);
|
|
491
|
+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
492
|
+
return null; // No parent (at root)
|
|
493
|
+
}
|
|
494
|
+
return result.parent_ncid;
|
|
495
|
+
}
|
|
496
|
+
function findDimInHierarchy(module, startNcid, name) {
|
|
497
|
+
let current = startNcid;
|
|
498
|
+
while (current !== null) {
|
|
499
|
+
const result = module.nc_inq_dimid(current, name);
|
|
500
|
+
if (result.result === NC_CONSTANTS.NC_NOERR) {
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
current = getGroupParent(module, current);
|
|
504
|
+
}
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Get complete hierarchy: groups + their variables, dimensions, and attributes recursively
|
|
509
|
+
* This is the unified method that should be used for exploring the file structure
|
|
510
|
+
* @param module - NetCDF4 module
|
|
511
|
+
* @param ncid - Group ncid to start from
|
|
512
|
+
* @param groupPath - Optional path to a specific starting group
|
|
513
|
+
* @param includeParentDims - Whether to include parent dimensions in each group (default: false)
|
|
514
|
+
* @returns Complete hierarchical structure
|
|
515
|
+
*/
|
|
516
|
+
export function getCompleteHierarchy(module, ncid, groupPath, includeParentDims = false) {
|
|
517
|
+
const workingNcid = groupPath ? getGroupNCID(module, ncid, groupPath) : ncid;
|
|
518
|
+
// Get variables at this level (now includes ncid)
|
|
519
|
+
const variables = getGroupVariables(module, workingNcid);
|
|
520
|
+
// Get dimensions at this level
|
|
521
|
+
const dimensions = getDims(module, workingNcid);
|
|
522
|
+
// If includeParentDims is true, also get parent dimensions
|
|
523
|
+
if (includeParentDims) {
|
|
524
|
+
const result = module.nc_inq_dimids(workingNcid, 1);
|
|
525
|
+
if (result.result === NC_CONSTANTS.NC_NOERR && result.dimids) {
|
|
526
|
+
const parentDims = {};
|
|
527
|
+
for (const dimid of result.dimids) {
|
|
528
|
+
const dim = getDim(module, workingNcid, dimid);
|
|
529
|
+
// Only add if not already in dimensions (avoid duplicates)
|
|
530
|
+
if (!dimensions[dim.name]) {
|
|
531
|
+
parentDims[dim.name] = {
|
|
532
|
+
size: dim.len,
|
|
533
|
+
units: dim.units ?? null,
|
|
534
|
+
id: dim.id,
|
|
535
|
+
inherited: true
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// Merge parent dimensions
|
|
540
|
+
Object.assign(dimensions, parentDims);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// Get attributes at this level
|
|
544
|
+
const attributes = getGlobalAttributes(module, workingNcid);
|
|
545
|
+
// Get the full path for this group
|
|
546
|
+
const fullPath = getGroupPath(module, workingNcid);
|
|
547
|
+
// Get subgroups and recurse
|
|
548
|
+
const groupsResult = module.nc_inq_grps(workingNcid);
|
|
549
|
+
const subgroups = {};
|
|
550
|
+
if (groupsResult.result === NC_CONSTANTS.NC_NOERR && groupsResult.grpids) {
|
|
551
|
+
for (const grpid of groupsResult.grpids) {
|
|
552
|
+
const nameResult = module.nc_inq_grpname(grpid);
|
|
553
|
+
if (nameResult.result === NC_CONSTANTS.NC_NOERR && nameResult.name) {
|
|
554
|
+
// Recursively get the complete hierarchy for this subgroup
|
|
555
|
+
subgroups[nameResult.name] = getCompleteHierarchy(module, grpid, undefined, includeParentDims);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return {
|
|
560
|
+
ncid: workingNcid, // Include the ncid at this level
|
|
561
|
+
path: fullPath, // Include the full path
|
|
562
|
+
variables,
|
|
563
|
+
dimensions,
|
|
564
|
+
attributes,
|
|
565
|
+
groups: subgroups
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Get all variables recursively from all groups
|
|
570
|
+
* Returns a flat structure with full paths as keys
|
|
571
|
+
* @param module - NetCDF4 module
|
|
572
|
+
* @param ncid - Group ncid to start from
|
|
573
|
+
* @param currentPath - Current path (used internally for recursion)
|
|
574
|
+
* @returns Flat dictionary with full variable paths
|
|
575
|
+
*/
|
|
576
|
+
export function getVariables(module, ncid, currentPath) {
|
|
577
|
+
const allVars = {};
|
|
578
|
+
// Get the actual path if not provided
|
|
579
|
+
const path = currentPath || getGroupPath(module, ncid);
|
|
580
|
+
// Get variables at current level
|
|
581
|
+
const vars = getGroupVariables(module, ncid);
|
|
582
|
+
for (const [name, varData] of Object.entries(vars)) {
|
|
583
|
+
const fullPath = path === '/' ? `/${name}` : `${path}/${name}`;
|
|
584
|
+
allVars[fullPath] = { ...varData, path, ncid };
|
|
585
|
+
}
|
|
586
|
+
// Recurse into subgroups
|
|
587
|
+
const groupsResult = module.nc_inq_grps(ncid);
|
|
588
|
+
if (groupsResult.result === NC_CONSTANTS.NC_NOERR && groupsResult.grpids) {
|
|
589
|
+
for (const grpid of groupsResult.grpids) {
|
|
590
|
+
const nameResult = module.nc_inq_grpname(grpid);
|
|
591
|
+
if (nameResult.result === NC_CONSTANTS.NC_NOERR && nameResult.name) {
|
|
592
|
+
const newPath = path === '/' ? `/${nameResult.name}` : `${path}/${nameResult.name}`;
|
|
593
|
+
const subVars = getVariables(module, grpid, newPath);
|
|
594
|
+
Object.assign(allVars, subVars);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return allVars;
|
|
599
|
+
}
|
|
263
600
|
//# sourceMappingURL=netcdf-getters.js.map
|