How should I call a Fortran function? - fortran

How should I call a Fortran function?
I am trying to call DLANSY but it erroneously returns 0. See the code and the program output below.
SUBROUTINE COND(TYP,N,A,LDA,IPIV,WORK,LWORK,IWORK,INFO,RCOND)
INTEGER TYP, N, LDA, IPIV(*), IWORK(*), INFO, LWORK
DOUBLE PRECISION A(LDA,*), ANORM, RCOND, WORK(*)
CHARACTER*1 UPLO
EXTERNAL DLANSY, DSYTRF, DSYCON
IF (TYP .EQ. 0) THEN
UPLO = 'L'
ELSE
UPLO = 'U'
ENDIF
DO I = 1, N
DO J = 1,N
WRITE(*,*) I,J,A(I,J)
END DO
END DO
WRITE(*,*) 'TYPE ',UPLO
WRITE(*,*) 'N ',N
WRITE(*,*) 'LDA ',LDA
ANORM = DLANSY('1', UPLO, N, A, LDA, WORK)
C ANORM = 10;
WRITE(*,*) 'ANORM ',ANORM
END
And what it prints:
1 1 1.0000000000000000
1 2 2.0000000000000000
1 3 3.0000000000000000
1 4 4.0000000000000000
2 1 1.0000000000000000
2 2 2.0000000000000000
2 3 3.0000000000000000
2 4 4.0000000000000000
3 1 1.0000000000000000
3 2 2.0000000000000000
3 3 3.0000000000000000
3 4 4.0000000000000000
4 1 1.0000000000000000
4 2 2.0000000000000000
4 3 3.0000000000000000
4 4 4.0000000000000000
TYPE L
N 4
LDA 4
ANORM 0.0000000000000000
In the input arrays are of proper size.
What is going on?

You need to tell the compiler that DLANSY returns a double precision value, rather than real, which is what you get currently via the implicit typing rules. E.g. with a line like
double precision, external :: dlansy
Or, if for some strange reason one is limited to some ancient compiler that does not support F90:
DOUBLE PRECISION DLANSY
EXTERNAL DLANSY

Related

how to receive a triangle shape output in Fortran

I was trying to write code with this output:
1
1 2 1
1 2 3 2 1
1 2 3 4 3 2 1
This is what I did :
program pascal
implicit none
integer i,j,k,p,n
write (*, '("input n: ")', advance="no")
read(*,*) n
do i=0,n-1
p=1
do j=1,n-1-i
write(*,'(3X)', advance="no")
enddo
do k = 0,i
write(*,'(I6)', advance="no") p
p = p*(i-k)/(k+1)
enddo
write(*, '(/)')
end do
endprogram
which the output is pascal triangle. How can I fix it?

Summarize output

