#!/usr/bin/env perl # # mknoocnmap.pl Erik Kluzek # Dec/07/2011 # # Create SCRIP grid and mapping files for a single-point or region # that is assumed to be a land land-only region. # use Cwd; use strict; use English; use IO::File; use Getopt::Long; # # Global constants # my $degsiz = 0.1; #----------------------------------------------------------------------------------------------- # Set the directory that contains this scripts. If the command was issued using a # relative or absolute path, that path is in $ProgDir. Otherwise assume the # command was issued from the current working directory. (my $ProgName = $0) =~ s!(.*)/!!; # name of this script my $ProgDir = $1; # name of directory containing this script -- may be a # relative or absolute path, or null if the script # is in # the user's PATH my $cmdline = "@ARGV"; # Command line arguments to script my $cwd = getcwd(); # current working directory my $scrdir; # absolute pathname of directory that contains this script my $nm = "${ProgName}::"; # name to use if script dies if ($ProgDir) { $scrdir = absolute_path($ProgDir); } else { $scrdir = $cwd; } #----------------------------------------------------------------------------------------------- sub usage { die < Center latitude,longitude of the grid to create. -name [-or -n] Name to use to describe point OPTIONS -dx Size of total grid in degrees in longitude direction (default is $degsiz) -dy Size of total grid in degrees in latitude direction (default is $degsiz) -silent [or -s] Make output silent -help [or -h] Print usage to STDOUT. -verbose [or -v] Make output more verbose. -nx Number of longitudes (default is 1) -ny Number of latitudes (default is 1) EOF } #----------------------------------------------------------------------------------------------- sub get_latlon { # # Return the latitude and longitude of the input string and validate it # my $string = shift; my $desc = shift; my $dx = shift; my $dy = shift; my $lat = undef; my $lon = undef; my $valreal1 = "[+-]?[0-9]*\.?[0-9]*[EedDqQ]?[0-9+-]*"; if ( $string =~ /^($valreal1)\s*,\s*($valreal1)$/ ) { $lat = $1; $lon = $2; } else { die <<"EOF"; ** $ProgName - Error in entering latitude/longitude for $desc ** EOF } if ( $dx <= 0.0 || $dx > 360. ) { die <<"EOF"; ** $ProgName - Bad value for dx (=$dx) for $desc ** } if ( $dy <= 0.0 || $dy > 180. ) { die <<"EOF"; ** $ProgName - Bad value for dy (=$dy) for $desc ** } if ( ($lat < -90.+$dy/2.0) || ($lat > 90.0-$dy/2.0) ) { die <<"EOF"; ** $ProgName - Bad value for latitude (=$lat) for $desc ** EOF } if ( ($lon < $dx/2.0) || ($lon > 360.0-$dx/2.0) ) { die <<"EOF"; ** $ProgName - Bad value for longitude (=$lat) for $desc ** EOF } return( $lat, $lon ); } #------------------------------------------------------------------------------- sub absolute_path { # # Convert a pathname into an absolute pathname, expanding any . or .. characters. # Assumes pathnames refer to a local filesystem. # Assumes the directory separator is "/". # my $path = shift; my $cwd = getcwd(); # current working directory my $abspath; # resulting absolute pathname # Strip off any leading or trailing whitespace. (This pattern won't match if # there's embedded whitespace. $path =~ s!^\s*(\S*)\s*$!$1!; # Convert relative to absolute path. if ($path =~ m!^\.$!) { # path is "." return $cwd; } elsif ($path =~ m!^\./!) { # path starts with "./" $path =~ s!^\.!$cwd!; } elsif ($path =~ m!^\.\.$!) { # path is ".." $path = "$cwd/.."; } elsif ($path =~ m!^\.\./!) { # path starts with "../" $path = "$cwd/$path"; } elsif ($path =~ m!^[^/]!) { # path starts with non-slash character $path = "$cwd/$path"; } my ($dir, @dirs2); my @dirs = split "/", $path, -1; # The -1 prevents split from stripping trailing nulls # This enables correct processing of the input "/". # Remove any "" that are not leading. for (my $i=0; $i<=$#dirs; ++$i) { if ($i == 0 or $dirs[$i] ne "") { push @dirs2, $dirs[$i]; } } @dirs = (); # Remove any "." foreach $dir (@dirs2) { unless ($dir eq ".") { push @dirs, $dir; } } @dirs2 = (); # Remove the "subdir/.." parts. foreach $dir (@dirs) { if ( $dir !~ /^\.\.$/ ) { push @dirs2, $dir; } else { pop @dirs2; # remove previous dir when current dir is .. } } if ($#dirs2 == 0 and $dirs2[0] eq "") { return "/"; } $abspath = join '/', @dirs2; return( $abspath ); } #------------------------------------------------------------------------------- # Process command-line options my %opts = ( ctr => undef, help => undef, name => undef, nx => 1, ny => 1, dx => $degsiz, dy => $degsiz, silent => 0, verbose => 0, ); GetOptions( "p|centerpoint=s" => \$opts{'ctr'}, "n|name=s" => \$opts{'name'}, "nx=i" => \$opts{'nx'}, "ny=i" => \$opts{'ny'}, "dx=f" => \$opts{'dx'}, "dy=f" => \$opts{'dy'}, "h|help" => \$opts{'help'}, "s|silent" => \$opts{'silent'}, "v|verbose" => \$opts{'verbose'}, ) or usage(); # Check for unparsed arguments if (@ARGV) { print "ERROR: unrecognized arguments: @ARGV\n"; usage(); } if ( $opts{'verbose'} && $opts{'silent'} ) { print "ERROR: Can NOT set both silent and verbose at once!\n"; usage(); } my $printlev; if ( $opts{'verbose'} ) { $printlev = 2; } elsif ( $opts{'silent'} ) { $printlev = 0; } else { $printlev = 1; } if ( ! defined($opts{'ctr'}) ) { print "ERROR: MUST set the center point\n"; usage(); } if ( ! defined($opts{'name'}) ) { print "ERROR: MUST set the name of the point\n"; usage(); } my $name = $opts{'name'}; my ($lat,$lon) = get_latlon( $opts{'ctr'}, $name, $opts{'dx'}, $opts{'dy'} ); my $S_lat = $lat - $opts{'dy'}/2.0; my $N_lat = $lat + $opts{'dy'}/2.0; my $W_lon = $lon - $opts{'dx'}/2.0; my $E_lon = $lon + $opts{'dx'}/2.0; my $nx = $opts{'nx'}; my $ny = $opts{'ny'}; if ( $opts{'nx'} < 1 ) { print "ERROR: nx MUST be greater than or equal to 1\n"; usage(); } if ( $opts{'ny'} < 1 ) { print "ERROR: ny MUST be greater than or equal to 1\n"; usage(); } #----------------------------------------------------------------------------------------------- my $print; if ( $printlev > 1 ) { $print = "PRINT=TRUE"; } # Creation date my $cdate = `date +%y%m%d`; chomp( $cdate ); if ( $printlev > 0 ) { print "\n\nCreate SCRIP grid and mapping files for a single-point\n"; } # land grid... my $GITDES = `cd $scrdir; git describe; cd -`; $GITDES =~ s/\n//g; my $grddir = absolute_path( "$scrdir/../mkmapgrids" ); my $cwd = getcwd(); my $datdir = $grddir; if ( $cwd ne $scrdir ) { $datdir = $cwd; } my $grid1 = "$datdir/SCRIPgrid_${name}_nomask_c${cdate}.nc"; my $cmdenv = "env S_LAT=$S_lat W_LON=$W_lon N_LAT=$N_lat E_LON=$E_lon " . "NX=$nx NY=$ny PTNAME=$name GITDES=$GITDES $print "; my $cmd = "$cmdenv GRIDFILE=$grid1 ncl $scrdir/../mkmapgrids/mkscripgrid.ncl"; if ( $printlev > 0 ) { print "Create land SCRIP gridfile\n"; print "Execute: $cmd\n"; } system( $cmd ); # ocean grid... my $grid2 = "$datdir/SCRIPgrid_${name}_noocean_c${cdate}.nc"; my $cmd = "$cmdenv GRIDFILE=$grid2 IMASK=0 ncl $scrdir/../mkmapgrids/mkscripgrid.ncl"; if ( $printlev > 0 ) { print "Create ocean SCRIP gridfile\n"; print "Execute: $cmd\n"; } system( $cmd ); # Now create a unity mapping between the two... # Note reversal of grid1 & grid2, because we want an ocean -> land # mapping file my $mapfile = "$datdir/map_${name}_noocean_to_${name}_nomask_aave_da_${cdate}.nc"; my $cmd = "env GRIDFILE1=$grid2 GRIDFILE2=$grid1 MAPFILE=$mapfile " . "GITDES=$GITDES $print ncl $scrdir/mkunitymap.ncl"; if ( $printlev > 0 ) { print "Create unity mapping file between the two gridfile\n"; print "Execute: $cmd\n"; } system( $cmd ); if ( $printlev > 0 ) { print "\n\nSuccessfully created grid/mapping files for single-point\n"; }