The Scientific Fortran Tools (SciFT) is a library specially oriented to scientific purposes for Fortran programmers. The library provides a wide range of mathematical routines such as random number generators, special functions, and high-level classes to manipulate strings, files parsing, matrices, grid-based numerical functions, data structures (lists, vectors, maps, graphs), and molecules.
System Requirements:
SciFT is known to work on GNU/Linux. However, it should work on any POSIX-compliant system.
Dependencies:
-
GNU Awk (gawk) (version >= 4.0)
-
Intel® Fortran Compiler (version >= 14.0.3)
SciFT has not been tested with any other compiler. -
Intel® Math Kernel Library (Intel® MKL)
SciFT has not been tested with any other math library.
Download the .zip file from this page and extract the files,
$ unzip scift-master.zip
Archive: scift-master.zip
3e330bbcb711cb2275ef1ce06aa021de764662f2
creating: scift-master/
inflating: scift-master/LICENSE
inflating: scift-master/LICENSE.FortranParser
inflating: scift-master/Makefile
...
$ mv scift-master scift
or clone the repository using git
$ git clone https://github.com/nfaguirrec/scift.git
The following should be the content of the scift directory if previous steps were successful:
$ cd scift
$ ls
docs examples LICENSE.FortranParser README.md src VERSION
doxyfile LICENSE Makefile SCIFTvars.sh utils
Enter in the scift directory (cd scift
) and modify the Makefile file (src/Makefile
) if necessary.
To build the code just type make inside the main directory as follows:
$ source SCIFTvars.sh
$ make
Building dependencies for Atom.f90 ... OK
Building dependencies for AtomicElementsDB.f90 ... OK
Building dependencies for BlocksIFileParser.f90 ... OK
...
Building n3df.eval.f90 (0:00.79)
Building n3df.func.f90 (0:00.63)
Building n3df.oper.f90 (0:00.67)
The basic environmental variables that SciFT needs can be loaded just adding the following command anywhere in the ~/.bashrc file:
source <PATH_TO_SCIFT>/SCIFTvars.sh
The following are some examples of how to use some important classes available in SciFT
class String
The following block (test.f90
) is an example of how to use the class String:
program test
use String_
type(String) :: str1, str2
integer :: int1
character(100), allocatable :: tokens(:)
integer :: i
str1 = "Hello"
str2 = str1+":fortran-string"
write(*,*) trim(str2.fstr)
call str2.split( tokens, ":-" )
do i=1,size(tokens)
write(*,*) i, " ", trim(tokens(i))
end do
call str2.replace( ":", " string " )
write(*,*) trim(str2.fstr)
call str2.replace( "string", "fortran", wholeWords=.true. )
write(*,*) trim(str2.fstr)
str1 = str2.toUpper()
write(*,*) trim(str1.fstr)
end program test
It is compiled an executed as follows:
$ ifort test.f90 -o test -I${SCIFT_HOME}/src -L${SCIFT_HOME}/src -lscift
$ ./test
Hello:fortran-string
1 Hello
2 fortran
3 string
Hello string fortran-string
Hello fortran fortran-string
HELLO FORTRAN FORTRAN-STRING
class RealList
The following block (test.f90
) is an example of how to use the class List (equivalent to list< double > in C++):
program test
use RealList_
type(RealList) :: mylist
class(RealListIterator), pointer :: iter
call mylist.init()
call mylist.append( 8.0_8 )
call mylist.append( 5.0_8 )
call mylist.append( 1.0_8 )
call mylist.prepend( 0.0_8 )
call mylist.append( [ 10.0_8, 11.0_8, 12.0_8 ] )
iter => mylist.begin
iter => iter.next
call mylist.insert( iter, 3.0_8 )
iter => mylist.begin
do while( associated(iter) )
write(*,"(A,F6.3)", advance="no") " --> ", iter.data
iter => iter.next
end do
end program test
It is compiled an executed as follows:
$ ifort test.f90 -o test -I${SCIFT_HOME}/src -L${SCIFT_HOME}/src -lscift
$ ./test
--> 0.000 --> 8.000 --> 3.000 --> 5.000 --> 1.000 --> 10.000 --> 11.000 --> 12.000
class List (containing user-defined objects)
The following block (test.f90
) is an example of how to specialize and use the class List to contain MyData objects. Notice that the class MyData must have defined the == operator (equivalent to list< MyData > in C++):
module MyData_
implicit none
private
type, public :: MyData
integer :: id
character(2) :: name
contains
generic :: operator(==) => MyData_eq
procedure :: MyData_eq
end type MyData
contains
function MyData_eq( this, other ) result( output )
class(MyData), intent(in) :: this, other
logical :: output
output = ( this.id == other.id .and. this.name == other.name )
end function MyData_eq
end module MyData_
module MyList_
use MyData_
implicit none
#define List MyList
#define ListBasicInterface
#define ListIterator MyListIterator
#define __CLASS_ITEMLIST__ class(MyData)
#define __TYPE_ITEMLIST__ type(MyData)
#include "List.h90"
#undef List
#undef ListBasicInterface
#undef ListIterator
#undef __CLASS_ITEMLIST__
#undef __TYPE_ITEMLIST__
end module MyList_
program test
use MyData_
use MyList_
type(MyList) :: list
class(MyListIterator), pointer :: iter
call list.init()
call list.append( MyData(1,"a") )
call list.append( MyData(5,"b") )
call list.prepend( MyData(0,"c") )
call list.append( [ MyData(0,"d"), MyData(1,"e"), MyData(2,"f") ] )
iter => list.begin
iter => iter.next
call list.insert( iter, MyData(3,"g") )
iter => list.begin
do while( associated(iter) )
write(*,"(A,I2,A3,A)", advance="no") " --> (", iter.data.id, iter.data.name, ")"
iter => iter.next
end do
end program test
It is compiled an executed as follows (notice it requires the Fortran preprocessor, -fpp):
$ ifort -fpp test.f90 -o test -I${SCIFT_HOME}/src -L${SCIFT_HOME}/src -lscift
$ ./test
--> ( 0 c ) --> ( 1 a ) --> ( 3 g ) --> ( 5 b ) --> ( 0 d ) --> ( 1 e ) --> ( 2 f )
class StringIntegerMap
The following block (test.f90
) is an example of how to use the class Map (equivalent to map<string, int> in C++):
program test
use String_
use StringIntegerPair_
use StringIntegerMap_
implicit none
type(StringIntegerPair) :: pair
type(StringIntegerMap) :: mymap
class(StringIntegerMapIterator), pointer :: iter
call mymap.init()
call mymap.insert( String("John"), 27 )
call mymap.insert( String("Marie"), 22 )
call mymap.insert( String("Luna"), 24 )
iter => mymap.begin
do while( associated(iter) )
pair = mymap.pair( iter )
write(*,"(A15,A,I2)") pair.first.fstr, " --> ", pair.second
iter => iter.next
end do
end program test
It is compiled an executed as follows:
$ ifort test.f90 -o test -I${SCIFT_HOME}/src -L${SCIFT_HOME}/src -lscift
$ ./test
John --> 27
Luna --> 24
Marie --> 22
class Map (containing user-defined objects)
The following block (test.f90
) is an example of how to specialize and use the class Map to contain String keys and MyData values. Notice that the class MyData must have defined the == operator (equivalent to map< string, MyData > in C++):
module MyData_
implicit none
private
type, public :: MyData
integer :: id
character(2) :: name
contains
generic :: operator(==) => MyData_eq
procedure :: MyData_eq
end type MyData
contains
function MyData_eq( this, other ) result( output )
class(MyData), intent(in) :: this, other
logical :: output
output = ( this.id == other.id .and. this.name == other.name )
end function MyData_eq
end module MyData_
module MyPair_
use String_
use MyData_
implicit none
private
#define Pair MyPair
#define PairBasicInterface
#define __CLASS_ITEMFIRST__ class(String)
#define __TYPE_ITEMFIRST__ type(String)
#define __CLASS_ITEMSECOND__ class(MyData)
#define __TYPE_ITEMSECOND__ type(MyData)
#define __ADD_ATTRIBUTES__
#define __ADD_METHODS__
#include "Pair.h90"
#undef Pair
#undef PairBasicInterface
#undef __CLASS_ITEMFIRST__
#undef __TYPE_ITEMFIRST__
#undef __CLASS_ITEMSECOND__
#undef __TYPE_ITEMSECOND__
#undef __ADD_ATTRIBUTES__
#undef __ADD_METHODS__
end module MyPair_
module MyPairList_
use String_
use MyPair_
implicit none
private
#define List MyPairList
#define ListBasicInterface
#define ListIterator MyPairListIterator
#define __CLASS_ITEMLIST__ class(MyPair)
#define __TYPE_ITEMLIST__ type(MyPair)
#include "List.h90"
#undef List
#undef ListBasicInterface
#undef ListIterator
#undef __CLASS_ITEMLIST__
#undef __TYPE_ITEMLIST__
end module MyPairList_
module MyMap_
use IOStream_
use String_
use MyData_
use MyPair_
use MyPairList_, MyMapIterator => MyPairListIterator
implicit none
private
public :: MyMapIterator
#define Map MyMap
#define MapBasicInterface
#define __CLASS_MAPITERATOR__ class(MyMapIterator)
#define __TYPE_MAPLIST__ type(MyPairList)
#define __TYPE_MAPPAIR__ type(MyPair)
#define __CLASS_MAPPAIR__ class(MyPair)
#define __CLASS_MAPVALUE__ class(MyData)
#define __TYPE_MAPVALUE__ type(MyData)
#define __ADD_METHODS__
#include "Map.h90"
#undef Map
#undef MapBasicInterface
#undef __CLASS_MAPITERATOR__
#undef __TYPE_MAPLIST__
#undef __TYPE_MAPPAIR__
#undef __CLASS_MAPPAIR__
#undef __CLASS_MAPVALUE__
#undef __TYPE_MAPVALUE__
#undef __ADD_METHODS__
end module MyMap_
program test
use String_
use MyData_
use MyPair_
use MyPairList_
use MyMap_
type(MyMap) :: mmap
class(MyMapIterator), pointer :: iter
type(MyPair) :: pair
call mmap.init()
call mmap.insert( String("John"), MyData(1,"a") )
call mmap.insert( String("Marie"), MyData(2,"b") )
call mmap.insert( String("Luna"), MyData(3,"c") )
iter => mmap.begin
do while( associated(iter) )
pair = mmap.pair( iter )
write(*,"(A15,A,I2,A3,A)") pair.first.fstr, &
" --> (", pair.second.id, pair.second.name, ")"
iter => iter.next
end do
end program test
It is compiled an executed as follows (notice it requires the Fortran preprocessor, -fpp):
$ ifort -fpp test.f90 -o test -I${SCIFT_HOME}/src -L${SCIFT_HOME}/src -lscift
$ ./test
John --> ( 1 a )
Luna --> ( 3 c )
Marie --> ( 2 b )
class IntegerGraph
The following block (test.f90
) is an example of how to use the class Graph (equivalent to GTL:graph in C++):
program test
use IntegerGraph_
type(IntegerGraph) :: mygraph
call mygraph.init( directed=.false. )
! (1)
! |
! (2)
! / \
! (3) (4)
! \ /
! (5)
call mygraph.newNodes( 5 )
call mygraph.newEdges( 1, [2] )
call mygraph.newEdges( 2, [1,3,4] )
call mygraph.newEdges( 3, [2,5] )
call mygraph.newEdges( 4, [2,5] )
call mygraph.newEdges( 5, [3,4] )
call mygraph.computeDijkstraPaths( 1 )
write(*,*) "distance from 1 to 5 = ", mygraph.distance(5)
end program test
It is compiled an executed as follows (notice it requires the MKL library):
$ ifort test.f90 -o test -I${SCIFT_HOME}/src -L${SCIFT_HOME}/src -lscift -mkl
$ ./test
distance from 1 to 5 = 3.00000000000000
class Molecule
The following block (test.f90
) is an example of how to use the class Molecule. It creates a hydrogen molecule, rotates it, and then show it on screen in the XYZ format:
program test
use UnitsConverter_
use Atom_
use Molecule_
implicit none
type(Atom) :: atm
type(Molecule) :: mol
call mol.init( 2, name="Hydrogen molecule" )
call atm.init( "H", 0.0_8, 0.0_8, 0.3561_8*angs ); mol.atoms(1) = atm
call atm.init( "H", 0.0_8, 0.0_8,-0.3561_8*angs ); mol.atoms(2) = atm
call mol.rotate( alpha=45.0*deg, beta=45.0*deg, gamma=0.0*deg )
call mol.save()
end program test
It is compiled and executed as follows (notice it requires the MKL library):
$ ifort test.f90 -o test -I${SCIFT_HOME}/src -L${SCIFT_HOME}/src -lscift -mkl
$ ./test
2
Hydrogen molecule
H 0.17805000 -0.25180072 0.17805000
H -0.17805000 0.25180072 -0.17805000
class Matrix
The following block (test.f90
) is an example of how to use the class Matrix. It creates the matrix, diagonalizes it, and then show the results in a nice format.
program test
use Matrix_
implicit none
type(Matrix) :: A, B, C
call A.init(5,5)
A.data(1,:) = [ 1.96, -6.49, -0.47, -7.20, -0.65 ]
A.data(2,:) = [ -6.49, 3.80, -6.39, 1.50, -6.34 ]
A.data(3,:) = [ -0.47, -6.39, 4.17, -1.51, 2.67 ]
A.data(4,:) = [ -7.20, 1.50, -1.51, 5.70, 1.80 ]
A.data(5,:) = [ -0.65, -6.34, 2.67, 1.80, -7.10 ]
write(*,*) ""
write(*,*) "A ="
call A.show( formatted=.true. )
call A.eigen( eVecs=B, eVals=C )
write(*,*) ""
write(*,*) "eigenvectors ="
call B.show( formatted=.true. )
write(*,*) ""
write(*,*) "eigenvalues ="
call C.show( formatted=.true. )
end program test
It is compiled and executed as follows (notice it requires the MKL library):
$ ifort test.f90 -o test -I${SCIFT_HOME}/src -L${SCIFT_HOME}/src -lscift -mkl
$ ./test
A =
1 2 3 4 5
1 1.960000 -6.490000 -0.470000 -7.200000 -0.650000
2 -6.490000 3.800000 -6.390000 1.500000 -6.340000
3 -0.470000 -6.390000 4.170000 -1.510000 2.670000
4 -7.200000 1.500000 -1.510000 5.700000 1.800000
5 -0.650000 -6.340000 2.670000 1.800000 -7.100000
eigenvectors =
1 2 3 4 5
1 -0.298067 -0.607513 -0.402620 -0.374481 0.489637
2 -0.507798 -0.287968 0.406586 -0.357169 -0.605255
3 -0.081606 -0.384320 0.659966 0.500764 0.399148
4 -0.003589 -0.446730 -0.455290 0.620365 -0.456375
5 -0.804130 0.448032 -0.172458 0.310768 0.162248
eigenvalues =
1 2 3 4 5
1 -11.065575 0.000000 0.000000 0.000000 0.000000
2 0.000000 -6.228747 0.000000 0.000000 0.000000
3 0.000000 0.000000 0.864028 0.000000 0.000000
4 0.000000 0.000000 0.000000 8.865457 0.000000
5 0.000000 0.000000 0.000000 0.000000 16.094837
- Nestor F. Aguirre ( nfaguirrec@gmail.com )