629 lines
17 KiB
Perl
629 lines
17 KiB
Perl
#!/usr/bin/perl -w
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Harvard University Atmospheric Chemistry Modeling Group !
|
|
#------------------------------------------------------------------------------
|
|
#BOP
|
|
#
|
|
# !MODULE: ncCodeRead
|
|
#
|
|
# !DESCRIPTION: This Perl script automatically creates a Fortran subroutine
|
|
# that reads data and attributes from a netCDF file. The Fortran subroutine
|
|
# (named READ\_FROM\_NETCDF\_FILE) contains calls to the proper NcdfUtilities
|
|
# library routines.
|
|
#\\
|
|
#\\
|
|
# !USES:
|
|
#
|
|
require 5.003; # Need this version of Perl or newer
|
|
use English; # Use English language
|
|
use Carp; # Get detailed error messages
|
|
use strict 'refs'; # Do not allow symbolic references
|
|
use strict 'subs'; # Treat all barewords as syntax errors
|
|
use StrTrim qw( &trim
|
|
&splitLine
|
|
&extractFile ); # Get string handling routines
|
|
#
|
|
# !PRIVATE MEMBER FUNCTIONS:
|
|
# &readRcFile($)
|
|
# &writeFortranVars($@)
|
|
# &writeFortranCalls($@)
|
|
#
|
|
# !PUBLIC MEMBER FUNCTIONS:
|
|
# &main()
|
|
#
|
|
# !PUBLIC DATA MEMBERS:
|
|
#
|
|
$F_ID = ""; # netCDF file ID
|
|
%F_DIMS = (); # Hash to store Fortran dim values
|
|
#
|
|
# !CALLING SEQUENCE:
|
|
# ncCodeCreate RESOURCE-FILE-NAME
|
|
#
|
|
# !REMARKS:
|
|
# Some hand-editing of the output Fortran subroutine may be necessary.
|
|
#
|
|
# !REVISION HISTORY:
|
|
# 30 Jan 2012 - R. Yantosca - Initial version
|
|
# 31 Jan 2012 - R. Yantosca - Minor edits for consistency
|
|
# 07 Mar 2012 - R. Yantosca - Minor fix, ignore comment lines
|
|
# 26 Mar 2012 - R. Yantosca - Now echo info about the file I/O to stdout
|
|
#EOP
|
|
#------------------------------------------------------------------------------
|
|
# Harvard University Atmospheric Chemistry Modeling Group !
|
|
#------------------------------------------------------------------------------
|
|
#BOP
|
|
#
|
|
# !IROUTINE: readRcFile
|
|
#
|
|
# !DESCRIPTION: Routine readRcFile reads the resource file which defines
|
|
# the variables and attributes to be written to the netCDF file.
|
|
#\\
|
|
#\\
|
|
# !INTERFACE:
|
|
#
|
|
sub readRcFile($) {
|
|
#
|
|
# !INPUT PARAMETERS:
|
|
#
|
|
# $fileName : Input file that describes the netCDF file
|
|
my ( $fileName ) = @_;
|
|
#
|
|
# !CALLING SEQUENCE:
|
|
# &readRcFile( RESOURCE-FILE-NAME );
|
|
#
|
|
# !REVISION HISTORY:
|
|
# 30 Jan 2012 - R. Yantosca - Initial version
|
|
# 07 Mar 2012 - R. Yantosca - Minor fix, ignore comment lines
|
|
#EOP
|
|
#------------------------------------------------------------------------------
|
|
#BOC
|
|
#
|
|
# !LOCAL VARIABLES:
|
|
#
|
|
my $cmdFile = "";
|
|
my $line = "";
|
|
my @lines = ();
|
|
my $name = "";
|
|
|
|
#--------------------------------------------------
|
|
# Read variable settings from the resource file
|
|
#--------------------------------------------------
|
|
open( I, "<$fileName" ) or die "Cannot open $fileName!\n";
|
|
chomp( @lines = <I> );
|
|
close( I );
|
|
|
|
#--------------------------------------------------
|
|
# Write Fortran commands to the output file
|
|
#--------------------------------------------------
|
|
|
|
# Pre-get a few quantities before creating the
|
|
# output file with the fortran code
|
|
foreach $line ( @lines ) {
|
|
|
|
# Skip comment lines
|
|
if ( !( substr( $line, 0, 1 ) eq '#' ) ) {
|
|
|
|
# Name of output file w/ Fortran code
|
|
if ( $line =~ 'Fortran Read File' ) {
|
|
( $name, $cmdFile ) = &splitLine( $line, '=' );
|
|
}
|
|
|
|
# NetCDF file ID (aka filehandle)
|
|
if ( $line =~ 'netCDF FileHandle' ) {
|
|
( $name, $F_ID ) = &splitLine( $line, '=' );
|
|
}
|
|
}
|
|
}
|
|
|
|
# Open the file that will ho
|
|
open( O, ">$cmdFile" ) or die "Cannot open $cmdFile\n";
|
|
|
|
# Pass thru @lines array so that we can declare Fortran variables
|
|
&writeFortranVars( \*O, @lines );
|
|
|
|
# Pass thru @lines array again to write
|
|
&writeFortranCalls( \*O, @lines );
|
|
|
|
#--------------------------------------------------
|
|
# Cleanup and quit
|
|
#--------------------------------------------------
|
|
|
|
# Close output file
|
|
close( O );
|
|
|
|
# Return
|
|
return( 0 );
|
|
}
|
|
#EOC
|
|
#------------------------------------------------------------------------------
|
|
# Harvard University Atmospheric Chemistry Modeling Group !
|
|
#------------------------------------------------------------------------------
|
|
#BOP
|
|
#
|
|
# !IROUTINE: writeFortranVars
|
|
#
|
|
# !DESCRIPTION: Routine writeFortranVars generates the proper Fortran
|
|
# variable declarations that are needed for use with the NcdfUtilities
|
|
# library routines.
|
|
#\\
|
|
#\\
|
|
# !INTERFACE:
|
|
#
|
|
sub writeFortranVars($@) {
|
|
#
|
|
# !INPUT PARAMETERS:
|
|
#
|
|
# $O : File handle
|
|
# @lines : Contents of the resource file
|
|
my ( $O, @lines ) = @_;
|
|
#
|
|
# !CALLING SEQUENCE:
|
|
# &writeFortranVars( \*O, @lines );
|
|
#
|
|
# !REVISION HISTORY:
|
|
# 30 Jan 2012 - R. Yantosca - Initial version
|
|
# 31 Jan 2012 - R. Yantosca - Minor edits for consistency
|
|
# 01 Feb 2012 - R. Yantosca - Fix typo in output ProTeX header
|
|
# 09 Jul 2012 - R. Yantosca - Now make fId a local variable
|
|
#EOP
|
|
#------------------------------------------------------------------------------
|
|
#BOC
|
|
#
|
|
# !LOCAL VARIABLES:
|
|
#
|
|
my @subStr = ();
|
|
my $name = "";
|
|
my $value = "";
|
|
my $varName = "";
|
|
my $varSize = "";
|
|
my $varType = "";
|
|
my $varDim = "";
|
|
my $nDims = "";
|
|
my @dims = ();
|
|
my $dimDef = "";
|
|
my $txt = "";
|
|
|
|
#-------------------------------------------------------
|
|
# Write USE statements
|
|
#-------------------------------------------------------
|
|
$txt .= <<EOF;
|
|
!EOC
|
|
!------------------------------------------------------------------------------
|
|
! Harvard University Atmospheric Chemistry Modeling Group !
|
|
!------------------------------------------------------------------------------
|
|
!BOP
|
|
!
|
|
! !IROUTINE: read\_from\_netcdf\_file
|
|
!
|
|
! !DESCRIPTION: Routine to read variables and attributes from a netCDF
|
|
! file. This routine was automatically generated by the Perl script
|
|
! NcdfUtilities/perl/ncCodeRead.
|
|
!\\\\
|
|
!\\\\
|
|
! !INTERFACE:
|
|
!
|
|
SUBROUTINE READ_FROM_NETCDF_FILE
|
|
!
|
|
! !USES:
|
|
!
|
|
! Modules for netCDF read
|
|
USE m_netcdf_io_open
|
|
USE m_netcdf_io_get_dimlen
|
|
USE m_netcdf_io_read
|
|
USE m_netcdf_io_readattr
|
|
USE m_netcdf_io_close
|
|
|
|
IMPLICIT NONE
|
|
|
|
\# include "netcdf.inc"
|
|
!
|
|
! !REMARKS:
|
|
! Assumes that you have:
|
|
! (1) A netCDF library (either v3 or v4) installed on your system
|
|
! (2) The NcdfUtilities package (from Bob Yantosca) source code
|
|
! .
|
|
! Although this routine was generated automatically, some further
|
|
! hand-editing may be required (i.e. to specify the size of parameters,
|
|
! and/or to assign values to variables. Also, you can decide how to handle
|
|
! the variable attributes (or delete calls for reading attributes that you
|
|
! do not need).
|
|
!
|
|
! !REVISION HISTORY:
|
|
! 30 Jan 2012 - R. Yantosca - Initial version
|
|
!EOP
|
|
!------------------------------------------------------------------------------
|
|
!BOC
|
|
!
|
|
! !LOCAL VARIABLES:
|
|
!
|
|
INTEGER :: $F_ID ! netCDF file ID
|
|
EOF
|
|
|
|
#-------------------------------------------------------
|
|
# Add spacer text to the file
|
|
#-------------------------------------------------------
|
|
$txt .= <<EOF;
|
|
!=================================================================
|
|
! Variable declarations
|
|
!=================================================================
|
|
|
|
EOF
|
|
|
|
# Loop thru the LINES array
|
|
for ( my $i=0; $i<scalar( @lines ); $i++ ) {
|
|
|
|
# Skip separator line
|
|
if ( $lines[$i] eq '#' ) {
|
|
# Do nothing
|
|
}
|
|
|
|
#----------------------------------------------------
|
|
# DIMENSIONS section
|
|
#----------------------------------------------------
|
|
elsif ( $lines[$i] =~ '!DIMENSIONS:' ) {
|
|
|
|
while ( $lines[++$i] ne '' ) {
|
|
|
|
# Get the dimension name and its value
|
|
( $name, $value ) = &splitLine( $lines[$i], '=' );
|
|
#
|
|
# Store the value in a hash under its name
|
|
$F_DIMS{$name} = $value;
|
|
}
|
|
}
|
|
|
|
#----------------------------------------------------
|
|
# VARIABLES section
|
|
#----------------------------------------------------
|
|
elsif ( $lines[$i] =~ '!VARIABLES:' ) {
|
|
|
|
# Add a comment
|
|
$txt .= " ! Data arrays\n";
|
|
|
|
while ( $lines[++$i] ne '' ) {
|
|
|
|
# Skip comment characters
|
|
if ( !( $lines[$i] =~ '#' ) ) {
|
|
|
|
# Split the line
|
|
( $name, $value ) = &splitLine( $lines[$i], '=' );
|
|
|
|
# If the name field does not have a semicolon
|
|
# then it is a variable name and not an attribute
|
|
if ( !( $name =~ ':' ) ) {
|
|
|
|
# Find the variable type and variable dimension(s)
|
|
( $varType, $varDim ) = &splitLine( $value, '::' );
|
|
if ( $varType =~ 'REAL' ) { $varType = "$varType "; }
|
|
|
|
# Get dimension information
|
|
@dims = split( ',', $varDim );
|
|
$nDims = scalar( @dims );
|
|
|
|
# Create the Fortran dimension string that is used to declare
|
|
# the variable, i.e. (IIPAR,JJPAR,1). Use the Perl hash %F_DIMS
|
|
# to refer to the correponding value for each netCDF dimension.
|
|
$dimDef = "(";
|
|
for ( my $i=0; $i<$nDims; $i++ ) {
|
|
while( my ( $key, $val ) = each( %F_DIMS ) ) {
|
|
if ( $key =~ $dims[$i] ) {
|
|
$dimDef .= "$val";
|
|
if ( $i < $nDims-1 ) { $dimDef .= ","; }
|
|
}
|
|
}
|
|
}
|
|
$dimDef .= ")";
|
|
|
|
# Definition string
|
|
$txt .= " $varType :: $name$dimDef\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
# OTHER VARIABLES section
|
|
#-------------------------------------------------------
|
|
$txt .= <<EOF2;
|
|
|
|
! Character strings
|
|
CHARACTER(LEN=255) :: nc_dir ! netCDF directory name
|
|
CHARACTER(LEN=255) :: nc_file ! netCDF file name
|
|
CHARACTER(LEN=255) :: nc_path ! netCDF path name
|
|
CHARACTER(LEN=255) :: v_name ! netCDF variable name
|
|
CHARACTER(LEN=255) :: a_name ! netCDF attribute name
|
|
CHARACTER(LEN=255) :: a_val ! netCDF attribute value
|
|
|
|
! Arrays for netCDF start and count values
|
|
INTEGER :: st1d(1), ct1d(1) ! For 1D arrays
|
|
INTEGER :: st2d(2), ct2d(2) ! For 2D arrays
|
|
INTEGER :: st3d(3), ct3d(3) ! For 3D arrays
|
|
INTEGER :: st4d(4), ct4d(4) ! For 4D arrays
|
|
INTEGER :: st5d(5), ct5d(5) ! For 5D arrays
|
|
INTEGER :: st6d(6), ct6d(6) ! For 6D arrays
|
|
EOF2
|
|
print $O "$txt\n";
|
|
|
|
# Return
|
|
return( 0 );
|
|
}
|
|
#EOC
|
|
#------------------------------------------------------------------------------
|
|
# Harvard University Atmospheric Chemistry Modeling Group !
|
|
#------------------------------------------------------------------------------
|
|
#BOP
|
|
#
|
|
# !IROUTINE: writeFortranCalls
|
|
#
|
|
# !DESCRIPTION: Routine writeFortranCalls generates the proper calls to the
|
|
# NcdfUtilities library routines for reading data from the netCDF file.
|
|
#\\
|
|
#\\
|
|
# !INTERFACE:
|
|
#
|
|
sub writeFortranCalls($@) {
|
|
#
|
|
# !INPUT PARAMETERS:
|
|
#
|
|
# $O : File handle
|
|
# @lines : Contents of the resource file
|
|
my ( $O, @lines ) = @_;
|
|
#
|
|
# !CALLING SEQUENCE:
|
|
# &writeFortranCalls( \*O, @lines );
|
|
#
|
|
# !REVISION HISTORY:
|
|
# 30 Jan 2012 - R. Yantosca - Initial version
|
|
# 31 Jan 2012 - R. Yantosca - Minor edits for consistency
|
|
# 26 Mar 2012 - R. Yantosca - Echo info about the file I/O to stdout
|
|
# 26 Mar 2012 - R. Yantosca - Now echo info about the file I/O to stdout
|
|
#EOP
|
|
#------------------------------------------------------------------------------
|
|
#BOC
|
|
#
|
|
# !LOCAL VARIABLES:
|
|
#
|
|
my $attName = "";
|
|
my $varName = "";
|
|
my $varDim = "";
|
|
my $varType = "";
|
|
my $ncDir = "";
|
|
my $ncFile = "";
|
|
my $ncPath = "";
|
|
my $nDims = "";
|
|
my $start = "";
|
|
my $count = "";
|
|
my @dims = ();
|
|
my $name = "";
|
|
my $value = "";
|
|
my $txt = "";
|
|
|
|
# Loop thru each line in the file
|
|
for ( my $i = 0; $i < scalar( @lines ); $i++ ) {
|
|
|
|
# Skip separator line
|
|
if ( $lines[$i] eq '#' ) {
|
|
# Do nothing
|
|
}
|
|
|
|
#----------------------------------------------------
|
|
# FILENAME section
|
|
#----------------------------------------------------
|
|
elsif ( $lines[$i] =~ '!FILENAME:' ) {
|
|
|
|
while ( $lines[++$i] ne '' ) {
|
|
|
|
if ( $lines[$i] =~ 'netCDF FileName' ) {
|
|
|
|
# Split the line on the equals sign
|
|
( $name, $value ) = &splitLine( $lines[$i], '=' );
|
|
|
|
# Full path name of file to read
|
|
$ncPath = $value;
|
|
|
|
# Split path into filename & directory parts
|
|
( $ncFile, $ncDir ) = &extractFile( $ncPath );
|
|
|
|
# Create string
|
|
$txt .= <<EOF;
|
|
!=================================================================
|
|
! Open and read data from the netCDF file
|
|
!=================================================================
|
|
|
|
! Open netCDF file
|
|
nc_path = '$ncPath'
|
|
CALL Ncop_Rd( $F_ID, TRIM(nc_path) )
|
|
|
|
! Echo info to stdout
|
|
nc_file = '$ncFile'
|
|
nc_dir = '$ncDir'
|
|
WRITE( 6, 100 ) REPEAT( '%', 79 )
|
|
WRITE( 6, 110 ) TRIM(nc_file)
|
|
WRITE( 6, 120 ) TRIM(nc_dir)
|
|
|
|
EOF
|
|
}
|
|
}
|
|
}
|
|
|
|
#----------------------------------------------------
|
|
# VARIABLES section
|
|
#----------------------------------------------------
|
|
elsif ( $lines[$i] =~ '!VARIABLES:' ) {
|
|
|
|
# Write fortran calls to define variables
|
|
while ( $lines[++$i] ne '' ) {
|
|
if ( !( $lines[$i] =~ '#' ) ) {
|
|
|
|
# Split the line on the equals sign
|
|
( $name, $value ) = &splitLine( $lines[$i], '=' );
|
|
|
|
#----------------------------------------------
|
|
# If the $name field has a semicolon,
|
|
# then it's a variable attribute
|
|
#----------------------------------------------
|
|
if ( $name =~ ':' ) {
|
|
|
|
# Split into the variable name and attribute name
|
|
( $varName, $attName ) = &splitLine( $name, ':' );
|
|
|
|
# Create the text
|
|
$txt .= <<EOF2;
|
|
! Read the $varName:$attName attribute
|
|
a_name = "$attName"
|
|
CALL NcGet_Var_Attributes( $F_ID,TRIM(v_name),TRIM(a_name),a_val )
|
|
|
|
EOF2
|
|
# Write info about the variable we are reading to stdout
|
|
if ( $attName =~ 'units' ) {
|
|
$txt .= <<EOF2a;
|
|
! Echo info to stdout
|
|
WRITE( 6, 130 ) TRIM(v_name), TRIM(a_val)
|
|
|
|
EOF2a
|
|
}
|
|
|
|
}
|
|
|
|
#--------------------------------------------
|
|
# If the $name field lacks a semicolon,
|
|
# then it's the variable name
|
|
#--------------------------------------------
|
|
else {
|
|
|
|
# Add spacer text
|
|
$txt .= " !----------------------------------------\n";
|
|
$txt .= " ! VARIABLE: $name\n";
|
|
$txt .= " !----------------------------------------\n\n";
|
|
|
|
# Find the variable type and variable dimension(s)
|
|
( $varType, $varDim ) = &splitLine( $value, '::' );
|
|
|
|
# Get dimension information
|
|
@dims = split( ',', $varDim );
|
|
$nDims = scalar( @dims );
|
|
|
|
# Write the variable name
|
|
$txt .= <<EOF3;
|
|
! Variable name
|
|
v_name = "$name"
|
|
|
|
EOF3
|
|
|
|
# Create the start array
|
|
$start = "st$nDims"."d";
|
|
$txt .= " ! Read $name from file\n";
|
|
$txt .= " $start = (/ ";
|
|
for ( my $j=0; $j<$nDims; $j++ ) {
|
|
$txt .= "1";
|
|
if ( $j < $nDims-1 ) { $txt .= ", "; }
|
|
}
|
|
$txt .= " /)\n";
|
|
|
|
# Create the count array
|
|
$count = "ct$nDims"."d";
|
|
$txt .= " $count = (/ ";
|
|
for ( my $j=0; $j<$nDims; $j++ ) {
|
|
while( my( $key, $val ) = each( %F_DIMS ) ) {
|
|
if ( $key =~ $dims[$j] ) {
|
|
$txt .= "$val";
|
|
if ( $j < $nDims-1 ) { $txt .= ", "; }
|
|
}
|
|
}
|
|
}
|
|
$txt .= " /)\n";
|
|
|
|
# Create the call to NcWr
|
|
$txt .= <<EOF4;
|
|
CALL NcRd( $name, $F_ID, TRIM(v_name), $start, $count )
|
|
|
|
EOF4
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#------------------------------------------------------
|
|
# Cleanup and quit
|
|
#------------------------------------------------------
|
|
|
|
# Closing text
|
|
$txt .= <<EOF5;
|
|
!=================================================================
|
|
! Cleanup and quit
|
|
!=================================================================
|
|
|
|
! Close netCDF file
|
|
CALL NcCl( $F_ID )
|
|
|
|
! Echo info to stdout
|
|
WRITE( 6, 140 )
|
|
WRITE( 6, 100 ) REPEAT( '%', 79 )
|
|
|
|
! FORMAT statements
|
|
100 FORMAT( a )
|
|
110 FORMAT( '%% Opening file : ', a )
|
|
120 FORMAT( '%% in directory : ', a, / , '%%' )
|
|
130 FORMAT( '%% Successfully read ', a, ' [', a, ']' )
|
|
140 FORMAT( '%% Successfully closed file!' )
|
|
|
|
END SUBROUTINE READ_FROM_NETCDF_FILE
|
|
!EOC
|
|
EOF5
|
|
|
|
# Write Fortran cmds to file
|
|
print $O "$txt\n";
|
|
|
|
# Return
|
|
return( 0 );
|
|
}
|
|
#EOC
|
|
#------------------------------------------------------------------------------
|
|
# Harvard University Atmospheric Chemistry Modeling Group !
|
|
#------------------------------------------------------------------------------
|
|
#BOP
|
|
#
|
|
# !IROUTINE: main
|
|
#
|
|
# !DESCRIPTION: Routine main is the driver routine for the ncCodeRead script.
|
|
#\\
|
|
#\\
|
|
# !INTERFACE:
|
|
#
|
|
sub main() {
|
|
#
|
|
# !CALLING SEQUENCE:
|
|
# &main();
|
|
#
|
|
# !REVISION HISTORY:
|
|
# 30 Jan 2012 - R. Yantosca - Initial version
|
|
#EOP
|
|
#------------------------------------------------------------------------------
|
|
#BOC
|
|
|
|
# Error check arguments
|
|
if ( scalar( @ARGV ) == 0 ) {
|
|
print "Usage: ncCodeRead RESOURCE-FILE\n";
|
|
exit(1);
|
|
}
|
|
|
|
# Read settings and create output files
|
|
&readRcFile( $ARGV[0] );
|
|
|
|
# Return normally
|
|
return( 0 );
|
|
}
|
|
#EOC
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
# Start main program
|
|
main();
|
|
|
|
# Exit normally
|
|
exit(0);
|