Skip to content

cmbant/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

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages