# include "define.inc" module file_utils implicit none private public :: init_file_utils ! subroutine init_file_utils (list, input, error, trin_run, name) ! logical, intent (out) :: list ! logical, intent (in), optional :: input, error, trin_run ! character(*), intent (in), optional :: name ! default: INPUT=.true., ERROR=.true., TRIN_RUN=.false., NAME="unknown" ! Set up run_name(s) and list_name for output files ! Open input file and strip comments, unless disabled with INPUT=.false. ! Open error output file, unless disabled with ERROR=.false. public :: init_job_name ! subroutine ... public :: finish_file_utils ! subroutine finish_file_utils ! Clean up files opened in init public :: run_name ! character(500) :: run_name ! Label for the run, taken from the command line public :: list_name ! character(500) :: list_name ! Label for the list, taken from the command line public :: input_unit ! function input_unit (nml) ! character(*), intent (in) :: nml ! integer :: input_unit ! Rewind the input file to start of namelist NML, ! and return its unit number public :: input_unit_exist ! function input_unit_exist (nml,exist) ! character(*), intent (in) :: nml ! integer :: input_unit ! Rewind the input file to start of namelist NML, ! and return its unit number, setexist=.true. ! If the namelist NML is not found, set exist=.false. public :: init_error_unit public :: init_input_unit public :: error_unit ! function error_unit () ! integer :: error_unit ! Return the error unit number public :: get_input_unit public :: open_output_file ! subroutine open_output_file (unit, ext) ! integer, intent (out) :: unit ! character (*), intent (in) :: ext ! Open a file with name made from the run_name with the EXT appended ! and return its unit number in UNIT public :: close_output_file ! subroutine close_output_file (unit) ! integer, intent (in) :: unit ! Close the file associated with UNIT from open_output_file public :: flush_output_file ! subroutine flush_output_file (unit) ! integer, intent (in) :: unit ! Close/open-append the file associated with UNIT from open_output_file public :: get_unused_unit ! subroutine get_unused_unit (unit) ! integer, intent (out) :: unit ! Return a unit number not associated with any file public :: get_indexed_namelist_unit ! subroutine get_indexed_namelist_unit (unit, nml, index) ! integer, intent (out) :: unit ! character (*), intent (in) :: nml ! integer, intent (in) :: index ! Copy namelist, NML // '_' // INDEX, from the input file to ! namelist, NML, in a temporary file, UNIT ! public :: num_input_lines public :: stdout_unit public :: runtype_option_switch public :: runtype_standalone public :: runtype_trinity public :: runtype_list public :: runtype_multibox character(500), pointer :: run_name character(500), target :: arun_name, job_name character(500) :: list_name integer, parameter :: stdout_unit = 6 integer :: runtype_option_switch integer, parameter :: runtype_standalone = 0, & runtype_list = 1, & runtype_trinity = 2, & runtype_multibox = 3 integer, save :: input_unit_no, error_unit_no = stdout_unit ! TT> integer, save, public :: num_input_lines ! <TT contains subroutine init_file_utils(list, input, error, trin_run, name, n_ensembles) ! Find out the [[run_name]], and use the run name to determine whether ! this is a [[list]] run (i.e. a list of runs has been given) or a [[Trinity]] run. ! If not, open the error file and call init_input_unit implicit none logical, intent(out) :: list logical, intent(in), optional :: input, error, trin_run character(*), intent(in), optional :: name integer, intent(in), optional :: n_ensembles logical :: inp, err if (present(input)) then inp = input else inp = .true. end if if (present(error)) then err = error else err = .true. end if if (present(name)) then !# if FCOMPILER == _XL_ ! arun_name = name !# else arun_name = trim(name) !# endif else arun_name = "unknown" end if ! TT> changed for slice_g ! call run_type (list) if (inp .and. .not. present(trin_run)) then ! get runname from command line and ! set list=T if input ends in ".list" call run_type(list) else if (present(trin_run)) then if (trin_run) runtype_option_switch = runtype_trinity list = .false. end if ! <TT if (list) then list_name = arun_name else if (present(n_ensembles)) then if (n_ensembles > 1) then list_name = arun_name else call init_run_name call init_error_unit(err) call init_input_unit(inp) end if else call init_run_name call init_error_unit(err) call init_input_unit(inp) end if end subroutine init_file_utils subroutine run_type(list) ! This determines the type of run, by reading the name of the input file ! on the command line into [[arun_name]], and then looking at the extension. If ! the extension is .list, then [[list]] is set to .true.). use command_line, only: cl_getarg, cl_iargc implicit none logical, intent(out) :: list integer :: l, ierr list = .false. ! get argument from command line and put in arun_name if (cl_iargc() /= 0) then call cl_getarg(1, arun_name, l, ierr) if (ierr /= 0) then print *, "Error getting run name." end if end if if (l > 5 .and. arun_name(l - 4:l) == ".list") then list = .true. runtype_option_switch = runtype_list end if if (l > 6 .and. arun_name(l - 5:l) == ".multi") then list = .true. runtype_option_switch = runtype_multibox end if end subroutine run_type subroutine init_run_name ! This is called for a non [[Trinity]] or [[list]] run - ! it checks that the input file name ends in ".in", chops ! the extension off and stores it in [[arun_name]]. It ! also assigns the pointer [[run_name]] to [[arun_name]]. implicit none integer :: l l = len_trim(arun_name) if (l > 3 .and. arun_name(l - 2:l) == ".in") then arun_name = arun_name(1:l - 3) end if run_name => arun_name end subroutine init_run_name subroutine init_job_name(jobname) implicit none character(len=500), intent(in) :: jobname job_name = trim(jobname) run_name => job_name end subroutine init_job_name subroutine get_unused_unit(unit) ! Get an unused unit number for I/O. implicit none integer, intent(out) :: unit logical :: od unit = 50 do inquire (unit=unit, opened=od) if (.not. od) return unit = unit + 1 end do end subroutine get_unused_unit !============================================== !============= OPEN OUTPUT FILE =============== !============================================== ! Open an output file to write data (replacing or appending any existing) ! The name is [[run_name]] + [[ext]], and set [[unit]] to the ! unit number of that output file. subroutine open_output_file(unit, ext, overwrite_in) implicit none integer, intent(out) :: unit logical, intent(in), optional :: overwrite_in logical :: overwrite character(*), intent(in) :: ext character(500) :: hack ! Initiate the optional argument if (present(overwrite_in)) then overwrite = overwrite_in else overwrite = .true. end if ! Get a unit for the output file that is not currently in use call get_unused_unit(unit) ! Create the name of the output file hack = trim(run_name)//ext ! If overwrite==True: Create a new output file or replace the existing file ! If overwrite==False: Append data to the already existing output file if (overwrite) then open (unit=unit, file=trim(hack), status="replace", action="write") else open (unit=unit, file=trim(hack), status="unknown", action="write", position="append") end if end subroutine open_output_file !============================================== !============= CLOSE OUTPUT FILE ============== !============================================== ! Close the output file identified by [[unit]]. subroutine close_output_file(unit) implicit none integer, intent(in) :: unit close (unit=unit) end subroutine close_output_file subroutine flush_output_file(unit) implicit none integer, intent(in) :: unit character(len=500) :: fname inquire (unit, name=fname) # if FCOMPILER == _XL_ call flush_(unit) # elif FCOMPILER == _NAG_ close (unit=unit) open (unit=unit, file=trim(fname), status="old", action="write", position="append") # else call flush (unit) # endif end subroutine flush_output_file subroutine init_error_unit(open_it) implicit none logical, intent(in) :: open_it ! TT> changed for slice_g ! error_unit_no = 6 error_unit_no = 0 ! <TT if (run_name /= "unknown" .and. open_it) then call open_output_file(error_unit_no, ".error") ! TT: error_unit_no is overwritten for .error file end if end subroutine init_error_unit subroutine strip_comments(line) implicit none character(*), intent(in out) :: line logical :: in_single_quotes, in_double_quotes integer :: i, length length = len_trim(line) i = 1 in_single_quotes = .false. in_double_quotes = .false. loop: do if (in_single_quotes) then if (line(i:i) == "'") in_single_quotes = .false. else if (in_double_quotes) then if (line(i:i) == '"') in_double_quotes = .false. else select case (line(i:i)) case ("'") in_single_quotes = .true. case ('"') in_double_quotes = .true. case ("!") i = i - 1 exit loop end select end if if (i >= length) exit loop i = i + 1 end do loop line = line(1:i) end subroutine strip_comments subroutine init_input_unit(open_it) ! open the input file, strip out any comments and ! write them into the file ".run_name.in". Check ! for includes, read any lines from the includes, strip ! any comments from them and add them to the same file. implicit none logical, intent(in) :: open_it integer :: in_unit, out_unit, iostat character(500) :: line integer :: ind_slash !To hold position of slash in run_name ! for includes integer, parameter :: stack_size = 10 integer, dimension(stack_size) :: stack integer :: stack_ptr if (.not. open_it) then input_unit_no = -1 return end if call get_unused_unit(in_unit) open (unit=in_unit, file=trim(run_name)//".in", status="old", & action="read", iostat=iostat) if (iostat /= 0) then print "(a)", "Could not open input file: "//trim(run_name)//".in" end if call get_unused_unit(out_unit) ! open (unit=out_unit, status="scratch", action="readwrite") !Determine if '/' is in input name and if so what position !in the string is the last one (i.e. split run_name into path_to_file and file) ind_slash = index(run_name, "/", .True.) if (ind_slash == 0) then !No slash in name !Original behaviour open (unit=out_unit, file="."//trim(run_name)//".in") else !General behaviour open (unit=out_unit, file=trim(run_name(1:ind_slash))//"."//trim(run_name(ind_slash + 1:))//".in") end if iostat = 0 stack_ptr = 0 num_input_lines = 0 do read (unit=in_unit, fmt="(a)", iostat=iostat) line if (iostat /= 0) then if (stack_ptr <= 0) exit close (unit=in_unit) iostat = 0 in_unit = stack(stack_ptr) stack_ptr = stack_ptr - 1 cycle end if if (line(1:9) == "!include ") then if (stack_ptr >= stack_size) then print "(a)", "!include ignored: nesting too deep: "//trim(line) cycle end if stack_ptr = stack_ptr + 1 stack(stack_ptr) = in_unit call get_unused_unit(in_unit) open (unit=in_unit, file=trim(line(10:)), status="old", & action="read", iostat=iostat) if (iostat /= 0) then print "(a)", "!include ignored: file unreadable: "//trim(line) in_unit = stack(stack_ptr) stack_ptr = stack_ptr - 1 cycle end if cycle end if call strip_comments(line) write (unit=out_unit, fmt="(a)") trim(line) num_input_lines = num_input_lines + 1 end do close (unit=in_unit) input_unit_no = out_unit end subroutine init_input_unit subroutine finish_file_utils implicit none if (input_unit_no > 0) then close (unit=input_unit_no) input_unit_no = -1 end if if (error_unit_no > 0 .and. error_unit_no /= 6) then close (unit=error_unit_no) error_unit_no = -1 end if end subroutine finish_file_utils function input_unit(nml) implicit none character(*), intent(in) :: nml integer :: input_unit, iostat character(500) :: line intrinsic adjustl, trim input_unit = input_unit_no if (input_unit_no > 0) then rewind (unit=input_unit_no) do read (unit=input_unit_no, fmt="(a)", iostat=iostat) line if (iostat /= 0) then rewind (unit=input_unit_no) exit end if if (trim(adjustl(line)) == "&"//nml) then backspace (unit=input_unit_no) return end if end do end if write (unit=error_unit_no, fmt="('Could not find namelist: ',a)") nml write (unit=*, fmt="('Could not find namelist: ',a)") nml end function input_unit function input_unit_exist(nml, exist) implicit none character(*), intent(in) :: nml logical, intent(out) :: exist integer :: input_unit_exist, iostat character(500) :: line intrinsic adjustl, trim input_unit_exist = input_unit_no exist = .true. if (input_unit_no > 0) then rewind (unit=input_unit_no) do read (unit=input_unit_no, fmt="(a)", iostat=iostat) line if (iostat /= 0) then rewind (unit=input_unit_no) exit end if if (trim(adjustl(line)) == "&"//nml) then backspace (unit=input_unit_no) return end if end do end if exist = .false. end function input_unit_exist function error_unit() implicit none integer :: error_unit error_unit = error_unit_no end function error_unit subroutine get_input_unit(unit) implicit none integer, intent(out) :: unit unit = input_unit_no end subroutine get_input_unit subroutine get_indexed_namelist_unit(unit, nml, index_in) implicit none integer, intent(out) :: unit character(*), intent(in) :: nml integer, intent(in) :: index_in character(500) :: line integer :: iunit, iostat, in_file integer :: ind_slash logical :: exist call get_unused_unit(unit) ! open (unit=unit, status="scratch", action="readwrite") !Determine if '/' is in input name and if so what position !in the string is the last one (i.e. split run_name into path_to_file and file) ind_slash = index(run_name, "/", .True.) if (ind_slash == 0) then !No slash in name !Original behaviour open (unit=unit, file="."//trim(run_name)//".scratch") else !General behaviour open (unit=unit, file=trim(run_name(1:ind_slash))//"."//trim(run_name(ind_slash + 1:))//".scratch") end if write (line, *) index_in line = nml//"_"//trim(adjustl(line)) in_file = input_unit_exist(trim(line), exist) if (exist) then iunit = input_unit(trim(line)) else write (6, *) "get_indexed_namelist: following namelist not found ", trim(line) return end if read (unit=iunit, fmt="(a)") line write (unit=unit, fmt="('&',a)") nml do read (unit=iunit, fmt="(a)", iostat=iostat) line if (iostat /= 0 .or. trim(adjustl(line)) == "/") exit write (unit=unit, fmt="(a)") trim(line) end do write (unit=unit, fmt="('/')") rewind (unit=unit) end subroutine get_indexed_namelist_unit end module file_utils