Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/pnavaro/fortran-vs-julia

Fortran-Julia syntax comparison and Maxwell Solver in 2D using Yee numerical scheme and MPI topology
https://github.com/pnavaro/fortran-vs-julia

cheatsheet fdtd fortran90 julia julia-language language-comparison maxwell maxwell-equations-solver mpi

Last synced: 3 months ago
JSON representation

Fortran-Julia syntax comparison and Maxwell Solver in 2D using Yee numerical scheme and MPI topology

Awesome Lists containing this project

README

        

# Julia Syntax: Comparison with Fortran

This is a simple cheatsheet and some performance comparison for scientific programmers who are interested in discover Julia.
It is not an exhaustive list. This page is inspired from [A Cheatsheet for Fortran 2008 Syntax: Comparison with Python 3](https://github.com/wusunlab/fortran-vs-python/).



Fortran
Julia


Top-level constructs




the main program


program my_program
...
end program



function my_program()
...
end
my_program()

Not required but it is recommended to use a function for your main program


modules


module my_module
...
end module my_module




module MyModule
...
end




subroutines


subroutine my_subroutine
...
end subroutine my_subroutine



function my_subroutine!
...
end

The bang in the function name is a convention if a function mutates one or more of its arguments. The convention is that the modified arguments should (if possible) come first.



functions


function f(x) result(res)
res = ...
end function f




function my_function(x)
...
return res
end




Generic interface


module cube_root_functions
interface cube_root
function s_cube_root(x)
real :: s_cube_root
real, intent(in) :: x
end function s_cube_root
function d_cube_root(x)
double precision :: d_cube_root
double precision, intent(in) :: x
end function d_cube_root
end interface
end module cube_root_functions
function s_cube_root(x)
real :: s_cube_root
real, intent(in) :: x
s_cube_root = x ** (1.0/3.0)
end function s_cube_root
function d_cube_root(x)
double precision :: d_cube_root
double precision, intent(in) :: x
d_cube_root = x ** (1.0d0/3.0d0)
end function d_cube_root




cube_root( x :: Float32 ) :: Float32 = x^(1/3)
cube_root( x :: Float64 ) :: Float64 = x^(1/3)




submodules


module main_module
...
contains
<submodule statements>
end module main_module



module MainModule
...
module SubModule
...
end
end



import statement


use my_module
use my_module, only : fun1, var1




using MyModule
import MyModule: fun1, var1




call subroutines and functions


call my_subroutine(args)
my_function(args)




my_function(args)




abort a program


stop




exit()




inline comments


! This is a comment




# This is a comment




include external source files


include 'source_file_name'



include("source_file_name")



Control flow patterns




if construct


if <logical expr> then
...
else if <logical expr> then
...
else
...
end if




if <logical expr>
...
elseif <logical expr>
...
else
...
end




case construct


select case <expr>
case <value>
...
case <value>
...
case default
...
end select


Not supported. Possible alternative is to use the ternary
 ? : 
syntax:

function case(x)
x == 1 ? println(1) :
x + 1 == 3 ? println(2) :
x == 3 ? println(3) :
println("greater than 3")
end




do construct


do i = start_value, end_value, step
...
end do




for i in start:step:end
...
end




do while construct


do while <logical expr>
...
end do




while <logical expr>
...
end




break from a loop


exit




break




leave this iteration and continue to the next iteration


cycle




continue




Data types




declaration


integer(kind=8) :: n = 0
real(kind=8) :: x = 0.




n = 0
n :: Int64 = 0
x = 0.
x :: Float64 = 0.




named constants


integer, parameter :: answer = 42
real(8), parameter :: pi = 4d0 * atan(1d0)




const answer = 42

pi is a named constant in Julia standard.



complex number


complex :: z = (1., -1.)




z = 1 - 1im
z = complex(1, -1)




string


character(len=10) :: str_fixed_length
character(len=:), allocatable :: str_var_length




string = "this is a string"




pointer


real, pointer :: p
real, target :: r
p => r




p = Ref(r)




boolean


.true.
.false.




true
false




logical operators


.not.
.and.
.or.
.eqv.
.neqv.




!
&&
||

Other logical operators do not have built-in support.



equal to


==, .eq.




==




not equal to


/=, .ne.




!==




greater than


>, .gt.




>




less than


<, .lt.




<




greater than or equal to


>=, .ge.




>=




less than or equal to


<=, .ge.




<=




array declaration


real(8), dimension(3) :: a = [1., 2., 3.]




a = [1., 2., 3.]




string array declaration


character(len=20), dimension(3, 4) :: char_arr




char_arr = String[]
push!(char_arr, new_string)

There is no easy way to preallocate space for strings.



elementwise array operations


a op b

op can be +, -, *, /, **, =, ==, etc.

This is supported since the Fortran 90 standard.

Supported by using the broadcast operator `.`and the `f.(x)` syntax


first element


a(1)




a[1] (or a[begin] for general indexing)




slicing


a(1:5)

This slice includes a(5).



a[1:5] (or @view(a[1:5]) for non-allocating slicing)

This slice includes a[5].



slicing with steps


a(1:100:2)




a[1:2:100]




size


size(a)




length(a)




shape


shape(a)




size(a)




shape along a dimension


size(a, dim)




size(a, dim)




Type conversion




to integer by truncation


int(x)




trunc(Int, x )




to integer by rounding


nint()




round()




integer to float


real(a[, kind])




float()




complex to real


real(z[, kind])




real()




to complex


cmplx(x [, y [, kind]])




complex()




to boolean


logical()




Bool()




Derived data types




definition


type Point
real(8) :: x, y
end type Point




struct Point
x :: Float64
y :: Float64
end




instantiation


type(Point) :: point1 = Point(-1., 1.)




point1 = Point(-1., 1.)




get attributes


point1%x
point1%y




point1.x
point1.y




array of derived type


type(Point), dimension(:), allocatable :: point_arr



point_arr = Vector{Point}



type bound procedures (aka class method)
Assume that Circle has a type bound procedure (subroutine) print_area.

type(Circle) :: c
call c%print_area


Assume that Circle has a method print_area(c :: Circle).

c = Circle()
print_area(c)




Built-in mathematical functions




functions with the same names


abs(), cos(), cosh(), exp(), floor(), log(),
log10(), max(), min(), sin(), sinh(), sqrt(),
sum(), tan(), tanh(), acos(), asin(), atan()


Have the same name in Julia.



functions with different names


aimag()
atan2(x, y)
ceiling()
conjg(z)
modulo()
call random_number()




imag()
atan(x, y)
ceil()
conj()
mod(), %
Random.rand()




Built-in string functions




string length


len()




length()




string to ASCII code


iachar()




Int()




ASCII code to string


achar()




String()




string slicing
Same as 1D array slicing.
Same as 1D array slicing.


find the position of a substring


index(string, substring)




findfirst(substring, string)




string concatenation


"hello" // "world"




"hello" * "world"
string("hello", "world")




Array constructs




where construct


where a > 0
b = 0
elsewhere
b = 1
end where




b[a .> 0] .= 0
b[a .<= 0] .= 1

or (faster - does not allocate an intermediate array):

for i in eachindex(a)
a[i] > 0 ? b[i] = 0 : b[i] = 1
end




Comprehension

    

integer, parameter :: n = 20
integer, parameter :: m = n*(n+1)/2
integer :: i, j
complex, dimension(m) :: a
a = [ ( ( cmplx(i,j), i=j,n), j=1,n) ]




a = [ complex(i,j) for j=1:n for i=j:n]




forall construct


real, dimension(10, 10) :: a = 0
int :: i, j
...
forall (i = 1:10, j = 1:10, i <= j)
a(i, j) = i + j
end forall




a = zeros(Float32, 10, 10)
for i in 1:10, j in 1:10
if i <= j
a[i, j] = i + j
end
end




CPU time


call cpu_time()




time = @elapsed begin
...
end




command line arguments


call command_argument_count()
call get_command()
call get_command_argument()


For basic parsing, use ARGS


Input/output




print


print fmt, <output list>




println()




read from the command prompt


read fmt, <input list>




readline()




open a file


open(unit, file, ...)




f = open(file, 'r')




read from a file


read(unit, fmt, ...) <input list>




read(f)
readlines(f)




write to a file


write(unit, fmt, ...) <output list>




write(f, ...)




close a file


close(unit, ...)




close(f)




file inquiry


inquire(unit, ...)



isfile("my_file.txt")



backspace in a file


backspace(unit, ...)




skip(f, -1)




end of file (EOF)


endfile(unit, ...)




seekend(f)




return to the start of a file


rewind(unit, ...)




seekstart(f)


## Maxwell parallel solver in 2D

Here an example of a Fortran to Julia translation. We use the Yee numerical scheme FDTD: [Finite-Difference Time-Domain method](https://en.wikipedia.org/wiki/Finite-difference_time-domain_method) and MPI topology.
You can find a serial version and a parallel version using MPI library.

Test your [MPI.jl](https://juliaparallel.github.io/MPI.jl/stable/installation/) installation with

```
$ mpirun -np 4 julia --project hello_mpi.jl
Hello world, I am 0 of 4
Hello world, I am 3 of 4
Hello world, I am 1 of 4
Hello world, I am 2 of 4
```
### Performances (without disk IO)

On small program like this in Julia is really fast.

### Serial computation

#### 1200 x 1200 and 1000 iterations.

- `julia -O3 --check-bounds=no maxwell_serial.jl` : 14 seconds
- `make && time ./maxwell_serial_fortran` : 31 seconds

#### 1200 x 1200 on 9 processors and 1000 iterations

- `make && time mpirun -np 9 ./maxwell_mpi_fortran` : 7 seconds
- `mpirun -np 9 julia --project -O3 --check-bounds=no ` : 5 seconds

### Plot the magnetic field

Uncomment the plot_fields call in Julia programs or change idiag value in input_data for fortran.

```
gnuplot bz.gnu
```
![](bz_field.gif)