I am learning correct use of subroutine, function and module, below is an simple example, no error occurs while compiling, after executing, the outcome is 4.57187637E-41 rather than pi, I have looked up several references, haven't found out the mistake yet.
module wz
implicit none
private
public :: print_out
real,parameter :: pi = 3.14159
contains
subroutine print_out
implicit none
real :: area
print *, area
end subroutine print_out
function f(x) result(area)
implicit none
real, intent(in):: x
real :: area
area = pi * x ** 2
end function f
end module wz
program test_module
use wz
implicit none
real :: x
x = 1.
call print_out
end program test_module
The value you are printing is area just after declaration and before doing anything with it. You need to pass x to f function, and you can do that via the print_out subroutine:
module wz
implicit none
private
public :: print_out
real,parameter :: pi = 3.14159
contains
subroutine print_out(x)
implicit none
real, intent(in) :: x
real :: area
area = f(x)
print *, area
end subroutine print_out
function f(x) result(area)
implicit none
real, intent(in):: x
real :: area
area = pi * x ** 2
end function f
end module wz
program test_module
use wz
implicit none
real :: x
x = 1.
call print_out(x)
end program test_module
Related
I have a rather large code (>6000 lines)that with a problem that I try to illustrate with the following very simplified extract:
program TestFortran
implicit none
real, parameter :: eps = 1d-30
real :: res
real :: tmp
call TestInitialisation(res,tmp)
if (res>0 .and. res <eps) then
write(*,*) "res is small but not zero and tmp = ", tmp
res = 0d0
else
write(*,*) "res is zero and tmp = ", tmp
end if
contains
subroutine TestInitialization(output,out2)
real,intent(out) :: output
real,intent(out) :: out2
real :: origa(10,10)
real :: copya(10,10)
origa = 0d0
copya = origa
call TIS1(copya,output,out2)
end subroutine TestInitialization
subroutine TIS1(arr2d,ret,out2)
real,intent(in) :: arr2d(:,:)
real,intent(out) :: ret
real,intent(out) :: out2
integer :: ii
do ii = 1,size(arr2d,2)
call TIS2(arr2d(:,ii),ii,ret,out2)
if (ret > 0) then
exit
end if
end do
end subroutine TIS1
subroutine TIS2(arr1d,jj,ret,out2)
real,intent(in) :: arr1d(:)
real,intent(out) :: ret
real,intent(out) :: out2
integer :: ii
integer,intent(in):: jj
do ii = 1,size(arr1d)
ret = arr1d(ii)
out2 = real(jj)
if (ret > 0) then
out2 = -1d0
exit
end if
end do
end subroutine TIS2
end program TestFortran
The real program does work as expected in debug mode. However, when in release mode (visual studio 2017 with intel compiler 2017), switch /O3, the res value is just garbage (like 1.0831d-273, however I am unsure weather to trust the variable explorer when debugging optimized code). I could not recreate the situation with the example above, it just serves as illustration (thetmp variable is there for it not to just optimize the whole thing away). If I add a write(*,*) "res in TIS2 =",resin subroutine TIS2 in the real program code, the result is correct, but this it not wanted (especially because of speed degradation).
I have tested various compiler flags compbinations; i.e. the following:
/debug:full /O2 /Qinit:snan /Qinit:arrays /fpe:0 /Qipo /traceback
/check:uninit /arch:SSE3 /real_size:64 /fp:fast=2 /Qvec-threshold:60 /recursive
Does anyone have any hint's or comments on this?
I had made a mistake (bug) where an array wasn't fully populated correctly. I found this using the compiler flags: /Qinit:snan together with /Qinit:arrays in debug mode. It did not show up in release mode.
So all in all it was just a fairly simple bug in my code that went unnoticed, mostly (in 99 % of the cases) everything went well, but not always. The strange thing was that it wasn't caught in release mode.
I have written the following program in fortran90:
module constants
real*8, parameter :: zero = 0.0d0
real*8, parameter :: one = 1.0d0
real*8, parameter :: two = 2.0d0
end module constants
module common
use constants
real*8 :: a_A, a_B, e_A, e_B, b_A, b_B
end module common
module procedures
use constants
contains
function f(p)
use common
real*8, dimension(2), intent(in) :: p
real*8, dimension(2) :: f
f(1) = a_A*((two*p(1)/p(1) + p(2))**(-e_A)) - (exp(b_A*p(1)) - one)
f(2) = a_B*((two*p(2)/p(1) + p(2))**(-e_B)) - (exp(b_B*p(2)) - one)
f = f
return
end function f
subroutine wait
write(6,"('Waiting...')")
read *
return
end subroutine wait
end module procedures
program main
use constants
use common
use procedures
use toolbox
real*8, dimension(2) :: plow,phigh,pmin
a_A = one
a_B = one
e_A = one
e_B = one
b_A = 0.1d0
b_b = 0.1d0
plow(1) = 6.0d0
plow(2) = 6.0d0
phigh(1) = 8.0d0
phigh(2) = 8.0d0
pmin = one
call fminsearch(pmin,fret,plow,phigh,f)
write(6,"(3f15.8)") pmin(1),pmin(2), fret
end program main
When I run it I get the following error
call fminsearch(pmin, fret, plow, phigh, f)
1
Error: There is no specific subroutine for the generic ‘fminsearch’ at (1)
I think it is a problem with my function arguments, but could anybody give me some clarity as to what is going wrong? I am new to fortran and do not quite understand. As far as I can tell, I have declared the x with intent(in) and have declared the vector output of the function.
Thank you
I want to build a hash table module that can use different instances in Fortran 90 (I am not exactly sure what to name this). This is what I am trying to achieve:
module hashing
implicit none
private
real, dimension(:), allocatable :: &
real1
public :: &
Hash, hash_init, hash_push, hash_set, hash_get, &
hash_print
type Hash
character (len=128) :: &
data_type
integer :: &
array_size
end type Hash
contains
subroutine hash_init (this)
type(Hash), intent (in) :: &
this
if (trim(this%dtype) == "real1) then
call make_real1(this%array_size)
end if
end subroutine hash_init
subroutine hash_print (this)
type(Hash), intent (in) :: &
this
if (trim(this%dtype) == "real1) then
print *, real1
end if
end subroutine hash_print
end module hashing
So, in my test program, both call hash_print statements prints an array of size 5, because the real1 array is a general instance of module hashing, instead of (what I am trying to achieve) printing the first instance of size 10 and the second instance of size 5.
program test
use hashing
implicit none
type(Hash) :: &
inst1, inst2
inst1 = Hash("real1", 10)
inst2 = Hash("real1", 5)
call hash_init(inst1)
call hash_init(inst2)
call hash_print(inst1)
call hash_print(inst2)
end program test
The main idea is to add integer and character type dimensions as well and using and expanding on the if statements, but I need to know where in the module I need to declare these allocatable dimensions so that they are bound to a specific instance only. If possible! I've tried declaring the allocatable array inside the hash_init subroutine, but then it is not available for the hash_print subroutine.
I am often confronted with the question whether it is better to pass large arrays and subsets thereof as arguments or use modules instead. For example:
type( plant_type ), dimension( 5, 50000 ) :: plant
Note that one dimension is very long and the other much smaller.
The argument that is passed is only a subset of the array:
call plantgrowth( plant(:,icell) )
Instead of passing this argument , I could also call plantgrowth() without the argument by adding a
use md_biosphere, only: plant
inside the subroutine plantgrowth().
==> Which option works faster?
Here are the alternative Fortran examples:
Using arguments:
module md_biosphere
implicit none
private
public :: biosphere, plant_type ! only plant_type (not plant) is made public, but not instance of the type ('plant')
! the important aspect here is that ncells >> nplant
integer, parameter :: ncells = 500000
integer, parameter :: nplant = 50
type plant_type
real :: foliage
real :: roots
real :: wood
end type plant_type
type( plant_type ), dimension( nplant, ncells ) :: plant
contains
subroutine biosphere()
integer :: icell
do icell=1,ncells
call plantgrowth( plant(:,icell) )
end do
end subroutine biosphere
subroutine plantgrowth( plant )
type( plant_type ), dimension(nplant), intent(inout) :: plant
integer :: iplant
! more stuff here ...
do iplant=1,nplant
plant(iplant)%foliage = 1.0
plant(iplant)%roots = 1.0
plant(iplant)%wood = 1.0
end do
end subroutine plantgrowth
end module md_biosphere
!//////////////////////////////////////////////////////////
program example_module
use md_biosphere, only: biosphere
implicit none
call biosphere()
end program example_module
Using 'use module':
module md_biosphere
implicit none
private
public :: biosphere, plant ! instance 'plant' is made public and does not have to be passed as argument
! the important aspect here is that ncells >> nplant
integer, parameter :: ncells = 500000
integer, parameter :: nplant = 50
type plant_type
real :: foliage
real :: roots
real :: wood
end type plant_type
type( plant_type ), dimension( nplant, ncells ) :: plant
contains
subroutine biosphere()
integer :: icell
do icell=1,ncells
! no arguments are passed
call plantgrowth( icell )
end do
end subroutine biosphere
subroutine plantgrowth( icell )
integer, intent(in) :: icell
integer :: iplant
! more stuff here ...
do iplant=1,nplant
plant(iplant,icell)%foliage = 1.0
plant(iplant,icell)%roots = 1.0
plant(iplant,icell)%wood = 1.0
end do
end subroutine plantgrowth
end module md_biosphere
!//////////////////////////////////////////////////////////
program example_module
use md_biosphere, only: biosphere
implicit none
call biosphere()
end program example_module
I have a nested loop which is supposed to iterate over a an N-dim cube (line, square, cube,...)
So far I do this using nested loops, eg.
for 2D:
do i = 1,Ni
do j = 1,Nj
! do stuff with f(i,j)
enddo
enddo
or 3D:
do i = 1,Ni
do j = 1,Nj
do k = 1,Nk
! do stuff with f(i,j,k)
enddo
enddo
enddo
I would like to replace these nested loops with a construct that works for every possible N-dimensional case. How can I do this in Fortran? In C++ one can use iterators. Is there something like this in Fortran?
I am considering writing a class, which kind of works like a mechanical n-dimensional counter (i.e. if we count 3 per dimension):
0,0,0,0,0
1,0,0,0,0
2,0,0,0,0
0,1,0,0,0
1,1,0,0,0
Would this be somewhat fast, compared to nested for loops? Do you guys have better ideas?
This may be the easiest...
Also you will note that the index order for the array is reversed. Fortran in fastest in the left, so it is opposite of C.
When you call it it uses which ever one matches the array dimensions that you sent to it automagically, by checking the interface of the module.
MODULE Stuff
IMPLICIT NONE
PUBLIC MY$Work
INTERFACE MY$Work
MODULE PROCEDURE MY$Work1D, MY$Work2D, MY$Work3D
END INTERFACE
PRIVATE
CONTAINS
!~~~~~~~~~~
SUBROUTINE MY$Work1d(Array, F_of_Array)
REAL, DIMENSION(:), INTENT(IN ) :: Array
REAL, DIMENSION(:), INTENT(INOUT) :: F_of_Array
INTEGER :: I
!DIR$ DO SIMD
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i)
enddo
RETURN
END SUBROUTINE MY$Work1d
!~~~~~~~~~~
SUBROUTINE MY$Work2d(Array, F_of_Array)
REAL, DIMENSION(:,:), INTENT(IN ) :: Array
REAL, DIMENSION(:,:), INTENT(INOUT) :: F_of_Array
INTEGER :: I,J
!DEC$ UNROLL_AND_JAM
do j = LBOUND(Array,2) ,UBOUND(Array,2)
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i,j)
enddo
enddo
RETURN
END SUBROUTINE MY$Work2d
!~~~~~~~~~~
SUBROUTINE MY$Work3d(Array, F_of_Array)
REAL, DIMENSION(:,:,:), INTENT(IN ) :: Array
REAL, DIMENSION(:,:,:), INTENT(INOUT) :: F_of_Array
INTEGER :: I,J,K
!DEC$ UNROLL_AND_JAM
do k = LBOUND(Array,3) , UBOUND(Array,3)
do j = LBOUND(Array,2) ,UBOUND(Array,2)
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i,j,k)
enddo
enddo
enddo
RETURN
END SUBROUTINE MY$Work3d(Array, F_of_Array)
END MODULE Stuff
PROGRAM XX
USE STUFF
...
So you could have a 3D array and do this
DO K = 1, nk
CALL MY$WORK(Array(:,:,k), ResultArray(:,:,K) )
ENDDO
That would use the 2D version and loop over it for all the K-cases...
I decided to use a super index. The size of my dimensions is limited to powers of two. This allows me to use bitshift operations and regular addition. Hopefully this is faster than a object-oriented counter.
pure function supI(j, k, n) result(vec)
implicit none
integer*8, intent(in) :: j
integer*8 :: copy
integer*4, intent(in) :: k, n
integer*4 :: vec(n), x, mask
! transforms super index j to a n-dimensional iteration,
! where each dimension has a range of 2^k
! mask to extract left most indicies
mask = ISHFT(1, k) -1
copy = j
do x = 1,n
! extract current value using mask
vec(x) = and(copy, mask)
! shift to next value
copy = ISHFT(copy, -k)
enddo
end function supI
A 3d counter with 4 in each dimension would look like this:
do j = 0,64
write(*,*) supI(j, 2, 3)
enddo
Edit: Compared to loop speed without optimization it is not to bad: ~20% more time, but If I use the optimizer it is much much slower than nested loops.