weacast / weacast-grib2json

CLI to converts GRIB2 files to JSON
MIT License
40 stars 9 forks source link

The precision option seems to have no effect when used via node.js #15

Closed drmrbrewer closed 3 years ago

drmrbrewer commented 3 years ago

I am using this library as a node module, passing an options object like that as follows:

{
    data: true,
    names: true,
    precision: 2,
    fc: '0',
    fp: '0',
    output: 'output.json',
    bufferSize: 32 * 1024 * 1024
}

But my data values are still coming out with 7 decimal place precision, e.g. "2.7128906". Am I doing something wrong? I've passed precision both as a number 2 and as a string '2' but with the same result.

claustres commented 3 years ago

Could you please provide your input file ?

drmrbrewer commented 3 years ago

http://dcpc-nwp.meteo.fr/services/PS_GetCache_DCPCPreviNum?model=ARPEGE&grid=0.1&format=grib2&package=SP1&referencetime=2020-10-18T12:00:00Z&time=00H12H

claustres commented 3 years ago

I tested with the following options and it seems to work fine:

grib2json(path.join(__dirname, 'data', 'meteo.grib2'), {
  data: true,
  names: true,
  precision: 2,
  fv: 10,
  fp: 2,
  fs: 103,
  bufferSize: 32 * 1024 * 1024,
  output: path.join(__dirname, 'data', 'meteo.json'), verbose: true,
})

It extracts all forecast times for wind component at 10m. Not sure what your fc option is ? With your options the generated file was something like 1.5GB, I did not try to open it but you might face some issue with too much large file like in https://github.com/weacast/weacast-grib2json/issues/14. You probably need to restrict the volume of data to be extracted.

drmrbrewer commented 3 years ago

So you are getting 2 decimal places out? I am still getting 7 decimal places, and I'm definitely using a precision of 2 in the options. Peculiar.

claustres commented 3 years ago

Yes I am getting 2 decimal places. Here is the output: meteo.zip

drmrbrewer commented 3 years ago

Here is a log output from mine, starting with the options being passed in, then the data out.

options: {"data":true,"names":true,"precision":2,"bufferSize":8388608,"fc":"0","fp":"0","output":"/root/workspace/json/SP1_2020-10-18T12:00:00Z_00H12H_0_0.json"}

data: [
  258.56903,  258.8034,  258.9909,  259.2409, 259.44403, 259.64716,
  259.85028, 260.06903,  260.3034, 260.60028, 260.88153,  261.1784,
   261.4909,  261.8659,  262.1784, 262.56903, 262.89716, 263.22528,
  263.72528, 264.19403, 264.78778, 265.47528, 266.16278, 266.66278,
   266.9284, 267.08466, 266.89716, 266.47528, 265.85028, 265.69403,
  266.50653, 267.14716,  267.0534,  266.6784,  266.0534, 267.03778,
  272.14716, 263.31903, 269.27216,  269.6784,  268.4909, 269.91278,
   264.1784, 263.39716,  264.4284,  266.2409, 266.97528, 265.53778,
   262.1159, 262.33466,  263.4284, 264.22528, 266.13153, 263.28778,
  263.94403,  262.7409,  263.4909, 263.58466, 263.13153,  261.9909,
  261.14716, 261.83466,  261.1784, 261.64716,  262.7409,  262.7409,
  258.60028, 258.10028, 259.77216, 259.81903, 257.63153, 259.91278,
  259.63153, 256.28778, 256.45966, 260.00653, 260.66278,  259.9909,
   258.9284, 258.50653, 258.69403, 257.95966, 260.22528, 261.47528,
  262.06903, 263.27216, 263.83466, 264.31903, 266.08466, 266.35028,
  269.75653, 269.75653,  269.5534, 269.27216, 269.02216, 268.85028,
  268.70966, 268.64716, 268.75653,  268.9284,
  ... 385961 more items
]

Actually, I should mention that I am using the json directly from grib2json call, not the json file itself... maybe that is the difference? The json object returned has full resolution, but the json file is written with 2 d.p.?

const jsondata = await grib2json(gribFileName, options);
await this.processJson(jsondata);
claustres commented 3 years ago

Yes you should have mentioned it, precision does not make any sense for the in-memory json, data are simply floating point values in the JS engine. Precision is only relevant when you output the data into a file as strings because you then have to choose how much decimal places you write. A JS object does not have any precision attached to it, it's when you "stringify" the object to JSON that you can select a format with a limited precision: https://github.com/weacast/weacast-grib2json/blob/master/index.js#L49.

drmrbrewer commented 3 years ago

OK, got it. I had assumed that the precision value would affect the in-memory values as well (after all, it is possible to reduce precision of a float value in JS even if it uses no less storage). Understand now that this isn't the case. Thanks.

claustres commented 3 years ago

What are you refering for limiting precision in JS ?

drmrbrewer commented 3 years ago

I just mean altering the float value to reduce its precision:

let a = 273.3835182; console.log(`before: ${a}`); a = Math.round(a * 100) / 100; console.log(`after: ${a}`); 
before: 273.3835182
after: 273.38

So it's still a floating point number, just different to what it was before. I agree that in general it would make more sense to limit precision when converting to a string or writing to a file, because until that point there is no benefit in terms of storage efficiency. I guess it is maybe just a little surprising the specifying precision only has an effect in the output written to file, but not in the json object returned directly, so you end up with different json depending on which you use. It's ok once I know that, but it may catch people out. Perhaps a note in the docs would help in this respect.

Thanks again for making this library available, and for being so supportive of it... really appreciated!

claustres commented 3 years ago

OK got it now, IMHO as there is no benefit it would be too bad to round numbers. I added a warning in the docs.

One option could be to store data as Float32Array to reduce the memory footprint. However at some point we can hit memory limits as well with 32-bit precision, the best strategy to avoid this is divide and conquer.