Random sampling in fortran - 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.

Related

How to increase N from 10 random points and up to 10^8 points in Monte Carlo [duplicate]

I want to double a number till 256, and when the program gets 256 make stop but the program that I created not giving me a double from 1 till 256
`````````````````````````````````````````````````````````````````
Fortran code
program exercise1
implicit none
real, external :: f
real :: h,a,b,prod,integration,summ,p
integer :: i,j,n
print*, 'Welcome, This program using Composite trapezoid method to calculate the integer'
print*, ' -------- '
prod=1
summ=0
print*,'Number of intervals ',' The integer value'
do i=1,258
n=(prod*i*i) ! Getting number of interval till 256
a=-1 ! The Lower limit of the integration
b=1 ! The Upper limit of the integration
h=(b-a)/n ! Calculate the delta X
p=(h/2.)*(f(a)+f(b)) ! Here as we have the whole equation is (h/2)*[f(a)+f(b)+2*sum(Xi) ! So we calculate the first part (h/2)*[f(a)+f(b) and then calculate the anoter part
summ=summ+h*f(a+i*h) !h/2 *2* sum[f(Xi)
integration = p+summ !Here the sum the both parts
if(n == 256) then !put a limit for the number of interval
Stop
end if
print*,n,' -', integration
enddo
end
real function f(x) !the function of the integer
f=sin(x+1)
end`
``````````````````````
the output
``````````````````
1 2.72789216
4 2.46665454
9 2.47777867
16 2.49350500
25 2.50419927
36 2.51126313
49 2.51606560
64 2.51944780
81 2.52190781
100 2.52374840
121 2.52515912
144 2.52626276
169 2.52714205
196 2.52785373
225 2.52843738
I think you want powers of: 2**i not squares: i**2. For example:
do i = 0,8
print*, 2**i
enddo
gives
1
2
4
8
16
32
64
128
256
I was originally voting to close as a typo, but your code maybe indeed does something different.
Your codes makes n to be a sequence if integer squares. 1^2, 2^2, 3^2 ... 16^2=256
But you wanted doubling the number, in that case just multiply n by 2.
n = 1
do i = 1, 10
do what you need
print *, n
n = n * 2
end do

How automatically double the number of intervals

I want to double a number till 256, and when the program gets 256 make stop but the program that I created not giving me a double from 1 till 256
`````````````````````````````````````````````````````````````````
Fortran code
program exercise1
implicit none
real, external :: f
real :: h,a,b,prod,integration,summ,p
integer :: i,j,n
print*, 'Welcome, This program using Composite trapezoid method to calculate the integer'
print*, ' -------- '
prod=1
summ=0
print*,'Number of intervals ',' The integer value'
do i=1,258
n=(prod*i*i) ! Getting number of interval till 256
a=-1 ! The Lower limit of the integration
b=1 ! The Upper limit of the integration
h=(b-a)/n ! Calculate the delta X
p=(h/2.)*(f(a)+f(b)) ! Here as we have the whole equation is (h/2)*[f(a)+f(b)+2*sum(Xi) ! So we calculate the first part (h/2)*[f(a)+f(b) and then calculate the anoter part
summ=summ+h*f(a+i*h) !h/2 *2* sum[f(Xi)
integration = p+summ !Here the sum the both parts
if(n == 256) then !put a limit for the number of interval
Stop
end if
print*,n,' -', integration
enddo
end
real function f(x) !the function of the integer
f=sin(x+1)
end`
``````````````````````
the output
``````````````````
1 2.72789216
4 2.46665454
9 2.47777867
16 2.49350500
25 2.50419927
36 2.51126313
49 2.51606560
64 2.51944780
81 2.52190781
100 2.52374840
121 2.52515912
144 2.52626276
169 2.52714205
196 2.52785373
225 2.52843738
I think you want powers of: 2**i not squares: i**2. For example:
do i = 0,8
print*, 2**i
enddo
gives
1
2
4
8
16
32
64
128
256
I was originally voting to close as a typo, but your code maybe indeed does something different.
Your codes makes n to be a sequence if integer squares. 1^2, 2^2, 3^2 ... 16^2=256
But you wanted doubling the number, in that case just multiply n by 2.
n = 1
do i = 1, 10
do what you need
print *, n
n = n * 2
end do

Inconsistent rows allocation in scalapack

