PartMC  2.2.1
spec_file.F90
Go to the documentation of this file.
00001 ! Copyright (C) 2007-2011 Nicole Riemer and Matthew West
00002 ! Licensed under the GNU General Public License version 2 or (at your
00003 ! option) any later version. See the file COPYING for details.
00004 
00005 !> \file
00006 !> The pmc_spec_file module.
00007 
00008 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00009 
00010 !> \page spec_file_format Input File Format: Spec File Format
00011 !!
00012 !! All PartMC input files are in a text format. Each line consists of
00013 !! a <b>parameter name</b>, followed by the <b>parameter value</b>,
00014 !! and an optional comment starting with the # character. Blank lines
00015 !! and comment-only lines are permitted, and everything on a line
00016 !! after a # is completely ignored.
00017 !!
00018 !! Parameter names are strings (normally lowercase) without spaces,
00019 !! such as \c output_prefix or \c del_t. The case of parameter names
00020 !! is significant. The order of parameters in a file is not
00021 !! arbitrary. Instead, they must come in the prescribed order and
00022 !! cannot be skipped or rearranged.
00023 !!
00024 !! The parameter types are:
00025 !!   - \b string: a single string without spaces (case is significant)
00026 !!   - \b logical: a true/false value that can be the exact values
00027 !!     "yes", "y", "true", "t", or "1" (for true values), or "no",
00028 !!     "n", "false", "f", or "0" (for false values
00029 !!   - \b integer: a positive or negative integer (depending on
00030 !!     whether PartMC was compiled as 32bit or 64bit the maximum size
00031 !!     will vary)
00032 !!   - \b real: a floating point real number in Fortran syntax,
00033 !!     e.g. -1.45, 5.27e10 (the available precision and range is that
00034 !!     of whatever double precision meant during the compilation)
00035 !!   - \b complex: two real numbers separated by a space, giving the
00036 !!     real and imaginary parts of a complex number, respectively
00037 !!   - <b>real array</b>: a list of real numbers separated by spaces,
00038 !!     giving the entries of the array
00039 
00040 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00041 
00042 !> Reading formatted text input.
00043 module pmc_spec_file
00044 
00045   use pmc_spec_line
00046   use pmc_util
00047   
00048   !> Maximum number of lines in an array.
00049   integer, parameter :: SPEC_FILE_MAX_LIST_LINES = 1000
00050 
00051   !> An input file with extra data for printing messages.
00052   !!
00053   !! An spec_file_t is just a simple wrapper around a Fortran unit
00054   !! number together with the filename and current line number. The
00055   !! line number is updated manually by the various \c spec_file_*()
00056   !! subroutine. To maintain its validity all file accesses must be
00057   !! done via the \c spec_file_*() subroutines, and no data should be
00058   !! accessed directly via \c spec_file%%unit.
00059   type spec_file_t
00060      !> Filename.
00061      character(len=SPEC_LINE_MAX_VAR_LEN) :: name
00062      !> Attached unit.
00063      integer :: unit
00064      !> Current line number.
00065      integer :: line_num
00066   end type spec_file_t
00067 
00068 contains
00069 
00070 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00071 
00072   !> Exit with an error message containing filename and line number.
00073   subroutine spec_file_die_msg(code, file, msg)
00074 
00075     !> Failure status code.
00076     integer, intent(in) :: code
00077     !> Spec file.
00078     type(spec_file_t), intent(in) :: file
00079     !> Error message.
00080     character(len=*), intent(in) :: msg
00081 
00082     call spec_file_assert_msg(code, file, .false., msg)
00083 
00084   end subroutine spec_file_die_msg
00085 
00086 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00087 
00088   !> Exit with an error message containing filename and line number
00089   !> if \c condition_ok is \c .false.
00090   subroutine spec_file_assert_msg(code, file, condition_ok, msg)
00091 
00092     !> Failure status code.
00093     integer, intent(in) :: code
00094     !> Spec file.
00095     type(spec_file_t), intent(in) :: file
00096     !> Whether the assertion is ok.
00097     logical, intent(in) :: condition_ok
00098     !> Error message.
00099     character(len=*), intent(in) :: msg
00100 
00101     if (.not. condition_ok) then
00102        call die_msg(code, "file " // trim(file%name) // " line " &
00103             // trim(integer_to_string(file%line_num)) // ": " // trim(msg))
00104     end if
00105 
00106   end subroutine spec_file_assert_msg
00107 
00108 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00109 
00110   !> Open a spec file for reading.
00111   subroutine spec_file_open(filename, file)
00112 
00113     !> Name of file to open.
00114     character(len=*), intent(in) :: filename
00115     !> Spec file.
00116     type(spec_file_t), intent(out) :: file
00117 
00118     integer :: ios, unit
00119 
00120     file%name = trim(filename)
00121     file%unit = get_unit()
00122     open(unit=file%unit, status='old', file=file%name, iostat=ios)
00123     if (ios /= 0) then
00124        call die_msg(173932734, "unable to open file " // trim(file%name) &
00125             // " for reading: IOSTAT = " // trim(integer_to_string(ios)))
00126     end if
00127     file%line_num = 0
00128 
00129   end subroutine spec_file_open
00130 
00131 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00132 
00133   !> Close a spec file.
00134   subroutine spec_file_close(file)
00135 
00136     !> Spec file.
00137     type(spec_file_t), intent(in) :: file
00138 
00139     close(file%unit)
00140     call free_unit(file%unit)
00141 
00142   end subroutine spec_file_close
00143 
00144 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00145 
00146   !> Read a single line from a spec file, signaling if we have hit EOF.
00147   subroutine spec_file_read_line_raw(file, line, eof)
00148 
00149     !> Spec file.
00150     type(spec_file_t), intent(inout) :: file
00151     !> Complete line read.
00152     character(len=*), intent(out) :: line
00153     !> True if at EOF.
00154     logical, intent(out) :: eof
00155 
00156     integer :: ios, n_read
00157 
00158     file%line_num = file%line_num + 1
00159     eof = .false.
00160     line = "" ! needed for pgf95 for reading blank lines
00161     read(unit=file%unit, fmt='(a)', advance='no', end=100, eor=110, &
00162          iostat=ios) line
00163     if (ios /= 0) then
00164        call spec_file_die_msg(869855853, file, &
00165             'error reading: IOSTAT = ' // trim(integer_to_string(ios)))
00166     end if
00167     ! only reach here if we didn't hit end-of-record (end-of-line) in
00168     ! the above read, meaning the line was too long
00169     call spec_file_die_msg(468785871, file, &
00170          'line exceeds length: ' // trim(integer_to_string(len(line))))
00171 
00172 100 line = "" ! goto here if end-of-file was encountered immediately
00173     eof = .true.
00174 
00175 110 return ! goto here if end-of-record, meaning everything is ok
00176     
00177   end subroutine spec_file_read_line_raw
00178 
00179 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00180 
00181   !> Read the next line from the spec file that contains useful data
00182   !> (stripping comments and blank lines).
00183   subroutine spec_file_read_next_data_line(file, line, eof)
00184 
00185     !> Spec file.
00186     type(spec_file_t), intent(inout) :: file
00187     !> Complete line read.
00188     character(len=*), intent(out) :: line
00189     !> True if EOF encountered.
00190     logical, intent(out) :: eof
00191 
00192     logical :: done
00193 
00194     done = .false.
00195     do while (.not. done)
00196        call spec_file_read_line_raw(file, line, eof)
00197        if (eof) then
00198           done = .true.
00199        else
00200           call spec_line_strip_comment(line)
00201           call spec_line_tabs_to_spaces(line)
00202           call spec_line_strip_leading_spaces(line)
00203           if (len_trim(line) > 0) then
00204              done = .true.
00205           end if
00206        end if
00207     end do
00208 
00209   end subroutine spec_file_read_next_data_line
00210 
00211 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00212 
00213   !> Read a spec_line from the spec_file.
00214   subroutine spec_file_read_line(file, line, eof)
00215 
00216     !> Spec file.
00217     type(spec_file_t), intent(inout) :: file
00218     !> Spec line.
00219     type(spec_line_t), intent(inout) :: line
00220     !> True if EOF encountered.
00221     logical, intent(out) :: eof
00222 
00223     character(len=SPEC_LINE_MAX_LEN) :: line_string, rest
00224     integer i, n_data
00225     logical done
00226 
00227     call spec_file_read_next_data_line(file, line_string, eof)
00228     if (eof) return
00229 
00230     ! strip off the name
00231     i = index(line_string, ' ') ! first space
00232     if (i == 0) then
00233        call spec_file_die_msg(117442928, file, 'line contains no whitespace')
00234     end if
00235     if (i == 1) then
00236        call spec_file_die_msg(650916702, file, 'line starts with whitespace')
00237     end if
00238     if (i >= SPEC_LINE_MAX_VAR_LEN) then
00239        call spec_file_die_msg(170403881, file, 'line name longer than: ' &
00240             // trim(integer_to_string(SPEC_LINE_MAX_VAR_LEN)))
00241     end if
00242     line%name = line_string(1:(i-1))
00243     line_string = line_string(i:)
00244     call spec_line_strip_leading_spaces(line_string)
00245 
00246     ! figure out how many data items we have (consecutive non-spaces)
00247     n_data = 0
00248     rest = line_string
00249     done = .false.
00250     do while (.not. done)
00251        if (len_trim(rest) == 0) then ! only spaces left
00252           done = .true.
00253        else
00254           ! strip the data element
00255           n_data = n_data + 1
00256           i = index(rest, ' ') ! first space
00257           rest = rest(i:)
00258           call spec_line_strip_leading_spaces(rest)
00259        end if
00260     end do
00261 
00262     ! allocate the data and read out the data items
00263     call spec_line_deallocate(line)
00264     call spec_line_allocate_size(line, n_data)
00265     n_data = 0
00266     rest = line_string
00267     done = .false.
00268     do while (.not. done)
00269        if (len_trim(rest) == 0) then ! only spaces left
00270           done = .true.
00271        else
00272           ! strip the data element
00273           n_data = n_data + 1
00274           i = index(rest, ' ') ! first space
00275           if (i <= 1) then
00276              call spec_file_die_msg(332939443, file, &
00277                   'internal processing error')
00278           end if
00279           if (i >= SPEC_LINE_MAX_VAR_LEN) then
00280              call spec_file_die_msg(145508629, file, &
00281                   'data element ' // trim(integer_to_string(n_data)) &
00282                   // ' longer than: ' &
00283                   // trim(integer_to_string(SPEC_LINE_MAX_VAR_LEN)))
00284           end if
00285           line%data(n_data) = rest(1:(i-1))
00286           rest = rest(i:)
00287           call spec_line_strip_leading_spaces(rest)
00288        end if
00289     end do
00290     
00291   end subroutine spec_file_read_line
00292 
00293 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00294 
00295   !> Read a spec_line from the spec_file. This will always succeed or
00296   !> error out, so should only be called if we know there should be a
00297   !> valid line coming.
00298   subroutine spec_file_read_line_no_eof(file, line)
00299 
00300     !> Spec file.
00301     type(spec_file_t), intent(inout) :: file
00302     !> Spec line.
00303     type(spec_line_t), intent(inout) :: line
00304 
00305     logical :: eof
00306 
00307     call spec_file_read_line(file, line, eof)
00308     if (eof) then
00309        call spec_file_die_msg(358475502, file, 'unexpected end of file')
00310     end if
00311 
00312   end subroutine spec_file_read_line_no_eof
00313 
00314 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00315 
00316   !> Read a list of spec_lines from a file, stopping at max_lines
00317   !> or EOF, whichever comes first.
00318   subroutine spec_file_read_line_list(file, max_lines, line_list)
00319 
00320     !> Spec file.
00321     type(spec_file_t), intent(inout) :: file
00322     !> Max lines to read (0 = no max).
00323     integer, intent(in) :: max_lines
00324     !> List of spec_lines.
00325     type(spec_line_t), pointer :: line_list(:)
00326 
00327     logical :: eof
00328     integer :: i, num_lines
00329     type(spec_line_t) :: temp_line_list(SPEC_FILE_MAX_LIST_LINES)
00330 
00331     ! read file, working out how many lines we have
00332     num_lines = 0
00333     eof = .false.
00334     call spec_line_allocate(temp_line_list(num_lines + 1))
00335     call spec_file_read_line(file, temp_line_list(num_lines + 1), eof)
00336     if (eof) then
00337        call spec_line_deallocate(temp_line_list(num_lines + 1))
00338     end if
00339     do while (.not. eof)
00340        num_lines = num_lines + 1
00341        if (num_lines > SPEC_FILE_MAX_LIST_LINES) then
00342           call spec_file_die_msg(450564159, file, &
00343                'maximum number of lines exceeded')
00344        end if
00345        if (max_lines > 0) then
00346           if (num_lines >= max_lines) then
00347              eof = .true.
00348           end if
00349        end if
00350        if (.not. eof) then
00351           call spec_line_allocate(temp_line_list(num_lines + 1))
00352           call spec_file_read_line(file, temp_line_list(num_lines + 1), eof)
00353           if (eof) then
00354              call spec_line_deallocate(temp_line_list(num_lines + 1))
00355           end if
00356        end if
00357     end do
00358 
00359     ! copy data to actual list
00360     do i = 1,size(line_list)
00361        call spec_line_deallocate(line_list(i))
00362     end do
00363     deallocate(line_list)
00364     allocate(line_list(num_lines))
00365     do i = 1,num_lines
00366        call spec_line_allocate(line_list(i))
00367        call spec_line_copy(temp_line_list(i), line_list(i))
00368        call spec_line_deallocate(temp_line_list(i))
00369     end do
00370 
00371   end subroutine spec_file_read_line_list
00372 
00373 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00374 
00375   !> Read an array of spec_lines from a file, stopping at max_lines
00376   !> or EOF. All lines must have the same number of elements.
00377   subroutine spec_file_read_line_array(file, max_lines, line_array)
00378 
00379     !> Spec file.
00380     type(spec_file_t), intent(inout) :: file
00381     !> Max lines to read (0 = no max).
00382     integer, intent(in) :: max_lines
00383     !> Array of spec_lines,.
00384     type(spec_line_t), pointer :: line_array(:)
00385 
00386     integer :: i, line_length
00387 
00388     call spec_file_read_line_list(file, max_lines, line_array)
00389     if (size(line_array) > 0) then
00390        line_length = size(line_array(1)%data)
00391        do i = 2,size(line_array)
00392           if (size(line_array(i)%data) /= line_length) then
00393              call spec_file_die_msg(298076484, file, &
00394                   'lines have unequal numbers of entries for array')
00395           end if
00396        end do
00397     end if
00398     
00399   end subroutine spec_file_read_line_array
00400 
00401 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00402 
00403   !> Check that the name of the line data is as given.
00404   subroutine spec_file_check_line_name(file, line, name)
00405 
00406     !> Spec file.
00407     type(spec_file_t), intent(in) :: file
00408     !> Spec line.
00409     type(spec_line_t), intent(in) :: line
00410     !> Expected line name.
00411     character(len=*), intent(in) :: name
00412 
00413     if (line%name /= name) then
00414        call spec_file_die_msg(462932478, file, &
00415             'line must begin with: ' // trim(name) &
00416             // ' not: ' // trim(line%name))
00417     end if
00418 
00419   end subroutine spec_file_check_line_name
00420   
00421 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00422 
00423   !> Checks that the read_name is the same as name.
00424   subroutine spec_file_check_name(file, name, read_name)
00425     
00426     !> Spec file.
00427     type(spec_file_t), intent(inout) :: file
00428     !> Name that we should have.
00429     character(len=*), intent(in) :: name
00430     !> Name that we do have.
00431     character(len=*), intent(in) :: read_name
00432     
00433     integer name_len, read_name_len
00434 
00435     if (name /= read_name) then
00436        call spec_file_die_msg(683719069, file, &
00437             'line must begin with: ' // trim(name) &
00438             // ' not: ' // trim(read_name))
00439     end if
00440     
00441   end subroutine spec_file_check_name
00442   
00443 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00444 
00445   !> Check that the length of the line data is as given.
00446   subroutine spec_file_check_line_length(file, line, length)
00447 
00448     !> Spec file.
00449     type(spec_file_t), intent(in) :: file
00450     !> Spec line.
00451     type(spec_line_t), intent(in) :: line
00452     !> Expected data length.
00453     integer, intent(in) :: length
00454 
00455     if (size(line%data) /= length) then
00456        call spec_file_die_msg(189339129, file, 'expected ' &
00457             // trim(integer_to_string(length)) // ' data items on line')
00458     end if
00459 
00460   end subroutine spec_file_check_line_length
00461   
00462 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00463 
00464   !> Check the IOSTAT and error if it is bad.
00465   subroutine spec_file_check_read_iostat(file, ios, type)
00466 
00467     !> Spec file.
00468     type(spec_file_t), intent(in) :: file
00469     !> Iostat result.
00470     integer, intent(in) :: ios
00471     !> Type being read during error.
00472     character(len=*), intent(in) :: type
00473 
00474     if (ios /= 0) then
00475        call spec_file_die_msg(704342497, file, &
00476             'error reading: IOSTAT = ' // trim(integer_to_string(ios)))
00477     end if
00478 
00479   end subroutine spec_file_check_read_iostat
00480 
00481 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00482 
00483   !> Convert a string to an integer.
00484   integer function spec_file_string_to_integer(file, string)
00485 
00486     !> Spec file.
00487     type(spec_file_t), intent(in) :: file
00488     !> String to convert.
00489     character(len=*), intent(in) :: string
00490     
00491     integer :: val
00492     integer :: ios
00493 
00494     read(string, '(i20)', iostat=ios) val
00495     call spec_file_check_read_iostat(file, ios, "integer")
00496     spec_file_string_to_integer = val
00497 
00498   end function spec_file_string_to_integer
00499 
00500 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00501 
00502   !> Convert a string to an real.
00503   real(kind=dp) function spec_file_string_to_real(file, string)
00504 
00505     !> Spec file.
00506     type(spec_file_t), intent(in) :: file
00507     !> String to convert.
00508     character(len=*), intent(in) :: string
00509     
00510     real(kind=dp) :: val
00511     integer :: ios
00512 
00513     read(string, '(f30.0)', iostat=ios) val
00514     call spec_file_check_read_iostat(file, ios, "real")
00515     spec_file_string_to_real = val
00516 
00517   end function spec_file_string_to_real
00518 
00519 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00520 
00521   !> Convert a string to an logical.
00522   logical function spec_file_string_to_logical(file, string)
00523 
00524     !> Spec file.
00525     type(spec_file_t), intent(in) :: file
00526     !> String to convert.
00527     character(len=*), intent(in) :: string
00528     
00529     logical :: val
00530     integer :: ios
00531 
00532     val = .false.
00533     if ((trim(string) == 'yes') &
00534          .or. (trim(string) == 'y') &
00535          .or. (trim(string) == 'true') &
00536          .or. (trim(string) == 't') &
00537          .or. (trim(string) == '1')) then
00538        val = .true.
00539     elseif ((trim(string) == 'no') &
00540          .or. (trim(string) == 'n') &
00541          .or. (trim(string) == 'false') &
00542          .or. (trim(string) == 'f') &
00543          .or. (trim(string) == '0')) then
00544        val = .false.
00545     else
00546        call spec_file_check_read_iostat(file, 1, "logical")
00547     end if
00548     spec_file_string_to_logical = val
00549 
00550   end function spec_file_string_to_logical
00551 
00552 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00553 
00554   !> Read an integer from a spec file that must have the given name.
00555   subroutine spec_file_read_integer(file, name, var)
00556 
00557     !> Spec file.
00558     type(spec_file_t), intent(inout) :: file
00559     !> Name.
00560     character(len=*), intent(in) :: name
00561     !> Variable to store data.
00562     integer, intent(out) :: var
00563 
00564     type(spec_line_t) :: line
00565 
00566     call spec_line_allocate(line)
00567     call spec_file_read_line_no_eof(file, line)
00568     call spec_file_check_line_name(file, line, name)
00569     call spec_file_check_line_length(file, line, 1)
00570     var = spec_file_string_to_integer(file, line%data(1))
00571     call spec_line_deallocate(line)
00572 
00573   end subroutine spec_file_read_integer
00574   
00575 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00576 
00577   !> Read a real number from a spec file that must have the given
00578   !> name.
00579   subroutine spec_file_read_real(file, name, var)
00580 
00581     !> Spec file.
00582     type(spec_file_t), intent(inout) :: file
00583     !> Name.
00584     character(len=*), intent(in) :: name
00585     !> Variable to store data.
00586     real(kind=dp), intent(out) :: var
00587 
00588     type(spec_line_t) :: line
00589 
00590     call spec_line_allocate(line)
00591     call spec_file_read_line_no_eof(file, line)
00592     call spec_file_check_line_name(file, line, name)
00593     call spec_file_check_line_length(file, line, 1)
00594     var = spec_file_string_to_real(file, line%data(1))
00595     call spec_line_deallocate(line)
00596 
00597   end subroutine spec_file_read_real
00598 
00599 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00600 
00601   !> Read a logical from a spec file that must have a given name.
00602   subroutine spec_file_read_logical(file, name, var)
00603 
00604     !> Spec file.
00605     type(spec_file_t), intent(inout) :: file
00606     !> Name.
00607     character(len=*), intent(in) :: name
00608     !> Variable to store data.
00609     logical, intent(out) :: var
00610 
00611     type(spec_line_t) :: line
00612 
00613     call spec_line_allocate(line)
00614     call spec_file_read_line_no_eof(file, line)
00615     call spec_file_check_line_name(file, line, name)
00616     call spec_file_check_line_length(file, line, 1)
00617     var = spec_file_string_to_logical(file, line%data(1))
00618     call spec_line_deallocate(line)
00619 
00620   end subroutine spec_file_read_logical
00621 
00622 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00623 
00624   !> Read a string from a spec file that must have a given name.
00625   subroutine spec_file_read_string(file, name, var)
00626 
00627     !> Spec file.
00628     type(spec_file_t), intent(inout) :: file
00629     !> Name.
00630     character(len=*), intent(in) :: name
00631     !> Variable to store data.
00632     character(len=*), intent(out) :: var
00633 
00634     type(spec_line_t) :: line
00635 
00636     call spec_line_allocate(line)
00637     call spec_file_read_line_no_eof(file, line)
00638     call spec_file_check_line_name(file, line, name)
00639     call spec_file_check_line_length(file, line, 1)
00640     var = line%data(1)
00641     call spec_line_deallocate(line)
00642 
00643   end subroutine spec_file_read_string
00644 
00645 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00646 
00647   !> Read a complex number from a spec file that must have the given
00648   !> name.
00649   subroutine spec_file_read_complex(file, name, var)
00650 
00651     !> Spec file.
00652     type(spec_file_t), intent(inout) :: file
00653     !> Name.
00654     character(len=*), intent(in) :: name
00655     !> Variable to store data.
00656     complex(kind=dc), intent(out) :: var
00657 
00658     type(spec_line_t) :: line
00659 
00660     call spec_line_allocate(line)
00661     call spec_file_read_line_no_eof(file, line)
00662     call spec_file_check_line_name(file, line, name)
00663     call spec_file_check_line_length(file, line, 2)
00664     var = cmplx(spec_file_string_to_real(file, line%data(1)), &
00665          spec_file_string_to_real(file, line%data(2)), kind=dc)
00666     call spec_line_deallocate(line)
00667 
00668   end subroutine spec_file_read_complex
00669 
00670 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00671 
00672   !> Read an array of named lines with real data. All lines must have
00673   !> the same number of data elements.
00674   subroutine spec_file_read_real_named_array(file, max_lines, names, vals)
00675 
00676     !> Spec file.
00677     type(spec_file_t), intent(inout) :: file
00678     !> Max lines to read (0 = no max).
00679     integer, intent(in) :: max_lines
00680     !> Names of lines.
00681     character(len=SPEC_LINE_MAX_VAR_LEN), pointer :: names(:)
00682     !> Data values.
00683     real(kind=dp), pointer :: vals(:,:)
00684 
00685     type(spec_line_t), pointer :: line_array(:)
00686     integer :: num_lines, line_length, i, j
00687 
00688     allocate(line_array(0))
00689     call spec_file_read_line_array(file, max_lines, line_array)
00690     num_lines = size(line_array)
00691     deallocate(names)
00692     deallocate(vals)
00693     if (num_lines > 0) then
00694        line_length = size(line_array(1)%data)
00695        allocate(names(num_lines))
00696        allocate(vals(num_lines, line_length))
00697        do i = 1,num_lines
00698           names(i) = line_array(i)%name
00699           do j = 1,line_length
00700              vals(i,j) = spec_file_string_to_real(file, line_array(i)%data(j))
00701           end do
00702        end do
00703     else
00704        allocate(names(0))
00705        allocate(vals(0,0))
00706     end if
00707     do i = 1,num_lines
00708        call spec_line_deallocate(line_array(i))
00709     end do
00710     deallocate(line_array)
00711 
00712   end subroutine spec_file_read_real_named_array
00713 
00714 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00715 
00716   !> Read an a time-indexed array of real data.
00717   subroutine spec_file_read_timed_real_array(file, name, times, vals)
00718 
00719     !> Spec file.
00720     type(spec_file_t), intent(inout) :: file
00721     !> Variable name.
00722     character(len=*), intent(in) :: name
00723     !> Names of lines.
00724     real(kind=dp), pointer :: times(:)
00725     !> Data values.
00726     real(kind=dp), pointer :: vals(:)
00727     
00728     integer :: n_lines, n_times
00729     character(len=SPEC_LINE_MAX_VAR_LEN), pointer :: read_names(:)
00730     real(kind=dp), pointer :: read_data(:,:)
00731 
00732     allocate(read_names(0))
00733     allocate(read_data(0,0))
00734     call spec_file_read_real_named_array(file, 0, read_names, read_data)
00735 
00736     n_lines = size(read_names)
00737     if (n_lines /= 2) then
00738        call die_msg(694159200, 'must have exactly two data lines in file ' &
00739             // trim(file%name))
00740     end if
00741     n_times = size(read_data,2)
00742     if (n_times < 1) then
00743        call die_msg(925956383, 'must have at least one data poin in file ' &
00744             // trim(file%name))
00745     end if
00746     if (trim(read_names(1)) /= "time") then
00747        call die_msg(407039398, 'first data line in ' // trim(file%name) &
00748             // ' must start with: time not: ' // trim(read_names(1)))
00749     end if
00750     if (trim(read_names(2)) /= name) then
00751        call die_msg(692842968, 'second data line in ' // trim(file%name) &
00752             // ' must start with: ' // trim(name) &
00753             // ' not: ' // trim(read_names(2)))
00754     end if
00755 
00756     deallocate(times)
00757     deallocate(vals)
00758     allocate(times(n_times))
00759     allocate(vals(n_times))
00760     times = read_data(1,:)
00761     vals = read_data(2,:)
00762     deallocate(read_names)
00763     deallocate(read_data)
00764 
00765   end subroutine spec_file_read_timed_real_array
00766 
00767 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00768 
00769 end module pmc_spec_file