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 testIt 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 testIt 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 testIt 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 testIt 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 testIt 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 testIt 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 testIt 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 testIt 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 )