Skip to content

handley-lab/forutils

 
 

Repository files navigation

ForUtils

ForUtils:Various fortran 2003/2008 utility classes.
Version: 1.0
Author: Antony Lewis
Homepage:https://github.com/cmbant/forutils
Code documentation:https://cosmologist.info/forutils/

ForUtils is a modern Fortran utility library that provides essential tools for scientific computing and data processing. It offers Python-like convenience functions and object-oriented interfaces for common programming tasks in Fortran 2003/2008 programs.

Key Features:

  • ArrayUtils - Find (minimal/maximal) index of an element in an array.
  • FileUtils - Classes for handling file access, python-like loadtxt/savetxt functions
  • IniObjects - Read/Write name=value configuration files with inheritance, array and default value support.
  • MatrixUtils - Read/Write matrices and interface to some BLAS/LAPACK routines.
  • MiscUtils - Utility functions for optional arguments.
  • MpiUtils - Wrappers for MPI-routines to compile with(out) MPI library.
  • ObjectLists - Lists of arbitrary objects including specializations for vectors.
  • RandUtils - Some functions to generate random numbers.
  • RangeUtils - Maintain sets of equally spaced intervals, e.g. for integration ranges.
  • StringUtils - Utilities for strings, like concat of distinct types a.s.o.

For a class summary see the class trees.

Clone this git repository:

$ git clone https://github.com/cmbant/forutils

Compile:

$ make all

This generates the subdirectories Debug and Release and when an MPI library is available also DebugMPI and ReleaseMPI. Each directory contains a libforutils.a archive, which can be used directly for static linking on the compiler command line by giving the absolute filename:

forutils/<RTYPE>/libforutils.a

or by specifying it as a library:

-Lforutils/<RTYPE> -lforutils

Specify one of Debug, DebugMPI, Release, or ReleaseMPI for <RTYPE>. The Debug release types contain debug symbols and use no optimization, while the Release types use a reasonable level of optimization.

Reading and writing text files:

use FileUtils
Type(TTextFile) :: F
character(LEN=:), allocatable :: line

! Write to file
call F%CreateFile('output.txt')
call F%Write('#comment header')
call F%Write('name = ', 3.04)
call F%Write('test values')
call F%Close()

! Read file line by line, skipping comments
do while (F%ReadNextContentLine('output.txt', line))
    print *, 'Read: ', line
end do

Python-like loadtxt/savetxt functions:

use FileUtils
real(kind(1.d0)), allocatable :: matrix(:,:), vector(:)

! Load data from text file (like numpy.loadtxt)
call File%LoadTxt('data.txt', matrix)
call File%LoadTxt('vector.txt', vector)

! Save data to text file (like numpy.savetxt)
call File%SaveTxt('output_matrix.txt', matrix)
call File%SaveTxt('output_vector.txt', vector)

String formatting and manipulation:

use StringUtils
character(LEN=:), allocatable :: result, joined

! Format strings (printf-style)
result = FormatString('Test %d for %f %s', 91, 3.04, 'result')
! result = 'Test 91 for 3.0400 result'

! Join strings with separator
joined = Join(',', 'apple', 'banana', 'cherry')
! joined = 'apple,banana,cherry'

! Case conversion
print *, UpperCase('hello world')  ! 'HELLO WORLD'
print *, LowerCase('HELLO WORLD')  ! 'hello world'

Working with string lists:

use ObjectLists
Type(TStringList) :: strings

! Add strings to list
call strings%Add('here')
call strings%Add('there')
call strings%Add('alpha')

! Sort the list
call strings%Sort()

! Access items
print *, strings%Item(1)  ! 'alpha' (first after sorting)
print *, strings%Item(3)  ! 'there'

! Find index of item
print *, strings%IndexOf('here')  ! returns index or -1 if not found

! Key-value pairs
call strings%Clear()
call strings%Add('key1', 'value1')
call strings%Add('key2', 'value2')
print *, strings%ValueOf('key1')  ! 'value1'

Working with numeric lists:

use ObjectLists
Type(TRealList) :: numbers
Type(TRealArrayList) :: arrays
integer :: i

! Add numbers to list
call numbers%Add(0.5d0)
call numbers%Add(-3.0d0)
call numbers%Add(12.0d0)
do i = 1, 10
    call numbers%Add(i * 1.0d0)
end do

! Sort and access
call numbers%Sort()
print *, numbers%Item(1)  ! smallest value
print *, numbers%AsArray()  ! convert to regular array

! Lists of arrays
call arrays%Add([0.5d0])
call arrays%Add([-3.0d0, 1.0d0])
print *, arrays%Item(1,1)  ! first element of first array
print *, arrays%Item(2,2)  ! second element of second array

Reading INI-style configuration files:

