#!/bin/bash
# --------------------------------------------------------------------------- #
# comp  : Compiler script for use in ad3 (customized for hardware and         #
#         optimization). Note that this script will not be replaced if part   #
#         of WAVEWATCH III is re-installed. Used by ad3.                      #
#                                                                             #
# use   : comp name                                                           #
#           name: name of source code file without the extension.             #
#                                                                             #
# error codes :  1 : input error                                              #
#                2 : no environment file $ww3_env found.                      #
#                3 : error in creating scratch directory.                     #
#                4 : w3adc error.                                             #
#                5 : compiler error.                                          #
#                                                                             #
# remarks :                                                                   #
#                                                                             #
#  - This script runs from the scratch directory, where it should remain.     #
#                                                                             #
#  - For this script to interact with ad3, it needs to generate / leave       #
#    following files :                                                        #
#       $name.f90   : Source code (generated by ad3).                         #
#       $name.o     : Object module.                                          #
#       $name.l     : Listing file.                                           #
#       comp.stat.$name   : status file of compiler, containing number of errors    #
#                     and number of warnings (generated by comp).             #
#                                                                             #
#  - Upon (first) installation of WAVEWATCH III the user needs to check the   #
#    following parts of this script :                                         #
#      sec. 2.b : Provide correct compiler/options.                           #
#      sec. 3.a : Provide correct error capturing.                            #
#      sec. 3.d : Remove unnecessary files.                                   #
#                                                                             #
#  - This version is made for the Intel ifort version 8.1 on a Pentium 4      #
#    processor.                                                               #
#                                                                             #
#                                                      Hendrik L. Tolman      #
#                                                      April    2015          #
# --------------------------------------------------------------------------- #
# 1. Preparations                                                             #
# --------------------------------------------------------------------------- #
# 1.a Check and process input

  if [ "$#" != '1' ]
  then
    echo "usage: comp name" ; exit 1
  fi
  name="$1"

# 1.b Initial clean-up - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

  rm -f $name.l
  rm -f $name.o
  rm -f comp.stat.$name

# --------------------------------------------------------------------------- #
# 2. Compile                                                                  #
# --------------------------------------------------------------------------- #
# Add here the correct compiler call including command line options
# Note: - do not invoke a link step
#       - if possible, generate a listing $name.l
#       - make sure the compiler point to the proper directory where the 
#         modules are stored ($m_path), see examples below.

# 2.a Determine file extension - - - - - - - - - - - - - - - - - - - - - - - - 
#     .f90 assumes free format, .f assumes fixed format, change if necessary
# *** file extension (fext) is set and exported by calling program (ad3) ***

# 2.b Perform compilation  - - - - - - - - - - - - - - - - - - - - - - - - - - 
#     Save compiler exit code in $OK
#
# Intel compiler on Linux ----------------------------------------------------
# 2.b.1 Build options and determine compiler name

  # compilation options
  opt="-c -module $path_m"


################################################################################
# *** System-dependant instructions                                            #
# -xHost : Generates instructions for the highest instruction set available on #
#          the compilation host processor                                      #
# -xcore-avx2 : Intel Advanced Vector Extensions 2                             #
# -no-fma : Generates separate multiply and add instructions with intermediate #
#           rounding                                                           #
#                                                                              #
# The value for <code> must be lower case on Linux or OS X                     #
################################################################################
  opt="$opt -xHost -no-fma"


################################################################################
# *** Optimization levels                                                      #
# -O0 : No optimizations applied                                               #
# -O1 : Provides a minimum of statement–level optimizations                    #
# -O2 : Enables basic block level optimizations                                #
# -O3 : Adds loop unrolling and global optimizations at the function level     #
# -O4 : Adds automatic inlining of routines contained in the same file         #
# -ip : Enables interprocedural optimizations for single-file compilation      #
#                                                                              #
# Debugging with -g does not suppress -On, but -On limits -g in certain ways   #
################################################################################
  opt="$opt -O0 -ip"


################################################################################
# *** Profiling and debugging analysis                                         #
# -p  : Profiling                                                              #
# -pg : Profiling with statistics in gmon.out                                  #
# -g  : Compiles for debugging and performance analysis.                       #
# -debug all : Generates complete debugging information                        #
#                                                                              #
# The compiler options -p, -pg, or -xpg should not be used to compile          #
# multi-threaded programs, because the runtime support for these options is    #
# not thread-safe. If a program that uses multiple threads is compiled with    #
# these options invalid results or a segmentation fault could occur at runtime #
# If you compile with -pg, then be sure to link with -pg.                      #
################################################################################
  opt="$opt -p"
  opt="$opt -g -debug all"


################################################################################
# *** Warning messages                                                         #
# -warn all : Specifies all diagnostic messages to be issued by the compiler   #
# -warn declarations : Enables warnings about any undeclared names. Equivalent #
#                      to -implicitnone                                        #
################################################################################
  opt="$opt -warn all"


################################################################################
# *** Check messages                                                           #
# -check all : Checks for all conditions at run time                           #
# -check noarg_temp_created : Disables message for temporary array created     #
################################################################################
  opt="$opt -check all -check noarg_temp_created"


