Dear netcdf users:
Does anyone out there have experience reading netcdf files via VB6?
I'm developing a VB6 application that will provide precipitation,
temperature and
crop evapotranspiration data over the Ogallala aquifer region. The
meteorological data I'm using is
daily U.S. Historical Climatology Network Data from 135 meteorological
stations during 1971-2000.
This data was loaded into a netcdf file called 'OGDATA.NC' on a Linux
workstation.
I then installed the Win32 netcdf.dll, and the ncgen, and ncdump (ver
3.6.1) utilities
on a PC running Windows XP. When I transferred OGDATA.NC to the Windows
box
and dumped it via ncdump everything seems OK.
Results for ncdump -c OGDATA.NC
netcdf OGDATA {
dimensions:
DAYS = 365 ;
YEAR = 30 ;
STATIONS = 135 ;
nchar6 = 6 ;
variables:
short TMAX(STATIONS, YEAR, DAYS) ;
short TMIN(STATIONS, YEAR, DAYS) ;
short DPCP(STATIONS, YEAR, DAYS) ;
float latitude(STATIONS) ;
float longitude(STATIONS) ;
int elevation(STATIONS) ;
char StationID(STATIONS, nchar6) ;
data:
}
After poking around the Unidata netcdf web site and googling 'netcdf and
VB6'
I found Carsten Wieczorrek's web page
(http://www.mn-net.com/tabid/10844/default.aspx ),
which describes some problems and fixes for reading netcdf files via VB6
code.
According to my reading of this web page, VB6 arrays such as the corner
and edge array arguments
to nectdf functions contain additional header bytes for every dimension
and are not suitable for the
Win32 netcdf dll. From that page:
" ...netcdf.dll requires dimids as C-array (4 bytes for every element).
The VB-array dimids() contains some header bytes for every dimension and
they are not suitable for the dll...".
A fix is proposes where multi-element long integer arrays are handled as
strings.
"... A C-long variable contains four bytes. So your string needs 4 bytes
for every array-element. For example, your variable is two-dimensional
with the varids Variable_1_ID = 3 and Variable_2_ID = 5. The bits in a
long variable with value = 3 are equal to
11000000 | 00000000 | 00000000 | 00000000
and that is equal to a 4 byte string with character(3) & character(0) &
character(0) & character(0)..."
I'm a little unclear on this, as character(0) in the ascii set maps to
Decimal 48, which should be (?)
00001100 | 00000000 | 00000000 | 00000000 in binary
Maybe I'm not accounting for endian-ness. At any rate, I've tried this
fix in the following code but it doesn't seem to be working.
I've found that I can open the file, and retrieve the file and variable
ID numbers. But when I try to read just the array containing the
latitudes of the stations I just get 0's as output. My stripped down
VB6 test code is as follows:
------------------------------------------------------------------------
-------------------------
' VB6 code to test read OGDATA.NC
Option Explicit
'nc_open /* open existing netCDF dataset */
Private Declare Function nc_open "netcdf.dll" _
(ByVal path As String, ByVal mode As Long, ByRef ncid As Long) As Long
'nc_inq_varid /* get variable IDs */
Private Declare Function nc_inq_varid Lib "netcdf.dll" _
(ByVal ncid As Long, ByVal name As String, ByRef varid As Long) As Long
' nc_get_vara_float with string edges and corner array arguments...
'Private Declare Function nc_get_vara_float Lib "netcdf.dll" _
(ByVal ncid As Long, ByVal varid As Long, ByVal corner As String, ByVal
edges As String, ByRef ip As Single) As Long
'nc_close /* close netCDF dataset */
Private Declare Function nc_close Lib "netcdf.dll" (ByRef ncid As Long)
As Long
Const ndays As Integer = 365
Const nyrs As Integer = 30 ' 1971-2000 in OGDATA.NC
Const nsta As Integer = 135
Const ndim As Integer = 3
Dim ncid As Long
Dim lon_id As Long
Dim lat_id As Long
Dim elev_id As Long
Dim stn_id As Long
Dim dpcp_id As Long
Dim tmin_id As Long
Dim tmax_id As Long
Dim ista As Long
Dim lon(1 To nsta) As Single
Dim corner(1 To 3) As Long
Dim edges(1 To 3) As Long
Public Sub Form_Load()
Open "test_netcdf.txt" For Output As #1
Infile = "OGDATA.NC"
On Error Resume Next
res = nc_open(Infile, 0, ncid)
On Error Resume Next
res = nc_inq_varid(ncid, "latitude", lat_id)
On Error Resume Next
res = nc_inq_varid(ncid, "longitude", lon_id)
On Error Resume Next
res = nc_inq_varid(ncid, "elevation", elev_id)
On Error Resume Next
res = nc_inq_varid(ncid, "StationID", stn_id)
On Error Resume Next
res = nc_inq_varid(ncid, "DPCP", dpcp_id)
On Error Resume Next
res = nc_inq_varid(ncid, "TMIN", tmin_id)
On Error Resume Next
res = nc_inq_varid(ncid, "TMAX", tmax_id)
Write #1, "Lat_ID " & lat_id
Write #1, "Lon_ID " & lon_id
Write #1, "Elev_ID " & elev_id
Write #1, "Sta_ID " & stn_id
Write #1, "DPCP_ID " & dpcp_id
Write #1, "TMIN_ID " & tmin_id
Write #1, "TMAX_ID " & tmax_id
Write #1, " "
' This corner & edges scheme was adopted from
' Carsten Wieczorrek's web page...
corner_1_val = 1
corner1 = Chr(corner_1_val) & Chr(0) & Chr(0) & Chr(0)
edges_1_val = nsta
edges1 = Chr(edges_1_val) & Chr(0) & Chr(0) & Chr(0)
On Error Resume Next
Call nc_get_vara_float(ncid, lon_id, corner1, edges1, lon(1))
For ista = 1 To nsta '
Print #1, "--- "; Format(ista, "####"); lon(ista)
Next ista
On Error Resume Next
res = nc_close(ncid)
End Sub
'-----------------------------------------------------------------------
-------------------------
This code produces the following output in test_netcdf.txt
"Lat_ID 3"
"Lon_ID 4"
"Elev_ID 5"
"Sta_ID 6"
"DPCP_ID 2"
"TMIN_ID 1"
"TMAX_ID 0"
" "
--- 1 0
--- 2 0
--- 3 0
--- 4 0
--- 5 0
--- 6 0
--- 7 0
--- 8 0
--- 9 0
--- 10 0
--- 11 0
--- 12 0
--- 13 0
--- 14 0
--- 15 0
--- 16 0
...
...
--- 135 0
------------------------------------------------------------------------
-----------------------
Clearly something is wrong there... So going back to the Unidata
archives I
Saw another post by Matthew Hanna ("Index mapping for VB6") where it
seemed that this
fix of substituting character strings for arrays was unnecessary....
In that post you'll find:
> Public Declare Function nc_get_varm_double Lib "netcdf.dll" (ByVal
ncid
> As Long, ByVal varid As Long, ByRef startp As Long, ByRef countp As
> Long, ByRef stridep As Long, ByRef imapp As Long, ByRef ip As Double)
As
> Long
> NcErr = nc_get_varm_double(fHandle, var_id, dims(1), count(1),
> stride(1), imap(1), dblArray(1, 1))
> If NcErr <> 0 Then GoTo NcErrOut
So I went ahead and gave that approach a try in my test VB6 code by
making the following changes...
'nc_get_var_long /* get arrays of floating point */
Private Declare Function nc_get_vara_float Lib "netcdf.dll" _
(ByVal ncid As Long, ByVal varid As Long, ByRef corner_p As Long, ByRef
edges_p As Long, ByRef fl_p As Single) As Long
corner(1) = 1
edges(1) = nsta
On Error Resume Next
Call nc_get_vara_float(ncid, lon_id, corner(1), edges(1), lon(1))
This produced the same results as found above. Can anyone with netcdf +
VB6 experience see what I'm doing wrong?
Thanks in Advance for any Advice,
Steve Mauget