use IniObjects
Type(TIniFile) :: ini
real :: x
double precision :: y
character(LEN=:), allocatable :: path

! Read from file
call ini%Open('config.ini')

! Read different types
path = ini%Read_String('parameter')
call ini%Read('x', x)
call ini%Read('x', y)  ! automatic type conversion

call ini%Close()

! Environment variable expansion
! If config contains: parameter = test$(PATH)/mypath
! It will expand $(PATH) with the actual PATH environment variable

Dynamic array reallocation:

use ArrayUtils
real, allocatable :: arr(:)
integer, allocatable :: iarr(:)

! Initial allocation
allocate(arr(3), source = [1.0, 2.0, 3.0])

! Reallocate (preserves existing data)
call reallocate(arr, 5)  ! expand to 5 elements
call reallocate(arr, 2)  ! shrink to 2 elements

! Works with different types
call reallocate(iarr, 10)
iarr(5) = 42
call reallocate(iarr, 20)  ! iarr(5) still equals 42

Cubic spline interpolation:

use Interpolation
Type(TCubicSpline) :: spline
Type(TRegularCubicSpline) :: reg_spline
real(kind(1.d0)), allocatable :: x(:), f(:)
real(kind(1.d0)) :: test_x, interpolated_value, derivative
integer :: i

! Prepare data points
allocate(x(100), f(100))
do i = 1, 100
    x(i) = 0.5367d0 * real(i, kind(1.d0)) + 0.3d0
    f(i) = (x(i)/47.2d0)**3 + (x(i)/5.5d0)**2 + x(i)*3.5d0 + 4.4579d0
end do

! Initialize irregular spline
call spline%Init(x, f)

! Initialize regular spline (evenly spaced x values)
call reg_spline%Init(x(1), x(size(x)), 100, values=f)

! Interpolate at any point
test_x = 13.2623d0
interpolated_value = spline%Value(test_x)
derivative = spline%Derivative(test_x)

! Interpolate arrays of values
real(kind(1.d0)) :: test_points(3) = [7.3d0, 9.0d0, 34.34643d0]
real(kind(1.d0)) :: results(3)
call reg_spline%Array(test_points, results)

Binary file I/O and object serialization:

use FileUtils, ObjectLists
Type(TBinaryFile) :: bf
Type(TStringList) :: list

! Save object to binary file
call list%Add('item1')
call list%Add('item2')

call bf%CreateFile('data.bin')
call list%SaveBinary(bf%unit)
call bf%Close()

! Load object from binary file
call list%Clear()
call bf%Open('data.bin')
call list%ReadBinary(bf%unit)
call bf%Close()

File utility functions:

use FileUtils
logical :: exists
character(LEN=:), allocatable :: path, name, ext

! Check file existence
exists = File%Exists('myfile.txt')

! Extract file components
path = File%ExtractPath('/home/user/data.txt')    ! '/home/user/'
name = File%ExtractName('/home/user/data.txt')    ! 'data.txt'
ext = File%ExtractExt('/home/user/data.txt')      ! '.txt'

! Get file information
print *, File%Size('myfile.txt')     ! file size in bytes
print *, File%TxtFileLines('data.txt')   ! number of lines
print *, File%TxtFileColumns('data.txt') ! number of columns

ForUtils includes comprehensive unit tests. To run them:

$ cd tests
$ make
$ ./run_tests.sh

The tests demonstrate practical usage patterns and can serve as additional examples for learning the library.

Most commonly used modules and types:

  • FileUtils: TTextFile, TBinaryFile, File%LoadTxt(), File%SaveTxt()
  • StringUtils: FormatString(), Join(), UpperCase(), LowerCase()
  • ObjectLists: TStringList, TRealList, TRealArrayList
  • IniObjects: TIniFile for configuration files
  • ArrayUtils: reallocate() for dynamic arrays
  • Interpolation: TCubicSpline, TRegularCubicSpline

Basic usage pattern:

program example
    use FileUtils
    use StringUtils
    use ObjectLists
    implicit none

    Type(TTextFile) :: file
    Type(TStringList) :: items
    character(LEN=:), allocatable :: formatted

    ! Create and write to file
    call file%CreateFile('example.txt')
    call file%Write('# Example data file')
    call file%Write(FormatString('Value: %f', 3.14159))
    call file%Close()

    ! Read and process
    call items%AddFromFile('example.txt', nodups=.false.)
    call items%WriteItems()  ! print all items

end program example
  • Fortran 2008 compatible compiler - E.g., ifort 14+, gfortran 6 or higher.
  • MPI library - Only when you want the MpiUtils fully functional. Without an MPI library MpiUtils compile, but the functions are merely no-ops and the makefile target DebugMPI and ReleaseMPI can not be built.

About

Fortran 2008 utility functions and reusable classes

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Fortran 98.8%
  • Other 1.2%