[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[netCDF #AOX-617597]: 2D character string array (Fortran 90)



Ruslan,

> The array I'm trying to store to netCDF file is declared in Fortran as:
> character(35) :: array(700,100).
> What should it like in CDL syntax?
> 
> I use pre-existing CDL file from which I generate netCDF file and
> where I write data to.  I tried to use the following:
>  
> netcdf test {
> dimensions:
>     Dim1 = 700 ;
>     Dim2 = 100 ;
>     Dim3 = 20 ;
> variables:
>     char Var1(Dim1, Dim3, Dim2) ;
> data: .
> 
> and:
> status=NF_PUT_VARA_TEXT(ncid,var_id,(/1,1,1/),(/700,20,100/),array)
>  
> But data section looks messy (multiple '\000' symbols instead of data).
> If I don't include Dim3 it stores only first letter of each array element.

The CDL dimension order is the C order, in which the last dimension
varies fastest and the first dimension variews most slowly.  In
Fortran uses the opposite order, in which the first dimension varies
fastes and the last most slowly.

So for a Fortran array declared like:

  character(35) :: array(700,100)

and assuming you only want 20 characters in the netCDF file rather
than the 35 character length you have in your program, the
corresponding CDL would be

  netcdf test {
  dimensions:
          Dim1 = 100 ;
          Dim2 = 700 ;
          Dim3 = 20 ;
  variables:
          char Var1(Dim1, Dim2, Dim3) ;
  data:
    ...
  }

If you made Dim3=35 to match your in-memory character string length,
the NF_PUT_VARA_TEXT call would be pretty easy:

  status=NF_PUT_VARA_TEXT(ncid,var_id,(/1,1,1/),(/35,700,100/),array)

but apparently you only want to write the subarray of the first 20
characters of each string into the netCDF file, skipping over the last
15 characters for each array value.  That makes it trickier, and you
have to instead use the NF_PUT_VARM_TEXT call, providing more
arguments to tell how much to skip along each in-memory dimension to
get to the next element along that dimension:

  status = nf_put_varm_text(ncid, var_id, (/1,1,1/), (/35,700,100/), 
 *                          (/1,1,1/), (/1,35,35*700/), array)

I've appended a small F77 example program illustrating this with a
3x2x20 array instead of your 700x100x20 array.  It creates a netCDF
file that has strings of length 20 and also shows that a string of
length 35 gets truncated when written in the file.  You should be able
to modify this example to get it working the way you want.

When I compile and run the program, it creates a netCDF file that
looks like this in ncdump:

  netcdf test {
  dimensions:
          Dim1 = 3 ;
          Dim2 = 2 ;
          Dim3 = 20 ;
  variables:
          char Var1(Dim1, Dim2, Dim3) ;
  data:

   Var1 =
    "string A, length 20.",
    "string B, length 20.",
    "string C, length 20.",
    "string D, length 20.",
    "string E, length 20.",
    "Here is F string 35 " ;
  }

--Russ

Russ Rew                                         UCAR Unidata Program
address@hidden                     http://www.unidata.ucar.edu



Ticket Details
===================
Ticket ID: AOX-617597
Department: Support netCDF
Priority: Normal
Status: Closed
      program chartst
      include 'netcdf.inc'
      integer ncid, var1id, dim1id, dim2id, dim3id
      integer ndims
      parameter(NDIMS = 3)
      parameter(LEN1 = 3, LEN2 = 2, LEN3 = 20)
      integer dimids(NDIMS), start(NDIMS), count(NDIMS)
      integer stride(NDIMS), amap(NDIMS)
      integer status
      character*35 :: array(LEN1,LEN2)
      data array /
     *            "string A, length 20.",
     *            "string B, length 20.",
     *            "string C, length 20.",
     *            "string D, length 20.",
     *            "string E, length 20.",
     *            "Here is F string 35 characters long"
     *            /

      status = nf_create('test.nc', nf_clobber, ncid)
                        if(status .ne. nf_noerr) then
                           print *, nf_strerror(status)
                           stop 1
                        endif
      status = nf_def_dim(ncid, 'Dim1', LEN1, dim1id)
                        if(status .ne. nf_noerr) then
                           print *, nf_strerror(status)
                           stop 1
                        endif
      status = nf_def_dim(ncid, 'Dim2', LEN2, dim2id)
                        if(status .ne. nf_noerr) then
                           print *, nf_strerror(status)
                           stop 1
                        endif
      status = nf_def_dim(ncid, 'Dim3', LEN3, dim3id)
                        if(status .ne. nf_noerr) then
                           print *, nf_strerror(status)
                           stop 1
                        endif
      dimids(1) = dim3id
      dimids(2) = dim2id
      dimids(3) = dim1id
      status = nf_def_var(ncid, 'Var1', nf_char, NDIMS, dimids, var1id)
                        if(status .ne. nf_noerr) then
                           print *, nf_strerror(status)
                           stop 1
                        endif
      status = nf_enddef(ncid)
                        if(status .ne. nf_noerr) then
                           print *, nf_strerror(status)
                           stop 1
                        endif

      start(1) = 1
      start(2) = 1
      start(3) = 1
      count(1) = LEN3
      count(2) = LEN2
      count(3) = LEN1
      stride(1) = 1
      stride(2) = 1
      stride(3) = 1
      amap(1) = 1
      amap(2) = 35
      amap(3) = 35*LEN2
c      status = nf_put_vara_text(ncid, var1id, start, count, array)
c                   if(status .ne. nf_noerr) then
c                          print *, nf_strerror(status)
c                          stop 1
c                       endif
      status = nf_put_varm_text(ncid, var1id, start, count, 
     *                          stride, amap, array)
                        if(status .ne. nf_noerr) then
                           print *, nf_strerror(status)
                           stop 1
                        endif
      status = nf_close(ncid)
                        if(status .ne. nf_noerr) then
                           print *, nf_strerror(status)
                           stop 1
                        endif
      end