################################################################################
# *** Numbers format                                                           #
# -fp-model precise : Disables optimizations that are not value-safe on        #
#                     floating-point data and rounds intermediate results to   #
#                     source-defined precision                                 #
# -assume byterecl : Defines the record length in bytes for the OPEN statement #
#                    RECL specifier in unformatted files                       #
# -convert big-endian: Specifies that the format will be big endian for        #
#                      integer data and big endian IEEE floating-point for     #
#                      real and complex data                                   #
# -fp-stack-check : Generates extra code after every function call to ensure   #
#                   that the floating-point stack is in the expected state     #
################################################################################
  opt="$opt -fp-model precise -assume byterecl -convert big_endian"
  opt="$opt -fp-stack-check"


################################################################################
# *** Aliasing                                                                 #
# -fno-alias : Aliasing during a procedure call is not assumed                 #
# -fno-fnalias : Aliasing is not assumed within functions, but it is assumed   #
#                across calls                                                  #
################################################################################
  opt="$opt -fno-alias -fno-fnalias"


################################################################################
# *** Memory setting                                                           #
# -heap-arrays : Puts automatic arrays and arrays for temporary computations   #
#                on the heap instead of the stack                              #
# -traceback : Issue a stack trace if a severe error occurs in execution       #
#                                                                              #
# If you compile with -traceback, then be sure to link with -traceback         #
# The heap is memory set aside for dynamic allocation                          #
# The stack is the memory set aside as scratch space for a thread of execution #
# Each thread gets a stack, while there is only one heap for the application   #
################################################################################
  opt="$opt -heap-arrays -traceback"


  # mpi implementation
  if [ "$mpi_mod" = 'yes' ]
  then
    comp=ifort
  else
    comp=ifort
  fi

  # open mpi implementation
  if [ "$omp_mod" = 'yes' ]
  then
    opt="$opt -qopenmp"
  fi

  # oasis coupler include dir
  if [ "$oasis_mod" = 'yes' ]
  then
    opt="$opt -I$OASISDIR/build/lib/psmile.MPI1"
  fi

  # netcdf include dir
  if [ "$netcdf_compile" = 'yes' ]
  then
    case $WWATCH3_NETCDF in
      NC3) opt="$opt -I$NETCDF_INCDIR" ;;
      NC4) if [ "$mpi_mod" = 'no' ]; then comp="`$NETCDF_CONFIG --fc`"; fi
           opt="$opt -I`$NETCDF_CONFIG --includedir`" ;;
    esac
  fi

  # ftn include dir
  opt="$opt -I$path_i"
  opt="$opt $ESMF_F90COMPILEPATHS"
  opt="$opt $EXTRA_COMP_OPTIONS"

# 2.b.2 Compile

  $comp $opt                             $name.$fext > $name.out 2> $name.err
  OK="$?"

# 2.b.2 Process listing

  if [ -s $name.lst ] 
  then
     mv $name.lst $name.l
  fi

# 2.b.3 Add test output to listing for later viewing

  if [ -s $name.l ] 
  then
    echo '------------' >> $name.l
    echo "$comp $opt"   >> $name.l
    echo '------------' >> $name.l
    cat $name.out       >> $name.l 2> /dev/null
    echo '------------' >> $name.l
    cat $name.err       >> $name.l 2> /dev/null
    echo '------------' >> $name.l
  fi

# --------------------------------------------------------------------------- #
# 3. Postprocessing                                                           #
# --------------------------------------------------------------------------- #
# 3.a Capture errors
#     nr_err : number of errors.
#     nr_war : number of errors.

  nr_err='0'
  nr_war='0'

  if [ -s $name.err ]
  then
    nr_err=`grep 'error' $name.err | wc -l | awk '{ print $1 }'`
    nr_war=`grep 'warning' $name.err | wc -l | awk '{ print $1 }'`
  else
    if [ "$OK" != '0' ]
    then
      nr_err='1'
    fi
  fi

# 3.b Make file comp.stat.$name  - - - - - - - - - - - - - - - - - - - - - - - - - - 

  echo "ERROR    $nr_err"   > comp.stat.$name
  echo "WARNING  $nr_war"  >> comp.stat.$name

# 3.c Prepare listing  - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#     if compiler does not provide listing, make listing from source code
#     and compiler messages. Second input line for w3list identifies if
#     comment lines are to be numbered.

  if [ ! -f $name.l ]
  then
    echo "$name.$fext" > w3list.inp
    echo "T"          >> w3list.inp
    w3list < w3list.inp 2> /dev/null
    rm -f w3list.inp
    mv w3list.out $name.l
    echo '------------' >> $name.l
    echo "$comp $opt"   >> $name.l
    echo '------------' >> $name.l
    cat $name.out >> $name.l #2> /dev/null
    echo '------------' >> $name.l
    cat $name.err >> $name.l #2> /dev/null
    echo '------------' >> $name.l
  fi

# 3.d Remove unwanted files  - - - - - - - - - - - - - - - - - - - - - - - - -
#     include here unwanted files generated by the compiler

#  rm -f $name.out
#  rm -f $name.err

# end of comp --------------------------------------------------------------- #