UNPKG

netcdf4-wasm

Version:

NetCDF4 library compiled to WebAssembly with TypeScript bindings

200 lines 9.11 kB
"use strict"; // Group class for hierarchical data organization Object.defineProperty(exports, "__esModule", { value: true }); exports.Group = void 0; const dimension_1 = require("./dimension"); const variable_1 = require("./variable"); const constants_1 = require("./constants"); class Group { constructor(netcdf, name, groupId) { this.netcdf = netcdf; this.name = name; this.groupId = groupId; this.dimensions = {}; this.variables = {}; this.groups = {}; this._attributes = {}; } // Attribute methods setAttr(name, value) { this._attributes[name] = value; // Store in mock file system if in test mode if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') { const mockFiles = global.__netcdf4_mock_files; const dataset = this.netcdf; if (mockFiles && dataset.filename && mockFiles[dataset.filename]) { mockFiles[dataset.filename].attributes[name] = value; } } // TODO: Implement actual NetCDF global attribute setting } getAttr(name) { // Check mock file system first if in test mode if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') { const mockFiles = global.__netcdf4_mock_files; const dataset = this.netcdf; if (mockFiles && dataset.filename && mockFiles[dataset.filename]) { const value = mockFiles[dataset.filename].attributes[name]; if (value !== undefined) { this._attributes[name] = value; // Sync local cache return value; } } } return this._attributes[name]; } attrs() { return Object.keys(this._attributes); } async createDimension(name, size) { // Check for duplicate dimension name if (this.dimensions[name]) { throw new Error(`Dimension '${name}' already exists`); } // Check for invalid size values if (size !== null && size < 0 && size !== constants_1.NC_CONSTANTS.NC_UNLIMITED) { throw new Error(`Invalid dimension size: ${size}. Size must be non-negative or null for unlimited.`); } // Handle unlimited dimension (null or NC_UNLIMITED constant) const isUnlimited = size === null || size === constants_1.NC_CONSTANTS.NC_UNLIMITED; const ncSize = isUnlimited ? 0 : size; // Use 0 for unlimited in the actual NetCDF API const dimid = await this.netcdf.defineDimension(this.groupId, name, ncSize); const actualSize = isUnlimited ? constants_1.NC_CONSTANTS.NC_UNLIMITED : size; const dimension = new dimension_1.Dimension(name, actualSize, isUnlimited); this.dimensions[name] = dimension; return dimension; } // Load dimensions and variables from mock storage when in test mode loadMockDimensions() { if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') { const mockFiles = global.__netcdf4_mock_files; const dataset = this.netcdf; if (mockFiles && dataset.filename && mockFiles[dataset.filename]) { // Load dimensions const mockDims = mockFiles[dataset.filename].dimensions; for (const [name, dimData] of Object.entries(mockDims)) { const dimension = new dimension_1.Dimension(name, dimData.size, dimData.unlimited); this.dimensions[name] = dimension; } // Load variables const mockVars = mockFiles[dataset.filename].variables; for (const [name, varData] of Object.entries(mockVars)) { const varInfo = varData; // Reconstruct variable - for now, assume double datatype and no dimensions for simplicity const variable = new variable_1.Variable(this.netcdf, name, varInfo.datatype || 'f8', varInfo.dimensions || [], 1, this.groupId); // Restore variable attributes if (varInfo.attributes) { for (const [attrName, attrValue] of Object.entries(varInfo.attributes)) { variable.setAttr(attrName, attrValue); } } this.variables[name] = variable; } } } } // Load dimensions, variables and attributes from an opened real file. loadFromFile() { const module = this.netcdf.getModule(); const ncid = this.groupId; const ndimsRes = module.nc_inq_ndims(ncid); if (ndimsRes.result !== constants_1.NC_CONSTANTS.NC_NOERR) return; const unlimdimid = module.nc_inq_unlimdim(ncid).unlimdimid; const dimNames = []; for (let dimid = 0; dimid < ndimsRes.ndims; dimid++) { const d = module.nc_inq_dim(ncid, dimid); if (d.result !== constants_1.NC_CONSTANTS.NC_NOERR) continue; dimNames[dimid] = d.name; this.dimensions[d.name] = new dimension_1.Dimension(d.name, d.len, dimid === unlimdimid); } const nvars = module.nc_inq_nvars(ncid).nvars; for (let varid = 0; varid < nvars; varid++) { const v = module.nc_inq_var(ncid, varid); if (v.result !== constants_1.NC_CONSTANTS.NC_NOERR) continue; const datatype = constants_1.NC_TYPE_TO_STR[v.xtype] ?? 'f8'; const varDims = v.dimids .map((id) => dimNames[id]) .filter((n) => !!n); const variable = new variable_1.Variable(this.netcdf, v.name, datatype, varDims, varid, ncid); this.loadAttributes(module, ncid, varid, v.natts, (n, val) => variable.setAttr(n, val)); this.variables[v.name] = variable; } const globalNatts = module.nc_inq_natts(ncid).natts; this.loadAttributes(module, ncid, constants_1.NC_CONSTANTS.NC_GLOBAL, globalNatts, (n, val) => this.setAttr(n, val)); } loadAttributes(module, ncid, varid, natts, set) { for (let attnum = 0; attnum < natts; attnum++) { const an = module.nc_inq_attname(ncid, varid, attnum); if (an.result !== constants_1.NC_CONSTANTS.NC_NOERR) continue; const ai = module.nc_inq_att(ncid, varid, an.name); if (ai.result !== constants_1.NC_CONSTANTS.NC_NOERR) continue; let value; if (ai.xtype === constants_1.NC_CONSTANTS.NC_CHAR) { value = module.nc_get_att_text(ncid, varid, an.name, ai.len).text; } else { const r = module.nc_get_att_double(ncid, varid, an.name, ai.len); value = ai.len === 1 ? r.values[0] : Array.from(r.values); } set(an.name, value); } } async createVariable(name, datatype, dimensions = [], options = {}) { const ncType = constants_1.DATA_TYPE_MAP[datatype]; if (ncType === undefined) { throw new Error(`Unsupported datatype: ${datatype}`); } // Get dimension IDs const dimIds = dimensions.map(dimName => { const dim = this.dimensions[dimName]; if (!dim) { throw new Error(`Dimension '${dimName}' not found`); } // For now, we'll use the dimension name as ID (simplified) return Object.keys(this.dimensions).indexOf(dimName); }); const varid = await this.netcdf.defineVariable(this.groupId, name, ncType, dimIds); const variable = new variable_1.Variable(this.netcdf, name, datatype, dimensions, varid, this.groupId); this.variables[name] = variable; // Store variable metadata in mock storage if in test mode if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') { const mockFiles = global.__netcdf4_mock_files; const dataset = this.netcdf; if (mockFiles && dataset.filename && mockFiles[dataset.filename]) { mockFiles[dataset.filename].variables[name] = { datatype: datatype, dimensions: dimensions, data: new Float64Array(0), attributes: {} }; } } return variable; } createGroup(name) { // For simplicity, groups use the same ncid for now const group = new Group(this.netcdf, name, this.groupId); this.groups[name] = group; return group; } // Python-like method to get all children children() { return this.groups; } // Get group path (Python-like) get path() { if (this.name === '') return '/'; return `/${this.name}`; } toString() { return `<netCDF4.Group '${this.path}'>`; } } exports.Group = Group; //# sourceMappingURL=group.js.map