Skip to content

Commit fd41b69

Browse files
authored
Merge pull request #3 from EarthyScience/jp/netcdf-worker
Add workers
2 parents b707be2 + b5e567d commit fd41b69

File tree

5 files changed

+652
-258
lines changed

5 files changed

+652
-258
lines changed

src/netcdf-getters.ts

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
import { NC_CONSTANTS, DATA_TYPE_SIZE, CONSTANT_DTYPE_MAP } from './constants.js';
2+
import type { NetCDF4Module } from './types.js';
3+
4+
export function getVariables(
5+
module: NetCDF4Module,
6+
ncid: number
7+
): Record<string, any> {
8+
const variables: Record<string, any> = {};
9+
const varCount = getVarCount(module, ncid);
10+
const dimIds = getDimIDs(module, ncid)
11+
for (let varid = 0; varid < varCount; varid++) {
12+
if (dimIds.includes(varid)) continue; //Don't include spatial Vars
13+
14+
const result = module.nc_inq_varname(ncid,varid);
15+
if (result.result !== NC_CONSTANTS.NC_NOERR || !result.name) {
16+
console.warn(`Failed to get variable name for varid ${varid} (error: ${result.result})`);
17+
continue;
18+
}
19+
variables[result.name] = {
20+
id: varid
21+
}
22+
}
23+
return variables;
24+
}
25+
26+
export function getVarCount(
27+
module: NetCDF4Module,
28+
ncid: number
29+
): number {
30+
const result = module.nc_inq_nvars(ncid);
31+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
32+
throw new Error(`Failed to get number of variables (error: ${result.result})`);
33+
}
34+
return result.nvars || 0;
35+
}
36+
37+
export function getDimCount(
38+
module: NetCDF4Module,
39+
ncid: number
40+
): number {
41+
const result = module.nc_inq_ndims(ncid);
42+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
43+
throw new Error(`Failed to get number of dimensions (error: ${result.result})`);
44+
}
45+
return result.ndims || 0;
46+
}
47+
48+
export function getDims(
49+
module: NetCDF4Module,
50+
ncid: number
51+
): Record<string, any> {
52+
const dimIDs = getDimIDs(module, ncid);
53+
const dims: Record<string, any> = {};
54+
for (const dimid of dimIDs) {
55+
const dim = getDim(module, ncid, dimid)
56+
dims[dim.name] = {
57+
size: dim.len,
58+
units:dim.units,
59+
id:dim.id
60+
}
61+
}
62+
return dims
63+
}
64+
65+
export function getDimIDs(
66+
module: NetCDF4Module,
67+
ncid: number
68+
): number[] | Int32Array {
69+
const result = module.nc_inq_dimids(ncid, 0);
70+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
71+
throw new Error(`Failed to get dimension IDs (error: ${result.result})`);
72+
}
73+
return result.dimids || [0];
74+
}
75+
76+
export function getDim(
77+
module: NetCDF4Module,
78+
ncid: number,
79+
dimid: number
80+
): Record<string, any> {
81+
const result = module.nc_inq_dim(ncid, dimid);
82+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
83+
throw new Error(`Failed to get dim (error: ${result.result})`);
84+
}
85+
const varResult = module.nc_inq_varid(ncid, result.name as string)
86+
const varID = varResult.varid as number
87+
const {result:output, ...dim} = result
88+
const unitResult = getAttributeValues(module, ncid, varID, "units")
89+
return {...dim, units:unitResult, id:varID};
90+
}
91+
92+
export function getAttributeValues(
93+
module: NetCDF4Module,
94+
ncid: number,
95+
varid: number,
96+
attname: string
97+
): any {
98+
const attInfo = module.nc_inq_att(ncid, varid, attname);
99+
if (attInfo.result !== NC_CONSTANTS.NC_NOERR) {
100+
console.warn(`Failed to get attribute info for ${attname} (error: ${attInfo.result})`);
101+
return;
102+
}
103+
const attType = attInfo.type;
104+
if (!attType) throw new Error("Failed to allocate memory for attribute type.");
105+
let attValue;
106+
if (attType === 2) attValue = module.nc_get_att_text(ncid, varid, attname, attInfo.len as number);
107+
else if (attType === 3) attValue = module.nc_get_att_short(ncid, varid, attname, attInfo.len as number);
108+
else if (attType === 4) attValue = module.nc_get_att_int(ncid, varid, attname, attInfo.len as number);
109+
else if (attType === 5) attValue = module.nc_get_att_float(ncid, varid, attname, attInfo.len as number);
110+
else if (attType === 6) attValue = module.nc_get_att_double(ncid, varid, attname, attInfo.len as number);
111+
else if (attType === 10) attValue = module.nc_get_att_longlong(ncid, varid, attname, attInfo.len as number);
112+
else attValue = module.nc_get_att_double(ncid, varid, attname, attInfo.len as number);
113+
114+
return attValue.data
115+
}
116+
117+
export function getGlobalAttributes(
118+
module: NetCDF4Module,
119+
ncid: number,
120+
): Record<string, any> {
121+
const attributes: Record<string, any> = {};
122+
const nattsResult = module.nc_inq_natts(ncid);
123+
if (nattsResult.result !== NC_CONSTANTS.NC_NOERR) {
124+
throw new Error(`Failed to get number of global attributes (error: ${nattsResult.result})`);
125+
}
126+
const nAtts = nattsResult.natts as number
127+
const attNames = []
128+
for (let i=0; i < nAtts; i++){
129+
const name = getAttributeName(module, ncid, NC_CONSTANTS.NC_GLOBAL, i)
130+
attNames.push(name)
131+
}
132+
if (attNames.length === 0) return attributes
133+
for (const attname of attNames){
134+
if (!attname) continue;
135+
attributes[attname] = getAttributeValues(module, ncid, NC_CONSTANTS.NC_GLOBAL, attname)
136+
}
137+
return attributes
138+
}
139+
140+
export function getAttributeName(
141+
module: NetCDF4Module,
142+
ncid: number,
143+
varid:number,
144+
attId: number
145+
) : string | undefined {
146+
const result = module.nc_inq_attname(ncid, varid, attId);
147+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
148+
throw new Error(`Failed to get attribute (error: ${result.result})`);
149+
}
150+
return result.name
151+
}
152+
153+
export function getFullMetadata(
154+
module: NetCDF4Module,
155+
ncid: number,
156+
): Record<string, any>[] {
157+
const varIds = getVarIDs(module, ncid)
158+
const metas = []
159+
for (const varid of varIds){
160+
const varMeta = getVariableInfo(module, ncid, varid)
161+
const {attributes, ...varDeets} = varMeta
162+
metas.push({...varDeets,...attributes})
163+
}
164+
return metas
165+
}
166+
167+
export function getVarIDs(
168+
module: NetCDF4Module,
169+
ncid: number
170+
): number[] | Int32Array {
171+
const result = module.nc_inq_varids(ncid);
172+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
173+
throw new Error(`Failed to get variable IDs (error: ${result.result})`);
174+
}
175+
return result.varids || [0];
176+
}
177+
178+
export function getVariableInfo(
179+
module: NetCDF4Module,
180+
ncid: number,
181+
variable: number | string): Record<string, any>{
182+
const info: Record<string, any> = {}
183+
184+
const isId = typeof variable === "number"
185+
let varid = variable
186+
if (!isId){
187+
const result = module.nc_inq_varid(ncid, variable)
188+
varid = result.varid as number
189+
}
190+
const result = module.nc_inq_var(ncid, varid as number);
191+
if (result.result !== NC_CONSTANTS.NC_NOERR) {
192+
throw new Error(`Failed to get variable info (error: ${result.result})`);
193+
}
194+
const typeMultiplier = DATA_TYPE_SIZE[result.type as number]
195+
196+
//Dim Info
197+
const dimids = result.dimids
198+
const dims = []
199+
const shape = []
200+
let size = 1
201+
if (dimids){
202+
for (const dimid of dimids){
203+
const dim = getDim(module, ncid, dimid)
204+
size *= dim.len
205+
dims.push(dim)
206+
shape.push(dim.len)
207+
}
208+
}
209+
210+
//Attribute Info
211+
const attNames = []
212+
if (result.natts){
213+
for (let i = 0; i < result.natts; i++ ){
214+
const attname = getAttributeName(module, ncid, varid as number, i)
215+
attNames.push(attname)
216+
}
217+
}
218+
const atts: Record<string, any> = {}
219+
if (attNames.length > 0){
220+
for (const attname of attNames){
221+
if (!attname) continue;
222+
atts[attname] = getAttributeValues(module, ncid, varid as number, attname)
223+
}
224+
}
225+
226+
//Chunking Info
227+
let chunks: number[];
228+
const chunkResult = module.nc_inq_var_chunking(ncid, varid as number);
229+
const isChunked = chunkResult.chunking === NC_CONSTANTS.NC_CHUNKED
230+
if (isChunked) {
231+
chunks = chunkResult.chunkSizes as number[]
232+
} else{
233+
chunks = shape
234+
}
235+
const chunkElements = chunks.reduce((a: number, b: number) => a * b, 1)
236+
237+
//Output
238+
info["name"] = result.name
239+
info["dtype"] = CONSTANT_DTYPE_MAP[result.type as number]
240+
info['nctype'] = result.type
241+
info["shape"] = shape
242+
info['dims'] = dims
243+
info["size"] = size
244+
info["totalSize"] = size * typeMultiplier
245+
info["attributes"] = atts
246+
info["chunked"] = isChunked
247+
info["chunks"] = chunks
248+
info["chunkSize"] = chunkElements * typeMultiplier
249+
250+
return info;
251+
}
252+
253+
export function getVariableArray(
254+
module: NetCDF4Module,
255+
ncid: number,
256+
variable: number | string
257+
): Float32Array | Float64Array | Int16Array | Int32Array | BigInt64Array | BigInt[] | string[] {
258+
const isId = typeof variable === "number"
259+
let varid = isId ? variable as number : 0
260+
if (!isId){
261+
const result = module.nc_inq_varid(ncid, variable)
262+
varid = result.varid as number
263+
}
264+
const info = getVariableInfo(module, ncid, varid)
265+
const arraySize = info.size
266+
const arrayType = info.nctype
267+
if (!arrayType || !arraySize) throw new Error("Failed to allocate memory for array")
268+
let arrayData;
269+
if (arrayType === 2) arrayData = module.nc_get_var_text(ncid, varid, arraySize);
270+
else if (arrayType === 3) arrayData = module.nc_get_var_short(ncid, varid, arraySize);
271+
else if (arrayType === 4) arrayData = module.nc_get_var_int(ncid, varid, arraySize);
272+
else if (arrayType === 10) arrayData = module.nc_get_var_longlong(ncid, varid, arraySize);
273+
else if (arrayType === 5) arrayData = module.nc_get_var_float(ncid, varid, arraySize);
274+
else if (arrayType === 6) arrayData = module.nc_get_var_double(ncid, varid, arraySize);
275+
else arrayData = module.nc_get_var_double(ncid, varid, arraySize);
276+
if (!arrayData.data) throw new Error("Failed to read array data")
277+
return arrayData.data
278+
}
279+
280+
export function getSlicedVariableArray(
281+
module: NetCDF4Module,
282+
ncid: number,
283+
variable: number | string,
284+
start: number[],
285+
count: number[]
286+
): Float32Array | Float64Array | Int16Array | Int32Array | BigInt64Array | BigInt[] | string[] {
287+
const isId = typeof variable === "number"
288+
let varid = isId ? variable as number : 0
289+
if (!isId){
290+
const result = module.nc_inq_varid(ncid, variable)
291+
varid = result.varid as number
292+
}
293+
const info = getVariableInfo(module, ncid, varid)
294+
const arrayType = info.nctype
295+
if (!arrayType) throw new Error("Failed to allocate memory for array")
296+
let arrayData;
297+
if (arrayType === 3) arrayData = module.nc_get_vara_short(ncid, varid, start, count);
298+
else if (arrayType === 4) arrayData = module.nc_get_vara_int(ncid, varid, start, count);
299+
else if (arrayType === 5) arrayData = module.nc_get_vara_float(ncid, varid, start, count);
300+
else if (arrayType === 6) arrayData = module.nc_get_vara_double(ncid, varid, start, count);
301+
else arrayData = module.nc_get_vara_double(ncid, varid, start, count);
302+
if (!arrayData.data) {
303+
console.log(arrayData)
304+
throw new Error("Failed to read array data")}
305+
return arrayData.data
306+
}
307+
308+
// if (!module) throw new Error("Failed to load module. Ensure module is initialized before calling methods")

0 commit comments

Comments
 (0)