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

Re: Support: NetCDF/Perl interface question



On Mon, 10 Apr 2006, Steve Diggs wrote:

> Dear NetCDF Support Team,
>
> Sorry for the direct email, but I'm getting desperate.  I'm using the
> NetCDF/Perl interface and (in the simplest case) I'm writing out
> temperature data that should be dimensioned:
>
>       temperature(time,pressure,lat,lon)

Steve,

i modified your netcdf_test.pl program so it produces the results that you
wanted and attached it. the problem was that the dimensions were not
set correctly for the temperature variable and the data writing start
and count wasn't correct. the syntax in netcdf-perl can get confusing so
it's easy to have these type of problems.  also attached is another perl
script netcdfperl.example  that deals with char data that may be usefull.
you might want to consider using the netcdf-java package for your
programs because the netcdf-perl package will be sunsetted in the future
because of it's prone to coding errors.

robb...


>
> But I can only figure out how to use NetCDF::varput such that
> 'temperature' in only dependent on 'pressure':
>
>       temperature(pressure)
>
> This, obviously, is not compatible with the CF/COARDS conventions and I
> can't find enough documentation on the NetCDF/Perl interface to do what
> I really *need* to do.  I get a 'Bus Error' each time I try to mess
> with the start and count arrays.  I think that's where I'm not
> understanding what needs to be done.  Do they need to be
> multi-dimensional?  If so, how should they be structured and passed to
> 'varput'?
>
> To make it easier to uderstand where I'm having trouble, I wrote and
> attached a piece of code, that will (under Linux/Unix) produce a sample
> file which does what I >can< do.
>
> If possible, could the person(s) there in the know, make the necessary
> well-documented modifications to this short piece of code, such that
> the output file writes temperature like this:
>
>       temperature(time,pressure,lat,lon)
>
> If you'd  do this, I'll post it to the NetCDF list for other dense
> people like myself to follow.  This must be very trivial for you folks
> (I hope).
>
> Thanks so much,
> -Steve Diggs
> --
> Stephen C. Diggs
> Southwest Fisheries Science Center / FRD
> 8604 La Jolla Shores Drive
> La Jolla, California, USA 92037
> +1.858.546.7083
>

===============================================================================
Robb Kambic                                Unidata Program Center
Software Engineer III                      Univ. Corp for Atmospheric Research
address@hidden             WWW: http://www.unidata.ucar.edu/
===============================================================================
#!/usr/bin/perl -w

#
# --> example of how to use the Perl/NetCDF interface (S. Diggs: 2006)
#
use strict;
use NetCDF;

#my $output_filename = "output" . $$ . ".nc";
my $output_filename = "output" . ".nc";
my $current_time        = localtime();

#
#--> make some data
#
my @temperature_array   = reverse(10..20);
my @pressure_array              = (0,20,40,60,80,100,120,140,160,180,200);
my $obs_time                    = 986762700;
my $latitude                    =   30.518;
my $longitude                   = -122.258;

