// *** constructors ******************************************************* /// <summary> Constructs a <tt>Grib1IndicatorSection</tt> object from a byteBuffer. /// /// </summary> /// <param name="raf">RandomAccessFile with IndicatorSection content /// /// </param> /// <throws> NotSupportedException if raf contains no valid GRIB file </throws> /// <throws> IOException </throws> //UPGRADE_TODO: Class 'java.io.RandomAccessFile' was converted to 'System.IO.FileStream' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioRandomAccessFile'" internal Grib1IndicatorSection(System.IO.Stream raf) { long mark = raf.Position; //if Grib edition 1, get bytes for the gribLength int[] data = new int[3]; for (int i = 0; i < 3; i++) { data[i] = raf.ReadByte(); } // edition of GRIB specification edition = raf.ReadByte(); if (edition == 1) { // length of GRIB record // Reset to beginning, then read 3 bytes raf.Position = mark; gribLength = (long)GribNumbers.uint3(raf); // Skip next byte, edition already read raf.ReadByte(); length = 8; } else if (edition == 2) { // length of GRIB record discipline = data[2]; gribLength = GribNumbers.int8(raf); length = 16; } else { throw new NotSupportedException("GRIB edition " + edition + " is not yet supported"); } } // end Grib1IndicatorSection
/// <summary> Constructs a Grib1BinaryDataSection object from a raf. /// A bit map is defined. /// /// </summary> /// <param name="raf">raf with BDS content /// </param> /// <param name="decimalscale">the exponent of the decimal scale /// </param> /// <param name="bms">bit map section of GRIB record /// /// </param> /// <throws> NotSupportedException if stream contains no valid GRIB file </throws> //UPGRADE_TODO: Class 'java.io.RandomAccessFile' was converted to 'System.IO.FileStream' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioRandomAccessFile'" internal Grib1BinaryDataSection(System.IO.Stream raf, int decimalscale, Grib1BitMapSection bms) { // octets 1-3 (section length) length = (int)GribNumbers.uint3(raf); // octet 4, 1st half (packing flag) int unusedbits = raf.ReadByte(); // TODO Check this!!! if ((unusedbits & 192) != 0) { throw new NotSupportedException("BDS: (octet 4, 1st half) not grid point data and simple packing "); } // octet 4, 2nd half (number of unused bits at end of this section) unusedbits = unusedbits & 15; // octets 5-6 (binary scale factor) int binscale = GribNumbers.int2(raf); // octets 7-10 (reference point = minimum value) float refvalue = GribNumbers.float4(raf); // octet 11 (number of bits per value) int numbits = raf.ReadByte(); if (numbits == 0) { isConstant = true; } // *** read values ******************************************************* //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float ref_Renamed = (float)(Math.Pow(10.0, -decimalscale) * refvalue); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float scale = (float)(Math.Pow(10.0, -decimalscale) * Math.Pow(2.0, binscale)); if (bms != null) { bool[] bitmap = bms.Bitmap; Values = new float[bitmap.Length]; for (int i = 0; i < bitmap.Length; i++) { if (bitmap[i]) { if (!isConstant) { Values[i] = ref_Renamed + scale * bits2UInt(numbits, raf); } else { // rdg - added this to handle a constant valued parameter Values[i] = ref_Renamed; } } else { Values[i] = MissingValue; } } } else { // bms is null if (!isConstant) { //(((length - 11) * 8 - unusedbits) / numbits)); Values = new float[((length - 11) * 8 - unusedbits) / numbits]; for (int i = 0; i < Values.Length; i++) { Values[i] = ref_Renamed + scale * bits2UInt(numbits, raf); } } else { // constant valued - same min and max int x = 0, y = 0; raf.Seek(raf.Position - 53, System.IO.SeekOrigin.Begin); // return to start of GDS length = (int)GribNumbers.uint3(raf); if (length == 42) { // Lambert/Mercator offset SupportClass.Skip(raf, 3); x = GribNumbers.int2(raf); y = GribNumbers.int2(raf); } else { SupportClass.Skip(raf, 7); length = (int)GribNumbers.uint3(raf); if (length == 32) { // Polar sterographic SupportClass.Skip(raf, 3); x = GribNumbers.int2(raf); y = GribNumbers.int2(raf); } else { x = y = 1; Console.Out.WriteLine("BDS constant value, can't determine array size"); } } Values = new float[x * y]; for (int i = 0; i < Values.Length; i++) { Values[i] = ref_Renamed; } } } } // end Grib1BinaryDataSection
// *** constructors ******************************************************* /// <summary> Constructs a <tt>Grib1ProductDefinitionSection</tt> object from a raf. /// /// </summary> /// <param name="raf">with PDS content /// /// </param> /// <throws> NotSupportedException if raf contains no valid GRIB file </throws> //UPGRADE_TODO: Class 'java.io.RandomAccessFile' was converted to 'System.IO.FileStream' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioRandomAccessFile'" internal Grib1ProductDefinitionSection(System.IO.Stream raf) { // octets 1-3 PDS length length = (int)GribNumbers.uint3(raf); // Paramter table octet 4 table_version = raf.ReadByte(); // Center octet 5 center_id = raf.ReadByte(); // octet 6 Generating Process - See Table A process_id = raf.ReadByte(); // octet 7 (id of grid type) - not supported yet grid_id = raf.ReadByte(); //octet 8 (flag for presence of GDS and BMS) int exists = raf.ReadByte(); //BKSystem.IO.BitStream s = new BKSystem.IO.BitStream(8); // s.WriteByte((byte)raf.ReadByte()); // s.Position = 0; // sbyte exists; // s.Read(out exists); // bms_exists = (exists & 64) == 64; gds_exists = (exists & 128) == 128; bms_exists = (exists & 64) == 64; // octet 9 (parameter and unit) parameterNumber = raf.ReadByte(); // octets 10-12 (level) int levelType = raf.ReadByte(); int levelValue1 = raf.ReadByte(); int levelValue2 = raf.ReadByte(); level = new GribPDSLevel(levelType, levelValue1, levelValue2); // octets 13-17 (base time for reference time) int year = raf.ReadByte(); int month = raf.ReadByte(); int day = raf.ReadByte(); int hour = raf.ReadByte(); int minute = raf.ReadByte(); // get info for forecast time // octet 18 Forecast time unit timeUnit = raf.ReadByte(); switch (timeUnit) { case 0: // minute tUnit = "minute"; break; case 1: // hours tUnit = "hour"; break; case 2: // day tUnit = "day"; break; case 3: // month tUnit = "month"; break; case 4: //1 year tUnit = "1year"; break; case 5: // decade tUnit = "decade"; break; case 6: // normal tUnit = "day"; break; case 7: // century tUnit = "century"; break; case 10: //3 hours tUnit = "3hours"; break; case 11: // 6 hours tUnit = "6hours"; break; case 12: // 12 hours tUnit = "12hours"; break; case 254: // second tUnit = "second"; break; default: Console.Error.WriteLine("PDS: Time Unit " + timeUnit + " is not yet supported"); break; } // octet 19 & 20 used to create Forecast time p1 = raf.ReadByte(); p2 = raf.ReadByte(); // octet 21 (time range indicator) timeRangeValue = raf.ReadByte(); // forecast time is always at the end of the range switch (timeRangeValue) { case 0: timeRange = "product valid at RT + P1"; forecastTime = p1; break; case 1: timeRange = "product valid for RT, P1=0"; forecastTime = 0; break; case 2: timeRange = "product valid from (RT + P1) to (RT + P2)"; forecastTime = p2; break; case 3: timeRange = "product is an average between (RT + P1) to (RT + P2)"; forecastTime = p2; break; case 4: timeRange = "product is an accumulation between (RT + P1) to (RT + P2)"; forecastTime = p2; break; case 5: timeRange = "product is the difference (RT + P2) - (RT + P1)"; forecastTime = p2; break; case 6: timeRange = "product is an average from (RT - P1) to (RT - P2)"; forecastTime = -p2; break; case 7: timeRange = "product is an average from (RT - P1) to (RT + P2)"; forecastTime = p2; break; case 10: timeRange = "product valid at RT + P1"; // p1 really consists of 2 bytes p1 and p2 forecastTime = p1 = GribNumbers.int2(p1, p2); p2 = 0; break; case 51: timeRange = "mean value from RT to (RT + P2)"; forecastTime = p2; break; default: Console.Error.WriteLine("PDS: Time Range Indicator " + timeRangeValue + " is not yet supported"); break; } // octet 22 & 23 int avgInclude = GribNumbers.int2(raf); // octet 24 int avgMissing = raf.ReadByte(); // octet 25 int century = raf.ReadByte() - 1; // octet 26, sub center subcenter_id = raf.ReadByte(); // octets 27-28 (decimal scale factor) decscale = GribNumbers.int2(raf); refTime = new DateTime(century * 100 + year, month, day, hour, minute, 0, DateTimeKind.Utc); baseTime = refTime; referenceTime = refTime.ToString(dateFormat); //(century * 100 + year) +"-" + //month + "-" + day + "T" + hour +":" + minute +":00Z" ); // TODO /* * parameter_table = GribPDSParamTable.getParameterTable(center_id, subcenter_id, table_version); * parameter = parameter_table.getParameter(parameterNumber); */ parameter = new Parameter(); if (center_id == 7 && subcenter_id == 2) { CustomData = new int[0]; // ensemble product epds = new Grib1Ensemble(raf, parameterNumber); } // Special handling of 2D Wave Spectra (single) else if (table_version == 140 && parameterNumber == 251) { CustomData = new int[0]; SupportClass.Skip(raf, 12); int extDef = raf.ReadByte(); // Extension definition // Read ECMWF extension for 2D wave spectra single if (extDef == 13) { waveSpectra2DDirFreq = new Grib1WaveSpectra2DDirFreq(raf); } } else { // Ignore reserved bytes 29-40 for (int i = 29; i <= Math.Min(length, 40); i++) { raf.ReadByte(); } // Try to read extra bytes CustomData = new int[Math.Max(length - 40, 0)]; for (int i = 0; i < CustomData.Length; i++) { CustomData[i] = raf.ReadByte(); } } } // end Grib1ProductDefinitionSection
} // end scan /// <summary> scans a Grib file to gather information that could be used to /// create an index or dump the metadata contents. /// /// </summary> /// <param name="getProducts">products have enough information for data extractions /// </param> /// <param name="oneRecord">returns after processing one record in the Grib file /// </param> /// <throws> NotSupportedException </throws> public IEnumerable <Grib1Record> scanRecords() { InputStream.Seek(0, SeekOrigin.Begin); // stores the number of times a particular GDS is used //UPGRADE_TODO: Class 'java.util.HashMap' was converted to 'System.Collections.Hashtable' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilHashMap'" System.Collections.Hashtable gdsCounter = new System.Collections.Hashtable(); Grib1ProductDefinitionSection pds = null; Grib1GridDefinitionSection gds = null; long startOffset = -1; while (InputStream.Position < InputStream.Length) { if (seekHeader(InputStream, InputStream.Length, out startOffset)) { // Read Section 0 Indicator Section Grib1IndicatorSection is_Renamed = new Grib1IndicatorSection(InputStream); // EOR (EndOfRecord) calculated so skipping data sections is faster long EOR = InputStream.Position + is_Renamed.GribLength - is_Renamed.Length; // Read Section 1 Product Definition Section PDS pds = new Grib1ProductDefinitionSection(InputStream); if (pds.LengthErr) { continue; } if (pds.gdsExists()) { // Read Section 2 Grid Definition Section GDS gds = new Grib1GridDefinitionSection(InputStream); } else { // GDS doesn't exist so make one gds = (Grib1GridDefinitionSection) new Grib1Grid(pds); } // obtain BMS or BDS offset in the file for this product long dataOffset; if (pds.Center == 98) { // check for ecmwf offset by 1 bug int length = (int)GribNumbers.uint3(InputStream); // should be length of BMS if ((length + InputStream.Position) < EOR) { dataOffset = InputStream.Position - 3; // ok } else { dataOffset = InputStream.Position - 2; } } else { dataOffset = InputStream.Position; } // position filePointer to EndOfRecord InputStream.Seek(EOR, System.IO.SeekOrigin.Begin); // assume scan ok Grib1Record gr = new Grib1Record(header, is_Renamed, pds, gds, dataOffset, InputStream.Position, startOffset); var currentPosition = InputStream.Position; yield return(gr); InputStream.Position = currentPosition; // early return because ending "7777" missing if (InputStream.Position > InputStream.Length) { InputStream.Seek(0, System.IO.SeekOrigin.Begin); checkGDSkeys(gds, gdsCounter); throw new BadGribFormatException("Grib1Input: GRIB ending missing. Possible file corruption"); } } // end if seekHeader } // end while raf.Position < raf.Length checkGDSkeys(gds, gdsCounter); } // end scan
/// <summary> scans a Grib file to gather information that could be used to /// create an index or dump the metadata contents. /// /// </summary> /// <param name="getProducts">products have enough information for data extractions /// </param> /// <param name="oneRecord">returns after processing one record in the Grib file /// </param> /// <throws> NotSupportedException </throws> public void scan(bool getProducts, bool oneRecord) { long start = (DateTime.Now.Ticks - 621355968000000000) / 10000; // stores the number of times a particular GDS is used //UPGRADE_TODO: Class 'java.util.HashMap' was converted to 'System.Collections.Hashtable' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilHashMap'" System.Collections.Hashtable gdsCounter = new System.Collections.Hashtable(); Grib1ProductDefinitionSection pds = null; Grib1GridDefinitionSection gds = null; long startOffset = -1; while (InputStream.Position < InputStream.Length) { if (seekHeader(InputStream, InputStream.Length, out startOffset)) { // Read Section 0 Indicator Section Grib1IndicatorSection is_Renamed = new Grib1IndicatorSection(InputStream); // EOR (EndOfRecord) calculated so skipping data sections is faster long EOR = InputStream.Position + is_Renamed.GribLength - is_Renamed.Length; // Read Section 1 Product Definition Section PDS pds = new Grib1ProductDefinitionSection(InputStream); if (pds.LengthErr) { continue; } if (pds.gdsExists()) { // Read Section 2 Grid Definition Section GDS gds = new Grib1GridDefinitionSection(InputStream); } else { // GDS doesn't exist so make one gds = (Grib1GridDefinitionSection) new Grib1Grid(pds); } // obtain BMS or BDS offset in the file for this product long dataOffset = 0; if (pds.Center == 98) { // check for ecmwf offset by 1 bug int length = (int)GribNumbers.uint3(InputStream); // should be length of BMS if ((length + InputStream.Position) < EOR) { dataOffset = InputStream.Position - 3; // ok } else { dataOffset = InputStream.Position - 2; } } else { dataOffset = InputStream.Position; } // position filePointer to EndOfRecord InputStream.Seek(EOR, System.IO.SeekOrigin.Begin); // assume scan ok if (getProducts) { Grib1Product gp = new Grib1Product(header, pds, getGDSkey(gds, gdsCounter), dataOffset, InputStream.Position); products.Add(gp); } else { Grib1Record gr = new Grib1Record(header, is_Renamed, pds, gds, dataOffset, InputStream.Position, startOffset); records.Add(gr); } if (oneRecord) { return; } // early return because ending "7777" missing if (InputStream.Position > InputStream.Length) { InputStream.Seek(0, System.IO.SeekOrigin.Begin); Console.Error.WriteLine("Grib1Input: possible file corruption"); checkGDSkeys(gds, gdsCounter); return; } } // end if seekHeader } // end while raf.Position < raf.Length // (System.currentTimeMillis()- start) + " milliseconds"); checkGDSkeys(gds, gdsCounter); return; } // end scan
/// <summary> Constructs a <tt>Grib1GridDefinitionSection</tt> object from a raf. /// /// </summary> /// <param name="raf">RandomAccessFile with GDS content /// /// </param> /// <throws> NoValidGribException if raf contains no valid GRIB info </throws> //UPGRADE_TODO: Class 'java.io.RandomAccessFile' was converted to 'System.IO.FileStream' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioRandomAccessFile'" internal Grib1GridDefinitionSection(System.IO.Stream raf) { int reserved; // used to read empty space // octets 1-3 (Length of GDS) length = (int)GribNumbers.uint3(raf); if (length == 0) { // there's a extra byte between PDS and GDS SupportClass.Skip(raf, -2); length = (int)GribNumbers.uint3(raf); } // TODO Fix Checksum stuff // get byte array for this gds, then reset raf to same position // calculate checksum for this gds via the byte array /* * long mark = raf.Position; * sbyte[] dst = new sbyte[length - 3]; * SupportClass.ReadInput(raf, dst, 0, dst.Length); * raf.Seek(mark, System.IO.SeekOrigin.Begin); * //UPGRADE_ISSUE: Class 'java.util.zip.CRC32' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javautilzipCRC32'" * //UPGRADE_ISSUE: Constructor 'java.util.zip.CRC32.CRC32' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javautilzipCRC32'" * CRC32 cs = new CRC32(); * //UPGRADE_ISSUE: Method 'java.util.zip.CRC32.update' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javautilzipCRC32'" * cs.update(dst); * //UPGRADE_ISSUE: Method 'java.util.zip.CRC32.getValue' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javautilzipCRC32'" * checksum = System.Convert.ToString(cs.getValue()); * */ // octets 4 NV int NV = raf.ReadByte(); // octet 5 PL the location (octet number) of the list of numbers of points in each row P_VorL = raf.ReadByte(); // octet 6 (grid type) type = raf.ReadByte(); name = getName(type); if (type != 50) { // values same up to resolution // octets 7-8 (Nx - number of points along x-axis) nx = GribNumbers.int2(raf); nx = (nx == -1) ? 1 : nx; // octets 9-10 (Ny - number of points along y-axis) ny = GribNumbers.int2(raf); ny = (ny == -1) ? 1 : ny; // octets 11-13 (La1 - latitude of first grid point) lat1 = GribNumbers.int3(raf) / 1000.0; // octets 14-16 (Lo1 - longitude of first grid point) lon1 = GribNumbers.int3(raf) / 1000.0; // octet 17 (resolution and component flags). See Table 7 resolution = raf.ReadByte(); } switch (type) { // Latitude/Longitude grids , Arakawa semi-staggered e-grid rotated // Arakawa filled e-grid rotated case 0: case 4: case 40: case 201: case 202: // octets 18-20 (La2 - latitude of last grid point) lat2 = GribNumbers.int3(raf) / 1000.0; // octets 21-23 (Lo2 - longitude of last grid point) lon2 = GribNumbers.int3(raf) / 1000.0; // octets 24-25 (Dx - Longitudinal Direction Increment ) dx = GribNumbers.int2(raf) / 1000.0; // octets 26-27 (Dy - Latitudinal Direction Increment ) // Np - parallels between a pole and the equator if (type == 4) { np = GribNumbers.int2(raf); } else { dy = GribNumbers.int2(raf) / 1000.0; } // octet 28 (Scanning mode) See Table 8 scan = raf.ReadByte(); // octet 29-32 reserved reserved = GribNumbers.int4(raf); if (length > 32) { // getP_VorL(raf); // Vertical coordinates (NV) and thinned grids (PL) not supported - skip this SupportClass.Skip(raf, length - 32); } break; // end Latitude/Longitude grids case 1: // Mercator grids // octets 18-20 (La2 - latitude of last grid point) lat2 = GribNumbers.int3(raf) / 1000.0; // octets 21-23 (Lo2 - longitude of last grid point) lon2 = GribNumbers.int3(raf) / 1000.0; // octets 24-26 (Latin - latitude where cylinder intersects the earth latin1 = GribNumbers.int3(raf) / 1000.0; // octet 27 reserved reserved = raf.ReadByte(); // octet 28 (Scanning mode) See Table 8 scan = raf.ReadByte(); // octets 29-31 (Dx - Longitudinal Direction Increment ) dx = GribNumbers.int3(raf); // octets 32-34 (Dx - Longitudinal Direction Increment ) dy = GribNumbers.int3(raf); // octet 35-42 reserved reserved = GribNumbers.int4(raf); reserved = GribNumbers.int4(raf); if (length > 42) { // getP_VorL(raf); // Vertical coordinates (NV) and thinned grids (PL) not supported - skip this SupportClass.Skip(raf, length - 42); } break; // end Mercator grids case 3: // Lambert Conformal // octets 18-20 (Lov - Orientation of the grid - east lon parallel to y axis) lov = GribNumbers.int3(raf) / 1000.0; // octets 21-23 (Dx - the X-direction grid length) See Note 2 of Table D dx = GribNumbers.int3(raf); // octets 24-26 (Dy - the Y-direction grid length) See Note 2 of Table D dy = GribNumbers.int3(raf); // octets 27 (Projection Center flag) See Note 5 of Table D proj_center = raf.ReadByte(); // octet 28 (Scanning mode) See Table 8 scan = raf.ReadByte(); // octets 29-31 (Latin1 - first lat where secant cone cuts spherical earth latin1 = GribNumbers.int3(raf) / 1000.0; // octets 32-34 (Latin2 - second lat where secant cone cuts spherical earth) latin2 = GribNumbers.int3(raf) / 1000.0; // octets 35-37 (lat of southern pole) latsp = GribNumbers.int3(raf) / 1000.0; // octets 38-40 (lon of southern pole) lonsp = GribNumbers.int3(raf) / 1000.0; // octets 41-42 reserved = GribNumbers.int2(raf); if (length > 42) { // getP_VorL(raf); // Vertical coordinates (NV) and thinned grids (PL) not supported - skip this SupportClass.Skip(raf, length - 42); } break; // end Lambert Conformal case 5: // Polar Stereographic grids // octets 18-20 (Lov - Orientation of the grid - east lon parallel to y axis) lov = GribNumbers.int3(raf) / 1000.0; // octets 21-23 (Dx - Longitudinal Direction Increment ) dx = GribNumbers.int3(raf); // octets 24-26(Dy - Latitudinal Direction Increment ) dy = GribNumbers.int3(raf); // octets 27 (Projection Center flag) See Note 5 of Table D proj_center = raf.ReadByte(); // octet 28 (Scanning mode) See Table 8 scan = raf.ReadByte(); // octet 29-32 reserved reserved = GribNumbers.int4(raf); if (length > 32) { // getP_VorL(raf); // Vertical coordinates (NV) and thinned grids (PL) not supported - skip this SupportClass.Skip(raf, length - 32); } break; // end Polar Stereographic grids default: Console.Out.WriteLine("Unknown Grid Type : " + type); break; } // end switch grid_type if ((scan & 63) != 0) { throw new BadGribFormatException("GDS: This scanning mode (" + scan + ") is not supported."); } } // end Grib1GridDefinitionSection( raf )