Consider the following simple fortran program
program test_vec_allocation
use mpi
implicit none
integer(kind=8) :: N
! =========================BLACS and MPI=======================
integer :: ierr, size, rank,dims(2)
! -------------------------------------------------------------
integer, parameter :: block_size = 100
integer :: context, nprow, npcol, local_nprow, local_npcol
integer :: numroc, indxl2g, descmat(9),descvec(9)
integer :: mloc_mat ,nloc_mat ,mloc_vec ,nloc_vec
call blacs_pinfo(rank,size)
dims=0
call MPI_Dims_create(size, 2, dims, ierr)
nprow = dims(1);npcol = dims(2)
call blacs_get(0,0,context)
call blacs_gridinit(context, 'R', nprow, npcol)
call blacs_gridinfo(context, nprow, npcol, local_nprow,local_npcol)
N = 700
mloc_vec = numroc(N,block_size,local_nprow,0, nprow)
nloc_vec = numroc(1,block_size,local_npcol,0, npcol)
print *,"Rank", rank, mloc_vec, nloc_vec
call blacs_gridexit(context)
call blacs_exit(0)
end program test_vec_allocation
when I run it with 11 mpi ranks i get
Rank 0 100 1
Rank 4 100 1
Rank 2 100 1
Rank 1 100 1
Rank 3 100 1
Rank 10 0 1
Rank 6 100 1
Rank 5 100 1
Rank 9 0 1
Rank 8 0 1
Rank 7 0 1
which is how i would expect scalapack to divide this array, however, for even number of ranks i get:
Rank 0 200 1
Rank 8 200 0
Rank 9 100 1
Rank 10 100 0
Rank 1 200 0
Rank 6 200 1
Rank 11 100 0
Rank 3 200 1
Rank 4 200 0
Rank 2 200 0
Rank 7 200 0
Rank 5 200 0
which makes no sense, why would rank 0 get 200 elements for block size 100 and ranks * block size > N.
Because of this my program works for mpi ranks 1,2,3,5,7,11, but fails for ranks 4,6,8,9,10,12, etc (I dont why it is failing for rank 9!). Can anyone explain what is wrong in my approach?
GFortran version: 6.1.0
SCALPACK version: 2.1.0
MacOS version: 10.11
There are a number of things wrong with your code
1) Firstly don't use Integer( 8 ). As Vladimir put it, please unlearn this. Not only is it not portable and therefore very bad practice (please see many examples here, e.g. Fortran 90 kind parameter) here it is wrong as numroc expects an integer of default kind as its first argument (see e.g. https://software.intel.com/content/www/us/en/develop/documentation/mkl-developer-reference-fortran/top/scalapack-routines/scalapack-utility-functions-and-routines/numroc.html)
2) You call an MPI routine before you call MPI_Init, with a hand full of exceptions (and this isn't one) this results in undefined behaviour. Note the description at https://www.netlib.org/blacs/BLACS/QRef.html#BLACS_PINFO makes no reference to actually calling MPI_Init. As such I also prefer to call MPI_Finalise
3) You have misunderstood MPI_Dims_create. You seem to assume you will get a 1 dimensional distribution, but you actually ask it for a two dimensional one. Quoting from the standard at https://www.mpi-forum.org/docs/mpi-3.1/mpi31-report.pdf
The entries in the array dims are set to describe a Cartesian grid
with ndims dimensions and a total of nnodes nodes. The dimensions are
set to be as close to each other as possible,using an appropriate
divisibility algorithm. The caller may further constrain the
operation of this routine by specifying elements of array dims. If
dims[i] is set to a positive number,the routine will not modify the
number of nodes in dimension i; only those entries where dims[i] = 0
are modified by the call.
You set dims equal to zero, so the routine is free to set both dimensions. Thus for 11 processes you will get a 1x11 or 11x1 grid, which is what you seem to expect. However for 12 processes, as The dimensions are set to be as close to each other as possible you will get either a 3x4 or 4x3 grid, NOT 12x1. If it is 3x4 along each row you expect numroc to return 3 processes with 200 elements ( 2 blocks ), and 1 with 100. As there are 3 rows you therefore expect 3x3=9 processes returning 200 and 3x1=3 returning 100. This is what you see. Also try 15 procs - you will see an odd number of processes that according to you "does not work", this is because (advanced maths alert) 15=3x5. Incidentally on my machine 9 processes does NOT return 3x3 - this looks like a bug in openmpi to me.

Do loop is stuck at the first subarray in MPI SCATTER and GATHER

I have two arrays, array global has 8 values and it will be scatter among array local with 2 values. What I was trying to do is, take the big array, split into small arrays, do some work, then put it back together.
Problem:
Even though I successfully scattered the data, the do loop as written is only working for the first sub array local. What I want is all of the integers in the scattered local array should be multiplied by 2, then gathered into the global array.
Code for the do loop (some work has been done here):
do j = 1,2
local(j) = j*2
print *, j
end do
Here's the full code. If you go down below you'll notice the part which I need your help.
MODULE MPI
IMPLICIT NONE
INCLUDE 'mpif.h'
INTEGER :: MYID,TOTPS, IERR, MPISTTS
CONTAINS
SUBROUTINE MPIINIT
IMPLICIT NONE
CALL MPI_INIT( IERR )
CALL MPI_COMM_RANK(MPI_COMM_WORLD,MYID,IERR)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD,TOTPS,IERR)
RETURN
END SUBROUTINE MPIINIT
END MODULE MPI
PROGRAM SCATTER
USE MPI
IMPLICIT NONE
CALL MPIINIT
CALL TEST
CALL MPI_FINALIZE(IERR)
CONTAINS
SUBROUTINE TEST
USE MPI
IMPLICIT NONE
INTEGER :: I,J
INTEGER,DIMENSION(8) :: GLOBAL
INTEGER,DIMENSION(2) :: LOCAL
if (myid .eq. 0) then
do i = 1,8
global(i) = i
end do
end if
call mpi_scatter(global,2,mpi_integer,local,2,mpi_integer,0, &
mpi_comm_world,ierr)
print*,"task",myid,":",local
call mpi_barrier(mpi_comm_world,ierr)
!!!!!!! do some work here
do j = 1,2
local(j) = j*2
print*,j
end do
!!!!!! end work
call mpi_gather(local,2,mpi_integer,global,2,mpi_integer,0, &
mpi_comm_world,ierr)
if(myid .eq. 0) then
print*,"task",myid,":",global
end if
END SUBROUTINE TEST
END PROGRAM SCATTER
Notes:
(1) I've been reading & learning from this thread but it looks challenging for now.
(2) Run code mpif90 SCATTER.f90 .. mpirun -np 4 ./a.out
Output:
task 0 : 1 2
task 1 : 3 4
task 2 : 5 6
task 3 : 7 8
1
2
1
2
1
2
1
2
task 0 : 2 4 2 4 2 4 2 4
What I want to get is: task 0 : 2 4 6 8 10 12 14 16
You wrote
local(j) = j * 2
print*, j
I don't think that does what you think it does.
You probably meant to write
local(j) = local(j) * 2
print*, local(j)

-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.