I have been stuck for a while on this. I ran a simulation in Fortran90.
program epidemic
implicit none
!!!variable declaration
integer, parameter::n=625
real, dimension(1:n)::x,y
real :: alpha, beta, epsilon, dist, prob, u
integer, dimension(1:n) :: infections
integer:: T, I1, I2, I3, i, j, K2, infperiod, k, tmax
!!!!!!!!!! paramater value
tmax=11
alpha=0.4
gamma=9
!!Generate population!!
I3=1
Do I1=1, 25, 1
Do I2=1,25,1
x(I3)=REAL(I1)
y(I3)=REAL(I2)
Infections(I3)=0
I3=I3+1
ENDDO
ENDDO
!!!INITIAL INFECTION!!!
call random_number(u)
k2=1+aint(u)*n
infections(k2)=1
!!!! initial infection !!!!!!
call random_number(u)
IF (prob >= u) THEN
END IF
END IF
ENDDO
enddo
!!! output data
!!! writing and saving
Do i= 1, n
write(*,*) i, x(i), y(i)
ENDDO
end program epidemic
The result of my simulation is a data frame that looks like this
1 1.00000000 1.00000000 1
2 1.00000000 2.00000000 4
3 1.00000000 3.00000000 3
4 1.00000000 4.00000000 4
5 1.00000000 5.00000000 4
6 1.00000000 6.00000000 4
7 1.00000000 7.00000000 4
8 1.00000000 8.00000000 2
9 1.00000000 9.00000000 4
10 1.00000000 10.0000000 4
11 1.00000000 11.0000000 5
12 1.00000000 12.0000000 5
13 1.00000000 13.0000000 4
14 1.00000000 14.0000000 5
15 1.00000000 15.0000000 6
The first column represents the individuals such that i=1, 625, The second and third column represents the matrix indices [i,j]. The forth column represents the (time) (1:15 days) the person get the infections. I would like to be able to table the output into just two columns.
Just to illustrate, I would like to create a new variable that show the many people got infected in this day.
So, the output of the 625 rows becomes something like this
AT Day=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Total of infected individual =3 5 6 7 11 8 0 1 ...........
Thank you very very much
Now that it's clear what you have, try this:
Add a new declaration
integer, dimension(15) :: infection_day
and, after your existing loop do T ..., insert something like
do i = 1, 15
infection_day(i) = count(infections==i)
end do
to summarise your data.
I don't have Fortran on this machine so haven't tested this code fragment, but it should put you on the right track.
This should get you started...
...
INTEGER, DIMENSION(31) :: Sums
!day is the 4th column from 1:625...
...
Sums(:) = 0
...
DO Entry = 1, 625
Sums(Thedayindex) = Sums(Thedayindex) + Day(Entry)
ENDDO
...

-fortran : reading numbers from a text file

I have a text file of numbers containing several columns and several lines. I have tried several ways including arrays but in the best result I could get only 3 columns of the whole. Any ideas how I can read all the data in Fortran 77?
open(unit=1, file='f', status='old')
do i = 1, 100
read(1, *) x(i), y(i), z(i)
write(6, * ) x(i), y(i), z(i)
enddo
or even 2 dimensional arrays:
do i = 1, 100
do j = 1, 50
read(1, *) x(i, j)
write(6, *) x(i, j)
enddo
enddo
or changing the open(..., access='direct')
none of them worked out since i have a file like this:
1 2 4.5 77 89 4 3 2...
2 4 4 5 6 73 5 3.4 ...
1 2 4 5 67 8 99...
...
The data does not seem to have any particular structure.
You can use list-directed input for this:
program main
real a(100)
read (*,*) a
print *,a
end
I would advise you against using any unit number smaller than 10 in your code for your own purposes.

Write Newton binomial in Fortran90

I have to write an script in Fortran that returns the results of the Newton binomial:
for a, b and n given.
The problem is that I cant use functions or subroutines.
Until now I have written the code for the combinations:
if (n==0) then
print*, "Cnk=",Cnk
else if ((n>=0).and.(k==0)) then
print*, "Cnk=",Cnk
else
do i=1,n,1
aux=aux*i
if (k==i) then
factK=aux
end if
if ((n-k)==i) then
factnk=aux
end if
factn=aux
end do
Cnk=factn/(factk*factnk)
print*, "Cnk=",Cnk
end if
In the case of the binomial k is variable from 0 to n.
Probably not the fastest solution, but quite short:
program binom
implicit none
integer,parameter :: N=5
integer,parameter :: a=3
integer,parameter :: b=5
integer :: k, i
integer :: coeff, eval, total
total = 0
do i=0,N
coeff = product((/ (k,k=1,n) /)) / product((/ (k,k=1,i),(k,k=1,n-i) /))
eval = coeff * a**(n-i) * b**i
total = total + eval
write(*,*) 'i=',i,'coeff=',coeff, 'eval=',eval
enddo !i
write(*,*) '(a+b)**n=',(a+b)**N,'Total=',total
end program binom
Output:
i= 0 coeff= 1 eval= 243
i= 1 coeff= 5 eval= 2025
i= 2 coeff= 10 eval= 6750
i= 3 coeff= 10 eval= 11250
i= 4 coeff= 5 eval= 9375
i= 5 coeff= 1 eval= 3125
(a+b)**n= 32768 Total= 32768

