@earthyscience/netcdf4-wasm 0.1.0 → 0.1.1
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/netcdf-getters.d.ts +16 -0
- package/dist/netcdf-getters.d.ts.map +1 -0
- package/dist/netcdf-getters.js +263 -0
- package/dist/netcdf-getters.js.map +1 -0
- package/dist/netcdf-worker.d.ts +2 -0
- package/dist/netcdf-worker.d.ts.map +1 -0
- package/dist/netcdf-worker.js +149 -0
- package/dist/netcdf-worker.js.map +1 -0
- package/dist/netcdf4-wasm.wasm +0 -0
- package/dist/netcdf4.d.ts +21 -14
- package/dist/netcdf4.d.ts.map +1 -1
- package/dist/netcdf4.js +228 -295
- package/dist/netcdf4.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/wasm-module.d.ts +2 -2
- package/dist/wasm-module.d.ts.map +1 -1
- package/dist/wasm-module.js.map +1 -1
- package/package.json +9 -11
package/dist/netcdf4.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Main NetCDF4 class implementation
|
|
2
2
|
import { Group } from './group.js';
|
|
3
3
|
import { WasmModuleLoader } from './wasm-module.js';
|
|
4
|
-
import { NC_CONSTANTS
|
|
4
|
+
import { NC_CONSTANTS } from './constants.js';
|
|
5
|
+
import * as NCGet from './netcdf-getters.js';
|
|
5
6
|
export class NetCDF4 extends Group {
|
|
6
7
|
filename;
|
|
7
8
|
mode;
|
|
@@ -11,6 +12,9 @@ export class NetCDF4 extends Group {
|
|
|
11
12
|
ncid = -1;
|
|
12
13
|
_isOpen = false;
|
|
13
14
|
memorySource;
|
|
15
|
+
workerSource;
|
|
16
|
+
worker;
|
|
17
|
+
workerReady;
|
|
14
18
|
constructor(filename, mode = 'r', options = {}) {
|
|
15
19
|
super(null, '', -1);
|
|
16
20
|
this.filename = filename;
|
|
@@ -20,30 +24,32 @@ export class NetCDF4 extends Group {
|
|
|
20
24
|
this.netcdf = this;
|
|
21
25
|
}
|
|
22
26
|
async initialize() {
|
|
23
|
-
if (this.initialized)
|
|
27
|
+
if (this.initialized)
|
|
24
28
|
return;
|
|
25
|
-
}
|
|
26
29
|
try {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
if (this.workerSource) {
|
|
31
|
+
// This now handles the WORKERFS mounting
|
|
32
|
+
await this.setupWorker();
|
|
33
|
+
this.initialized = true;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this.module = await WasmModuleLoader.loadModule(this.options);
|
|
37
|
+
if (this.memorySource) {
|
|
38
|
+
await this.mountMemoryData();
|
|
39
|
+
}
|
|
32
40
|
}
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
this.initialized = true;
|
|
42
|
+
// Automatically open the file if a filename was provided
|
|
43
|
+
if (this.filename && !this.workerSource) {
|
|
35
44
|
await this.open();
|
|
36
45
|
}
|
|
37
46
|
}
|
|
38
47
|
catch (error) {
|
|
39
|
-
// Check if this is a test environment and we should use mock mode
|
|
40
48
|
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {
|
|
41
|
-
// Mock the module for testing
|
|
42
49
|
this.module = this.createMockModule();
|
|
43
50
|
this.initialized = true;
|
|
44
|
-
if (this.filename
|
|
51
|
+
if (this.filename)
|
|
45
52
|
await this.open();
|
|
46
|
-
}
|
|
47
53
|
}
|
|
48
54
|
else {
|
|
49
55
|
throw error;
|
|
@@ -84,9 +90,27 @@ export class NetCDF4 extends Group {
|
|
|
84
90
|
await dataset.initialize();
|
|
85
91
|
return dataset;
|
|
86
92
|
}
|
|
93
|
+
// New factory for Blob/File (local, no full preload)
|
|
94
|
+
static async fromBlobLazy(blob, options = {}) {
|
|
95
|
+
// IMPORTANT: Keep this path consistent with the mount logic in the worker
|
|
96
|
+
const mountPoint = '/working';
|
|
97
|
+
const baseName = `netcdf_lazy_${Date.now()}.nc`;
|
|
98
|
+
const fullPath = `${mountPoint}/${baseName}`;
|
|
99
|
+
console.log('fromBlobLazy: Creating dataset with path:', fullPath);
|
|
100
|
+
const dataset = new NetCDF4(fullPath, 'r', options);
|
|
101
|
+
// Store the raw blob. The worker will mount it via WORKERFS
|
|
102
|
+
dataset.workerSource = { blob, filename: fullPath };
|
|
103
|
+
await dataset.initialize();
|
|
104
|
+
console.log('fromBlobLazy: Initialization complete, calling open()');
|
|
105
|
+
// After worker is set up, open the file
|
|
106
|
+
await dataset.open();
|
|
107
|
+
console.log('fromBlobLazy: Open complete, ncid:', dataset.ncid);
|
|
108
|
+
return dataset;
|
|
109
|
+
}
|
|
87
110
|
async open() {
|
|
88
111
|
if (this._isOpen)
|
|
89
112
|
return;
|
|
113
|
+
console.log('open() called, filename:', this.filename, 'worker:', !!this.worker);
|
|
90
114
|
if (!this.filename || this.filename.trim() === '') {
|
|
91
115
|
throw new Error('No filename specified');
|
|
92
116
|
}
|
|
@@ -95,6 +119,19 @@ export class NetCDF4 extends Group {
|
|
|
95
119
|
if (!validModes.includes(this.mode)) {
|
|
96
120
|
throw new Error(`Unsupported mode: ${this.mode}`);
|
|
97
121
|
}
|
|
122
|
+
// Worker path
|
|
123
|
+
if (this.worker) {
|
|
124
|
+
console.log('open(): Using worker path, waiting for workerReady');
|
|
125
|
+
// Wait for worker to be ready first
|
|
126
|
+
await this.workerReady;
|
|
127
|
+
console.log('open(): Worker ready, calling nc_open with path:', this.filename);
|
|
128
|
+
const modeValue = this.mode === 'r' ? NC_CONSTANTS.NC_NOWRITE : NC_CONSTANTS.NC_WRITE;
|
|
129
|
+
this.ncid = await this.callWorker('open', { path: this.filename, modeValue });
|
|
130
|
+
console.log('open(): Received ncid from worker:', this.ncid);
|
|
131
|
+
this.groupId = this.ncid;
|
|
132
|
+
this._isOpen = true;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
98
135
|
if (this.mode === 'w' || this.mode === 'w-') {
|
|
99
136
|
// Create new file
|
|
100
137
|
let createMode = NC_CONSTANTS.NC_CLOBBER;
|
|
@@ -186,305 +223,171 @@ export class NetCDF4 extends Group {
|
|
|
186
223
|
return result.ncid;
|
|
187
224
|
}
|
|
188
225
|
async closeFile(ncid) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (result !== NC_CONSTANTS.NC_NOERR) {
|
|
192
|
-
throw new Error(`Failed to close NetCDF file with ID: ${ncid} (error: ${result})`);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
getGlobalAttributes() {
|
|
196
|
-
const attributes = {};
|
|
197
|
-
const module = this.module;
|
|
198
|
-
if (!module)
|
|
199
|
-
throw new Error("Failed to load module. Ensure module is initialized before calling methods");
|
|
200
|
-
const nattsResult = module.nc_inq_natts(this.ncid);
|
|
201
|
-
if (nattsResult.result !== NC_CONSTANTS.NC_NOERR) {
|
|
202
|
-
throw new Error(`Failed to get number of global attributes (error: ${nattsResult.result})`);
|
|
203
|
-
}
|
|
204
|
-
const nAtts = nattsResult.natts;
|
|
205
|
-
const attNames = [];
|
|
206
|
-
for (let i = 0; i < nAtts; i++) {
|
|
207
|
-
const name = this.getAttributeName(NC_CONSTANTS.NC_GLOBAL, i);
|
|
208
|
-
attNames.push(name);
|
|
209
|
-
}
|
|
210
|
-
if (attNames.length === 0)
|
|
211
|
-
return attributes;
|
|
212
|
-
for (const attname of attNames) {
|
|
213
|
-
if (!attname)
|
|
214
|
-
continue;
|
|
215
|
-
attributes[attname] = this.getAttributeValues(NC_CONSTANTS.NC_GLOBAL, attname);
|
|
216
|
-
}
|
|
217
|
-
return attributes;
|
|
218
|
-
}
|
|
219
|
-
getFullMetadata() {
|
|
220
|
-
const varIds = this.getVarIDs();
|
|
221
|
-
const metas = [];
|
|
222
|
-
for (const varid of varIds) {
|
|
223
|
-
const varMeta = this.getVariableInfo(varid);
|
|
224
|
-
const { attributes, ...varDeets } = varMeta;
|
|
225
|
-
metas.push({ ...varDeets, ...attributes });
|
|
226
|
-
}
|
|
227
|
-
return metas;
|
|
228
|
-
}
|
|
229
|
-
getAttributeValues(varid, attname) {
|
|
230
|
-
const module = this.module;
|
|
231
|
-
if (!module)
|
|
232
|
-
throw new Error("Failed to load module. Ensure module is initialized before calling methods");
|
|
233
|
-
const attInfo = module.nc_inq_att(this.ncid, varid, attname);
|
|
234
|
-
if (attInfo.result !== NC_CONSTANTS.NC_NOERR) {
|
|
235
|
-
console.warn(`Failed to get attribute info for ${attname} (error: ${attInfo.result})`);
|
|
236
|
-
return;
|
|
226
|
+
if (this.worker) {
|
|
227
|
+
this.callWorker('close');
|
|
237
228
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
attValue = module.nc_get_att_short(this.ncid, varid, attname, attInfo.len);
|
|
246
|
-
else if (attType === 4)
|
|
247
|
-
attValue = module.nc_get_att_int(this.ncid, varid, attname, attInfo.len);
|
|
248
|
-
else if (attType === 5)
|
|
249
|
-
attValue = module.nc_get_att_float(this.ncid, varid, attname, attInfo.len);
|
|
250
|
-
else if (attType === 6)
|
|
251
|
-
attValue = module.nc_get_att_double(this.ncid, varid, attname, attInfo.len);
|
|
252
|
-
else if (attType === 10)
|
|
253
|
-
attValue = module.nc_get_att_longlong(this.ncid, varid, attname, attInfo.len);
|
|
254
|
-
else
|
|
255
|
-
attValue = module.nc_get_att_double(this.ncid, varid, attname, attInfo.len);
|
|
256
|
-
return attValue.data;
|
|
257
|
-
}
|
|
258
|
-
getDimCount() {
|
|
259
|
-
const module = this.module;
|
|
260
|
-
if (!module)
|
|
261
|
-
throw new Error("Failed to load module. Ensure module is initialized before calling methods");
|
|
262
|
-
const result = module.nc_inq_ndims(this.ncid);
|
|
263
|
-
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
264
|
-
throw new Error(`Failed to get number of dimensions (error: ${result.result})`);
|
|
265
|
-
}
|
|
266
|
-
return result.ndims || 0;
|
|
267
|
-
}
|
|
268
|
-
getVariables() {
|
|
269
|
-
const variables = {};
|
|
270
|
-
const module = this.module;
|
|
271
|
-
if (!module)
|
|
272
|
-
throw new Error("Failed to load module. Ensure module is initialized before calling methods");
|
|
273
|
-
const varCount = this.getVarCount();
|
|
274
|
-
const dimIds = this.getDimIDs();
|
|
275
|
-
for (let varid = 0; varid < varCount; varid++) {
|
|
276
|
-
if (dimIds.includes(varid))
|
|
277
|
-
continue; //Don't include spatial Vars
|
|
278
|
-
const result = module.nc_inq_varname(this.ncid, varid);
|
|
279
|
-
if (result.result !== NC_CONSTANTS.NC_NOERR || !result.name) {
|
|
280
|
-
console.warn(`Failed to get variable name for varid ${varid} (error: ${result.result})`);
|
|
281
|
-
continue;
|
|
229
|
+
else {
|
|
230
|
+
const module = this.module;
|
|
231
|
+
if (!module)
|
|
232
|
+
throw new Error("Failed to load module. Ensure module is initialized before calling methods");
|
|
233
|
+
const result = module.nc_close(ncid);
|
|
234
|
+
if (result !== NC_CONSTANTS.NC_NOERR) {
|
|
235
|
+
throw new Error(`Failed to close NetCDF file with ID: ${ncid} (error: ${result})`);
|
|
282
236
|
}
|
|
283
|
-
|
|
284
|
-
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
requestId = 0;
|
|
240
|
+
async callWorker(type, payload = {}) {
|
|
241
|
+
if (!this.worker)
|
|
242
|
+
throw new Error("Worker not initialized");
|
|
243
|
+
const id = ++this.requestId;
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
245
|
+
const handler = (e) => {
|
|
246
|
+
// Only handle messages that match our request ID
|
|
247
|
+
if (e.data.id !== id)
|
|
248
|
+
return;
|
|
249
|
+
if (e.data.success) {
|
|
250
|
+
resolve(e.data.result);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
reject(new Error(e.data.error || `Worker error in ${type}`));
|
|
254
|
+
}
|
|
255
|
+
this.worker.removeEventListener('message', handler);
|
|
285
256
|
};
|
|
257
|
+
this.worker.addEventListener('message', handler);
|
|
258
|
+
this.worker.postMessage({
|
|
259
|
+
id, // Include the ID in the request
|
|
260
|
+
type,
|
|
261
|
+
ncid: this.ncid,
|
|
262
|
+
...payload
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
async getGlobalAttributes() {
|
|
267
|
+
if (this.worker) {
|
|
268
|
+
return this.callWorker('getGlobalAttributes');
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
272
|
+
return NCGet.getGlobalAttributes(this.module, this.ncid);
|
|
286
273
|
}
|
|
287
|
-
return variables;
|
|
288
274
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
275
|
+
async getFullMetadata() {
|
|
276
|
+
if (this.worker) {
|
|
277
|
+
return this.callWorker('getFullMetadata');
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
281
|
+
return NCGet.getFullMetadata(this.module, this.ncid);
|
|
296
282
|
}
|
|
297
|
-
return result.varids || [0];
|
|
298
283
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
284
|
+
async getAttributeValues(varid, attname) {
|
|
285
|
+
if (this.worker) {
|
|
286
|
+
return this.callWorker('getAttributeValues', { varid, attname });
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
290
|
+
return NCGet.getAttributeValues(this.module, this.ncid, varid, attname);
|
|
306
291
|
}
|
|
307
|
-
return result.dimids || [0];
|
|
308
292
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
const varResult = module.nc_inq_varid(this.ncid, result.name);
|
|
318
|
-
const varID = varResult.varid;
|
|
319
|
-
const { result: output, ...dim } = result;
|
|
320
|
-
const unitResult = this.getAttributeValues(varID, "units");
|
|
321
|
-
return { ...dim, units: unitResult, id: varID };
|
|
322
|
-
}
|
|
323
|
-
getDims() {
|
|
324
|
-
const dimIDs = this.getDimIDs();
|
|
325
|
-
const dims = {};
|
|
326
|
-
for (const dimid of dimIDs) {
|
|
327
|
-
const dim = this.getDim(dimid);
|
|
328
|
-
dims[dim.name] = {
|
|
329
|
-
size: dim.len,
|
|
330
|
-
units: dim.units,
|
|
331
|
-
id: dim.id
|
|
332
|
-
};
|
|
293
|
+
async getDimCount() {
|
|
294
|
+
if (this.worker) {
|
|
295
|
+
return this.callWorker('getDimCount');
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
299
|
+
return NCGet.getDimCount(this.module, this.ncid);
|
|
333
300
|
}
|
|
334
|
-
return dims;
|
|
335
301
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
302
|
+
async getVariables() {
|
|
303
|
+
if (this.worker) {
|
|
304
|
+
return this.callWorker('getVariables');
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
308
|
+
return NCGet.getVariables(this.module, this.ncid);
|
|
343
309
|
}
|
|
344
|
-
return result.nvars || 0;
|
|
345
310
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
throw new Error("Failed to load module. Ensure module is initialized before calling methods");
|
|
350
|
-
const result = module.nc_inq_attname(this.ncid, varid, attId);
|
|
351
|
-
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
352
|
-
throw new Error(`Failed to get attribute (error: ${result.result})`);
|
|
353
|
-
}
|
|
354
|
-
return result.name;
|
|
355
|
-
}
|
|
356
|
-
getVariableInfo(variable) {
|
|
357
|
-
const info = {};
|
|
358
|
-
const module = this.module;
|
|
359
|
-
if (!module)
|
|
360
|
-
throw new Error("Failed to load module. Ensure module is initialized before calling methods");
|
|
361
|
-
const isId = typeof variable === "number";
|
|
362
|
-
let varid = variable;
|
|
363
|
-
if (!isId) {
|
|
364
|
-
const result = module.nc_inq_varid(this.ncid, variable);
|
|
365
|
-
varid = result.varid;
|
|
366
|
-
}
|
|
367
|
-
const result = module.nc_inq_var(this.ncid, varid);
|
|
368
|
-
if (result.result !== NC_CONSTANTS.NC_NOERR) {
|
|
369
|
-
throw new Error(`Failed to get variable info (error: ${result.result})`);
|
|
370
|
-
}
|
|
371
|
-
const typeMultiplier = DATA_TYPE_SIZE[result.type];
|
|
372
|
-
//Dim Info
|
|
373
|
-
const dimids = result.dimids;
|
|
374
|
-
const dims = [];
|
|
375
|
-
const shape = [];
|
|
376
|
-
let size = 1;
|
|
377
|
-
if (dimids) {
|
|
378
|
-
for (const dimid of dimids) {
|
|
379
|
-
const dim = this.getDim(dimid);
|
|
380
|
-
size *= dim.len;
|
|
381
|
-
dims.push(dim);
|
|
382
|
-
shape.push(dim.len);
|
|
383
|
-
}
|
|
311
|
+
async getVarIDs() {
|
|
312
|
+
if (this.worker) {
|
|
313
|
+
return this.callWorker('getVarIDs');
|
|
384
314
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
for (let i = 0; i < result.natts; i++) {
|
|
389
|
-
const attname = this.getAttributeName(varid, i);
|
|
390
|
-
attNames.push(attname);
|
|
391
|
-
}
|
|
315
|
+
else {
|
|
316
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
317
|
+
return NCGet.getVarIDs(this.module, this.ncid);
|
|
392
318
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
319
|
+
}
|
|
320
|
+
async getDimIDs() {
|
|
321
|
+
if (this.worker) {
|
|
322
|
+
return this.callWorker('getDimIDs');
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
326
|
+
return NCGet.getDimIDs(this.module, this.ncid);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
async getDim(dimid) {
|
|
330
|
+
if (this.worker) {
|
|
331
|
+
return this.callWorker('getDim', { dimid });
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
335
|
+
return NCGet.getDim(this.module, this.ncid, dimid);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
async getDims() {
|
|
339
|
+
if (this.worker) {
|
|
340
|
+
return this.callWorker('getDims');
|
|
400
341
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
342
|
+
else {
|
|
343
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
344
|
+
return NCGet.getDims(this.module, this.ncid);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
async getVarCount() {
|
|
348
|
+
if (this.worker) {
|
|
349
|
+
return this.callWorker('getVarCount');
|
|
407
350
|
}
|
|
408
351
|
else {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
if (
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
else
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
else if (arrayType === 10)
|
|
449
|
-
arrayData = module.nc_get_var_longlong(this.ncid, varid, arraySize);
|
|
450
|
-
else if (arrayType === 5)
|
|
451
|
-
arrayData = module.nc_get_var_float(this.ncid, varid, arraySize);
|
|
452
|
-
else if (arrayType === 6)
|
|
453
|
-
arrayData = module.nc_get_var_double(this.ncid, varid, arraySize);
|
|
454
|
-
else
|
|
455
|
-
arrayData = module.nc_get_var_double(this.ncid, varid, arraySize);
|
|
456
|
-
if (!arrayData.data)
|
|
457
|
-
throw new Error("Failed to read array data");
|
|
458
|
-
return arrayData.data;
|
|
459
|
-
}
|
|
460
|
-
getSlicedVariableArray(variable, start, count) {
|
|
461
|
-
const module = this.module;
|
|
462
|
-
if (!module)
|
|
463
|
-
throw new Error("Failed to load module. Ensure module is initialized before calling methods");
|
|
464
|
-
const isId = typeof variable === "number";
|
|
465
|
-
let varid = isId ? variable : 0;
|
|
466
|
-
if (!isId) {
|
|
467
|
-
const result = module.nc_inq_varid(this.ncid, variable);
|
|
468
|
-
varid = result.varid;
|
|
469
|
-
}
|
|
470
|
-
const info = this.getVariableInfo(varid);
|
|
471
|
-
const arrayType = info.nctype;
|
|
472
|
-
if (!arrayType)
|
|
473
|
-
throw new Error("Failed to allocate memory for array");
|
|
474
|
-
let arrayData;
|
|
475
|
-
if (arrayType === 3)
|
|
476
|
-
arrayData = module.nc_get_vara_short(this.ncid, varid, start, count);
|
|
477
|
-
else if (arrayType === 4)
|
|
478
|
-
arrayData = module.nc_get_vara_int(this.ncid, varid, start, count);
|
|
479
|
-
else if (arrayType === 5)
|
|
480
|
-
arrayData = module.nc_get_vara_float(this.ncid, varid, start, count);
|
|
481
|
-
else if (arrayType === 6)
|
|
482
|
-
arrayData = module.nc_get_vara_double(this.ncid, varid, start, count);
|
|
483
|
-
else
|
|
484
|
-
arrayData = module.nc_get_vara_double(this.ncid, varid, start, count);
|
|
485
|
-
if (!arrayData.data)
|
|
486
|
-
throw new Error("Failed to read array data");
|
|
487
|
-
return arrayData.data;
|
|
352
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
353
|
+
return NCGet.getVarCount(this.module, this.ncid);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async getAttributeName(varid, attId) {
|
|
357
|
+
if (this.worker) {
|
|
358
|
+
return this.callWorker('getAttributeName', { varid, attId });
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
362
|
+
return NCGet.getAttributeName(this.module, this.ncid, varid, attId);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
async getVariableInfo(variable) {
|
|
366
|
+
if (this.worker) {
|
|
367
|
+
return this.callWorker('getVariableInfo', { variable });
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
371
|
+
return NCGet.getVariableInfo(this.module, this.ncid, variable);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
async getVariableArray(variable) {
|
|
375
|
+
if (this.worker) {
|
|
376
|
+
return this.callWorker('getVariableArray', { variable });
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
380
|
+
return NCGet.getVariableArray(this.module, this.ncid, variable);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
async getSlicedVariableArray(variable, start, count) {
|
|
384
|
+
if (this.worker) {
|
|
385
|
+
return this.callWorker('getSlicedVariableArray', { variable, start, count });
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
// Main thread path is already synchronous (or could be wrapped in Promise.resolve)
|
|
389
|
+
return NCGet.getSlicedVariableArray(this.module, this.ncid, variable, start, count);
|
|
390
|
+
}
|
|
488
391
|
}
|
|
489
392
|
async defineDimension(ncid, name, size) {
|
|
490
393
|
const module = this.getModule();
|
|
@@ -639,6 +542,36 @@ export class NetCDF4 extends Group {
|
|
|
639
542
|
nc_enddef: (ncid) => NC_CONSTANTS.NC_NOERR,
|
|
640
543
|
};
|
|
641
544
|
}
|
|
545
|
+
async setupWorker() {
|
|
546
|
+
if (!this.workerSource)
|
|
547
|
+
throw new Error('No worker source');
|
|
548
|
+
// 1. Instantiate the worker if it doesn't exist
|
|
549
|
+
if (!this.worker) {
|
|
550
|
+
// Option A: If using Vite/Webpack 5
|
|
551
|
+
this.worker = new Worker(new URL('./netcdf-worker.js', import.meta.url), { type: 'module' });
|
|
552
|
+
}
|
|
553
|
+
this.workerReady = new Promise((resolve, reject) => {
|
|
554
|
+
// Use a named function so we can remove the listener later
|
|
555
|
+
const initHandler = (e) => {
|
|
556
|
+
if (e.data.success) {
|
|
557
|
+
this.worker.removeEventListener('message', initHandler);
|
|
558
|
+
resolve();
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
this.worker.removeEventListener('message', initHandler);
|
|
562
|
+
reject(new Error(e.data.message));
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
this.worker.addEventListener('message', initHandler);
|
|
566
|
+
// 3. Send the initialization message
|
|
567
|
+
this.worker.postMessage({
|
|
568
|
+
type: 'init',
|
|
569
|
+
blob: this.workerSource.blob,
|
|
570
|
+
filename: this.workerSource.filename
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
return this.workerReady;
|
|
574
|
+
}
|
|
642
575
|
// Mount memory data in the WASM virtual file system
|
|
643
576
|
async mountMemoryData() {
|
|
644
577
|
if (!this.memorySource || !this.module) {
|