clm5/tools/mkprocdata_map/mkprocdata_map_wrap
2024-05-09 15:14:01 +08:00

251 lines
8.9 KiB
Bash

#!/bin/bash
# This script is a wrapper around mkprocdata_map that runs that
# program and then copies some additional variables from the template
# file to the output file. It also does some additional pre and
# post-processing in order to create some additional variables.
# Created by Bill Sacks, 5-25-11
# ----------------------------------------------------------------------
# SET PARAMETERS HERE
# ----------------------------------------------------------------------
# comma-delimited list of extra variables to copy directly from
# template file; note that these variables should not be written out
# by mkprocdata_map (i.e., everything in this list should be listed in
# the 'ignore_var' function in mkprocdata_map.F90); however, there may
# be some variables in the 'ignore_var' function that are not listed
# here - e.g., variables that we treat specially.
copy_vars="lon,lat"
# comma-delimited list of extra variables to copy from the template
# file if the -l option is specified -- this option says to copy
# landfrac and related variables. Note that some of these variables
# may be written out by mkprocdata_map, in which case they will be
# overwritten afterwards (slighly less efficient, but that keeps
# things simpler).
landfrac_copy_vars="landfrac,landmask,pftmask"
# name of the executable;
# expected to be in the same directory as this script unless -e option is given
executable="mkprocdata_map"
# minimum value for regridded pftmask variable for the output variable to be 1
pftmask_min="1.e-6"
# fill value for landmask
landmask_fill=-9999
# ----------------------------------------------------------------------
# LOCAL FUNCTIONS DEFINED HERE
# ----------------------------------------------------------------------
function Usage {
script_name=`basename $0`
echo "Usage: $script_name -i input_file -o output_file -m map_file -t template_file [-e executable-path] [-h] [-l]"
echo ""
echo "This script runs mkprocdata_map with the given arguments (-i, -o, -m and -t),"
echo "then copies some additional variables from the template file"
echo "to the output file. It also does some additional pre and"
echo "post-processing in order to create some additional variables."
echo ""
echo "Additional optional arguments:"
echo ""
echo "[-e executable-path]: Gives the path of the mkprocdata_map executable."
echo " If not specified, the executable is assumed to be"
echo " in the same directory as this script."
echo ""
echo "[-h]: Print this help message and exit"
echo ""
echo "[-l]: Rather than computing landfrac and related variables"
echo "by regridding the input file, instead copy these variables"
echo "directly from the template file. The variables this pertains"
echo "to are:"
echo $landfrac_copy_vars
}
# This function operates on a single variable in a file, changing all
# places where that variable is missing to some new (non-missing)
# value. The _FillValue attribute remains unchanged.
# Usage: change_missing_to_value varname newval infile outfile
# - varname: the name of the variable to change
# - newval: all instances of the missing value will be replaced with
# this new value
# - infile: input file name
# - outfile: output file name (can be the same as infile)
function change_missing_to_value {
if [[ $# -ne 4 ]]; then
echo "ERROR in change_missing_to_value: wrong number of arguments: expected 2, received $#"
exit 1
fi
varname=$1
newval=$2
infile=$3
outfile=$4
varname_tmp=${varname}_tmp_$$
cat > cmds.nco.tmp.$$ <<EOF
*missing=${varname}.get_miss();
/* we need to create a temporary variable because it seems that
delete_miss can only operate on variables that have been previously
defined in this script */
*${varname_tmp}=${varname};
/* we need to delete the missing value in order to replace those
values with 0 (needed because ncap2 doesn't let you do operations
on points that have the missing value) */
${varname_tmp}.delete_miss();
where(${varname_tmp}==missing)
${varname_tmp}=${newval};
/* WJS (6-28-11): I could imagine the following line having negative
performance implications. However, I think it's best to maintain
a _FillValue attribute in case some programs expect it.
One alternative may be to use ncatted to restore the _FillValue
attribute; I don't know if that would be more or less efficient. */
${varname_tmp}.set_miss(missing);
${varname}=${varname_tmp};
EOF
do_cmd "ncap2 -O -S cmds.nco.tmp.$$ $infile $outfile" 0
rm cmds.nco.tmp.$$
}
# ----------------------------------------------------------------------
# BEGIN MAIN SCRIPT
# ----------------------------------------------------------------------
script_dir=`dirname $0`
source $script_dir/mkprocdata_map_functions.bash
# ----------------------------------------------------------------------
# Handle command-line arguments, and check for errors
# ----------------------------------------------------------------------
# define default values:
input_file=""
output_file=""
map_file=""
template_file=""
executable_path=$script_dir
do_landfrac_copies=0
while getopts e:hi:lm:o:t: opt; do
case $opt in
e) executable_path=$OPTARG;;
h) Usage; exit;;
i) input_file=$OPTARG;;
l) do_landfrac_copies=1;;
m) map_file=$OPTARG;;
o) output_file=$OPTARG;;
t) template_file=$OPTARG;;
\?) Usage; exit 1
esac
done
check_file_arg "$input_file" "input"
check_file_arg "$map_file" "map"
check_file_arg "$template_file" "template"
if [ -z "$output_file" ]; then
echo "Must specify an output file"
Usage
exit 1
fi
# ----------------------------------------------------------------------
# Do some preprocessing
# ----------------------------------------------------------------------
tempfile="$output_file.tmp.$$"
if [ $do_landfrac_copies -eq 0 ]; then
# the following things are preprocessing that needs to be done on
# variables that are only used when do_landfrac_copies==0
echo ""
# for landfrac to be regridded appropriately, it needs to be set
# to 0 over ocean grid cells, rather than having the missing value
# there
change_missing_to_value landfrac 0 $input_file $tempfile
# we need a pftmask_float variable because we can't regrid integer
# variables properly
do_cmd "ncap2 -O -s 'pftmask_float=float(pftmask)' $tempfile $tempfile" 0
# pftmask_float should also be 0 over the ocean for the regridding
# to work as desired (analogously to what we do for landfrac,
# above). However, we don't have to do the following
# change_missing_to_value call because pftmask already doesn't
# have any missing values in the input file (as of 6-28-11).
### change_missing_to_value pftmask_float 0 $tempfile $tempfile
else
ln -s $input_file $tempfile
fi
# ----------------------------------------------------------------------
# Run mkprocdata_map
# ----------------------------------------------------------------------
do_cmd "${executable_path}/${executable} -i $tempfile -o $output_file -m $map_file -t $template_file" 0
rm $tempfile
# ----------------------------------------------------------------------
# Add extra variables to the output file
# ----------------------------------------------------------------------
if [ $do_landfrac_copies -eq 0 ]; then
all_copy_vars=$copy_vars
else
all_copy_vars="${copy_vars},${landfrac_copy_vars}"
fi
echo ""
do_cmd "ncks -A -v $all_copy_vars $template_file $output_file" 0
# ----------------------------------------------------------------------
# Do some post-processing
# ----------------------------------------------------------------------
# --- Rename area-related variables ---
do_cmd "ncrename -v area,area_regridded -v gw,area $output_file" 0
do_cmd "ncatted -a long_name,area_regridded,o,c,'grid cell areas, regridded from the original resolution' $output_file" 0
if [ $do_landfrac_copies -eq 0 ]; then
# --- Convert pftmask back to integer ---
echo ""
do_cmd "ncap2 -O -s 'pftmask = int(pftmask_float >= $pftmask_min)' $output_file $output_file" 0
do_cmd "ncks -O -x -v pftmask_float $output_file $output_file" 0
# --- Calculate landmask from landfrac ---
echo ""
cat > cmds.nco.tmp.$$ <<EOF
/* we need to make a landmask_float then later convert it to the
integer landmask, because we need to change the FillValue to be
within the range of an integer before converting landmask to an
integer */
*landmask_float=(landfrac > 0);
landmask_float.change_miss($landmask_fill);
landmask=int(landmask_float);
EOF
do_cmd "ncap2 -O -S cmds.nco.tmp.$$ $output_file $output_file" 0
rm cmds.nco.tmp.$$
change_missing_to_value landmask 0 $output_file $output_file
# in the following, note that we need to manually set missing_value, because it doesn't get changed through the .set_miss call in nco:
do_cmd "ncatted -a long_name,landmask,o,c,'land/ocean mask (0.=ocean and 1.=land)' -a missing_value,landmask,o,i,$landmask_fill $output_file" 0
fi
echo "Successfully regridded data"