Random sampling in fortran

I have the following data
X Y INFTIME
1 1 0
1 2 4
1 3 4
1 4 3
2 1 3
2 2 1
2 3 3
2 4 4
3 1 2
3 2 2
3 3 0
3 4 2
4 1 4
4 2 3
4 3 3
4 4 0
X and Y represent he X and Y components in the square grid of 4 by 4.
Here I want to sample randomly 10% from the population which are infected i.e, whose INFTIME is non zero. I did not get any idea of coding so could not start it.
Any suggestions and idea will be great for me.
Thanks
EDIT:
DO T = 1,10
DO i = 1, 625
IF(INFTIME(i)/=0 .AND. INFTIME(i) .LE. T)THEN
CALL RANDOM_NUMBER(u(i))
u(i) = 1+aint(u(i)*25)
CALL RANDOM_NUMBER(v(i))
v(i) = 1+aint(v(i)*25)
CALL RANDOM_NUMBER(w(i))
w(i) = 1+aint(w(i)*10)
ENDIF
ENDDO
ENDDO
do p = 1,625
WRITE(*,*) u(p),v(p),w(p)
enddo
This is my code what I tried but it only gives the random numbers, not the connection to the data. I used the data of 25 by 25 grids i.e, 625 individuals and time of infection 1 to 10
Follow what ja72 said. You have three 1D arrays of the same size (16). All you need to do is pick a number between 1 and 16, check to see if INFTIME is zero and accept the value as needed, then repeat until you've taken 10% of the samples (which would be 1.6 values, so I presume you'd just take 2? Or do you have more data than this 4x4 you presented?)
Edit You need to call the random number generator before the if statement:
do t=1,10
do i=1,625
ind = 1+int(624*rand(seed))
if(inftime(ind).neq.0 .and. inftime(ind).le.t) then
stuff
endif
enddo
enddo
The call ind=1+int(625*rand(seed)) will pick a random integer between 1 (when rand(seed)=0) and 625 (when rand(seed)=1). Then you can do what you need if the if statement is satisfied.
EDIT: program epimatrix
IMPLICIT NONE
INTEGER ::l, i,T,K
REAL, DIMENSION(1:625):: X,y,inftime
INTEGER::seed,my_cnt
INTEGER,DIMENSION(8) :: time1
CALL DATE_AND_TIME(values=time1)
seed = 1000*time1(7)+time1(8)
call srand(seed)
OPEN(10, FILE = 'epidemicSIR.txt', FORM = 'FORMATTED')
DO l = 1,625
READ(10,*,END = 200) X(l), Y(l), INFTIME(l)
! WRITE(*,*) X(l),Y(l), INFTIME(l)
! if you know how it was formatted, you should use
! read(10,20) X(l), Y(l), INFTIME(l)
! where 20 is the format
ENDDO
200 CONTINUE
CLOSE(10)
DO T = 1,10
my_cnt=0
write(*,*) "T=",T
DO while (my_cnt.le.63)
K = 1+int(624*rand())
IF(INFTIME(K)/=0 .AND. INFTIME(K) .LE. T)THEN
write(*,*) X(k),Y(k),INFTIME(k)
my_cnt=my_cnt+1
ENDIF
enddo
write(*,*) " "
ENDDO
end program
EDIT 2
I've adjusted the program to fix some of the issues. I've tried keeping my edits in lowercase so that you can see the difference. The do-while loop allows the code to continue running until the condition my_cnt.le.63 has been met (which means you have 63 lines of X, Y, inftime per T). I've added a line to output T and another line to add a space so that the data might be more clear when looking at the output.
This should take care of all the issues you've been running into. If not, I'll keep checking this page.