28
28
*/
29
29
30
30
class Giniheader {
31
+ // Unidata Gini table:
32
+ // https://github.com/Unidata/gempak/blob/master/gempak/tables/unidata/nex2gini.tbl
33
+ // Special instructions for handling negative numbers
34
+ // https://github.com/Unidata/gempak/blob/master/gempak/source/gemlib/mv/Linux/mvitob.c
35
+ //
36
+ private static org .slf4j .Logger log = org .slf4j .LoggerFactory .getLogger (Giniheader .class );
37
+
31
38
static private final int GINI_PIB_LEN = 21 ; // gini product identification block
32
39
static private final int GINI_PDB_LEN = 512 ; // gini product description block
33
40
static private final int GINI_HED_LEN = GINI_PDB_LEN + GINI_PIB_LEN ; // gini product header
34
41
static private final double DEG_TO_RAD = 0.017453292 ;
35
42
private boolean debug = false ;
36
43
private ucar .nc2 .NetcdfFile ncfile ;
37
- static private org .slf4j .Logger log = org .slf4j .LoggerFactory .getLogger (Giniheader .class );
38
44
int dataStart = 0 ; // where the data starts
39
45
protected int Z_type = 0 ;
40
46
@@ -379,7 +385,7 @@ void read(ucar.unidata.io.RandomAccessFile raf, ucar.nc2.NetcdfFile ncfile) thro
379
385
break ;
380
386
381
387
default :
382
- System . out . println ( "unimplemented projection" );
388
+ log . warn ( "GINI: Unimplemented projection! " );
383
389
}
384
390
385
391
this .ncfile .addAttribute (null , new Attribute ("title" , gini_GetEntityID (ent_id )));
@@ -492,6 +498,7 @@ void read(ucar.unidata.io.RandomAccessFile raf, ucar.nc2.NetcdfFile ncfile) thro
492
498
xaxis .setDataType (DataType .DOUBLE );
493
499
xaxis .setDimensions ("x" );
494
500
xaxis .addAttribute (new Attribute (CDM .LONG_NAME , "projection x coordinate" ));
501
+ xaxis .addAttribute (new Attribute (CF .STANDARD_NAME , "projection_x_coordinate" ));
495
502
xaxis .addAttribute (new Attribute (CDM .UNITS , "km" ));
496
503
xaxis .addAttribute (new Attribute (_Coordinate .AxisType , "GeoX" ));
497
504
double [] data = new double [nx ];
@@ -520,6 +527,7 @@ void read(ucar.unidata.io.RandomAccessFile raf, ucar.nc2.NetcdfFile ncfile) thro
520
527
yaxis .setDataType (DataType .DOUBLE );
521
528
yaxis .setDimensions ("y" );
522
529
yaxis .addAttribute (new Attribute (CDM .LONG_NAME , "projection y coordinate" ));
530
+ yaxis .addAttribute (new Attribute (CF .STANDARD_NAME , "projection_y_coordinate" ));
523
531
yaxis .addAttribute (new Attribute (CDM .UNITS , "km" ));
524
532
yaxis .addAttribute (new Attribute (_Coordinate .AxisType , "GeoY" ));
525
533
data = new double [ny ];
@@ -556,6 +564,8 @@ void read(ucar.unidata.io.RandomAccessFile raf, ucar.nc2.NetcdfFile ncfile) thro
556
564
ncfile .addVariable (null , ct );
557
565
ncfile .addAttribute (null , new Attribute (CDM .CONVENTIONS , _Coordinate .Convention ));
558
566
567
+ var .addAttribute (new Attribute (CF .GRID_MAPPING , ct .getFullName ()));
568
+
559
569
// finish
560
570
ncfile .finish ();
561
571
}
@@ -581,10 +591,35 @@ int[] getCalibrationInfo(ByteBuffer bos, int phys_elem, int ent_id) {
581
591
for (int i = 0 ; i < calcod ; i ++) {
582
592
583
593
bos .position (56 + i * 16 );
594
+ // We expect these to always be positive, so just read the int as-is
584
595
int minb = bos .getInt () / 10000 ; /* min brightness values */
585
596
int maxb = bos .getInt () / 10000 ; /* max brightness values */
597
+
598
+ // Since these are data values, we need to consider the case of them being positive or negative
599
+ // Careful though, it's not that easy. Step one is to read the 32-bits like before...
586
600
int mind = bos .getInt (); /* min data values */
601
+ // Now for the fun.
602
+ // According to https://github.com/Unidata/gempak/blob/master/gempak/source/gemlib/mv/Linux/mvitob.c,
603
+ // which is used when writing gini files, if the first bit is set, that indicates that we have a negative
604
+ // value and need to do a bit more work.
605
+ // Check if left-most bit is 1. Right shift bit pattern of value 31 times. This will make all bits 0, or
606
+ // all bits 1. If all 0, then the result will equal zero. If all 1's, then the result will equal -1, and
607
+ // that's how we know we need to do more work.
608
+ if ((mind >> 31 ) == -1 ) {
609
+ // Set the first bit to zero, and negate the value (again, described in mvitob.c from gempak)
610
+ // 0x7FFFFFFF -> left-most bit is zero, all the rest are 1's.
611
+ // The bit-wise & results in flipping the first bit of "mind" (because we know it is 1 at this point, and
612
+ // 1 & 0 -> 0) while retaining the rest of the pattern of mind (because 0 & 1 -> 0, 1 & 1 -> 1).
613
+ // To negate, just use the negative sign...we could do ~(mind & 0x7FFFFFFF) + 1, but let's not hang out
614
+ // in bit operator land longer than we need to.
615
+ mind = -(mind & 0x7FFFFFFF );
616
+ }
617
+
618
+ // same thing as above
587
619
int maxd = bos .getInt (); /* max data values */
620
+ if ((maxd >> 31 ) == -1 ) {
621
+ maxd = -(maxd & 0x7FFFFFFF );
622
+ }
588
623
589
624
int idscal = 1 ;
590
625
while (mind % idscal == 0 && maxd % idscal == 0 ) {
0 commit comments