my $temperature_dimension       = ($#temperature_array+1);
my $pressure_dimension          = ($#pressure_array+1);

# --> open new NetCDF file
my $ncid        = NetCDF::create($output_filename, NetCDF::WRITE);

#--> dimension variables
#my $temperature_id     = NetCDF::dimdef($ncid, 'temperature', 
$pressure_dimension);
my $pressure_id         = NetCDF::dimdef($ncid, 'pressure', 
$pressure_dimension);
my $time_id                     = NetCDF::dimdef($ncid, 'time', 1);
my $lat_id                      = NetCDF::dimdef($ncid, 'latitude', 1);
my $lon_id                      = NetCDF::dimdef($ncid, 'longitude', 1);

#--> Global Attribute   
NetCDF::attput($ncid, NetCDF::GLOBAL, "file_creation_time", NetCDF::CHAR,
                $current_time);
                
#--> Data Attributes
my $varid_pressure      = 
        NetCDF::vardef($ncid, 'pressure',       NetCDF::FLOAT, $pressure_id);
        my $attid = NetCDF::attput($ncid, $varid_pressure, "long_name",
                        NetCDF::CHAR,'pressure');
        $attid = NetCDF::attput($ncid, $varid_pressure, "units", 
                        NetCDF::CHAR,"dbar");
        $attid = NetCDF::attput($ncid, $varid_pressure, "C_format", 
                        NetCDF::CHAR,"%f");     
                        
my $varid_latitude      = 
        NetCDF::vardef($ncid, 'latitude',       NetCDF::DOUBLE, $lat_id);
        $attid = NetCDF::attput($ncid, $varid_latitude, "long_name",
                        NetCDF::CHAR,"latitude");
        $attid = NetCDF::attput($ncid, $varid_latitude, "units", 
                        NetCDF::CHAR,"degrees_N");
        $attid = NetCDF::attput($ncid, $varid_latitude, "C_format", 
                        NetCDF::CHAR,"%9.4f");
                                                
my $varid_longitude     = 
        NetCDF::vardef($ncid, 'longitude',      NetCDF::DOUBLE, $lon_id);
        $attid = NetCDF::attput($ncid, $varid_longitude, "long_name",
                        NetCDF::CHAR,"longitude");
        $attid = NetCDF::attput($ncid, $varid_longitude, "units", 
                        NetCDF::CHAR,"degrees_E");
        $attid = NetCDF::attput($ncid, $varid_longitude, "C_format", 
                        NetCDF::CHAR,"%9.4f");
                        
my $varid_time  = 
        NetCDF::vardef($ncid, 'time',   NetCDF::LONG,   $time_id);
        $attid = NetCDF::attput($ncid, $varid_time, "long_name",
                        NetCDF::CHAR,"time");
        $attid = NetCDF::attput($ncid, $varid_time, "units", 
                        NetCDF::CHAR,"seconds since 1970-01-01 00:00:00");
        $attid = NetCDF::attput($ncid, $varid_time, "C_format", 
                        NetCDF::CHAR,"%10d");
                                
my $varid_temperature   = 
        NetCDF::vardef($ncid, 'temperature',    NetCDF::FLOAT, [ $time_id, 
$pressure_id, $lat_id, $lon_id ]);
        #NetCDF::vardef($ncid, 'temperature',   NetCDF::FLOAT, [ $time_id ]);
        $attid = NetCDF::attput($ncid, $varid_temperature, "long_name",
                        NetCDF::CHAR,'temperature');
        $attid = NetCDF::attput($ncid, $varid_temperature, "units", 
                        NetCDF::CHAR,"deg_C");
        $attid = NetCDF::attput($ncid, $varid_temperature, "C_format", 
                        NetCDF::CHAR,"%f");
                        
#--> END VARIABLE DEFINITIONS
NetCDF::endef($ncid); 
#NetCDF::close($ncid);
#exit 0;

#--> Write Variables
#
my @start                       = (0);
my @single                      = (1);
my @pressure_count      = ($pressure_dimension);

#--> WRITE DATA
my $result =
        NetCDF::varput($ncid, $varid_pressure,  \@start, \(@pressure_count),    
                 \@pressure_array );
                 
        #NetCDF::varput($ncid, $varid_temperature, \@start, \(@pressure_count),
$result =
        NetCDF::varput($ncid, $varid_temperature, [0,0,0,0], [1,11,1,1],
                 \@temperature_array );

$result =
        NetCDF::varput($ncid, $varid_latitude,  \@start, \@single,      
                ($latitude));

$result =
        NetCDF::varput($ncid, $varid_longitude, \@start, \@single,      
                ($longitude));

$result =
        NetCDF::varput($ncid, $varid_time,      \@start, \@single,      
                ($obs_time));
                 
#--> END NETCDF FILE
NetCDF::close($ncid);
#!/opt/bin/perl
  use NetCDF ;
  $ncid   = NetCDF::create("demo.nc", NetCDF::CLOBBER ) ;
  $dimid = NetCDF::dimdef($ncid, 'recNum', NetCDF::UNLIMITED);
  $stadim = NetCDF::dimdef($ncid,"stations",10) ;
  $strlen = 10 ;
  $strdim = NetCDF::dimdef($ncid,"strlen", $strlen) ;
  $varid  = NetCDF::vardef($ncid,"station",NetCDF::CHAR,[$dimid,$strdim]);
  NetCDF::endef($ncid) ;

  @names = ( "abcdef", "ABCDEF","A", "B", "C", "D", "E", "F", "G", "H" ) ;
  for ($i = 0 ; $i < 10 ; $i++ ) {
      $names[ $i ] = padstr( $names[ $i ], $strlen ) ;
      NetCDF::varput( $ncid, $varid, [$i,0], [1, $strlen], \$names[ $i ] ) ;
      #NetCDF::varput( $ncid, $varid, [$i,0], [1,10], "??????????" ) ;
      }

  #NetCDF::varput( $ncid, $varid, [3,2], [2,7], \@names ) ;

  NetCDF::close($ncid) ;

        
# pad str to correct length
sub padstr
{
( $str, $len ) = @_ ;

my( $size, $i ) ;

$size = length( $str ) ;

for( $i = $size; $i < $len; $i++ ) {
        $str .= "\0" ;
        #print "$str,\n" ;
}
if( $size > $len ) {
        print STDOUT "String length is over $len chars long:\n $str\n" ;
        $str = substr( $str, 0, $len ) ;
        #exit 0 ;
}
return $str ;
}
__END__

And this is what I get from ncdump:

ncdump demo.nc
netcdf demo {
dimensions:
        recNum = UNLIMITED ; // (10 currently)
        stations = 10 ;
        strlen = 10 ;
variables:
        char station(recNum, strlen) ;
data:

 station =
  "abcdef",
  "ABCDEF",
  "A",
  "B",
  "C",
  "D",
  "E",
  "F",
  "G",
  "H" ;
}