I have that each processor has its own unique matrix, A, of size Nx2 where N varies with processor. I want to collect all these matrices into one single buff (NxP)x2 matrix, where P is the number of processors.
Size wise in Fortran they are allocated like,
A(N,2)
buff(N*P,2)
As an example, let P = 2 and the A matrices for each processor be,
for Proc-1
10 11
10 11
for Proc-2
20 21
20 21
To this end I use MPI_GATHERV and save the individual matrices in the buff matrix. If I do this then buff will look like this,
10 20
10 20
11 21
11 21
But what I want is the matrix to look like this,
10 11
10 11
20 21
20 21
In memory (I think) Buff : |10 , 10 , 20, 20 , 11 , 11 , 21 , 21|
Sample code is below,
...
! size = 2
root = 0
ALLOCATE ( count(size), num(size) )
! -----------------------------------------------------------
! Mock data
! -----------------------------------------------------------
IF(rank.eq.0) THEN
m = 2
mm = m*2
allocate(A(m,2))
A(1,1) = 10
A(1,2) = 11
A(2,1) = 10
A(2,2) = 11
ELSE
m = 2
mm = m*2
allocate(A(m,2))
A(1,1) = 20
A(1,2) = 21
A(2,1) = 20
A(2,2) = 21
END IF
! -----------------------------------------------------------
! send number of elements
! -----------------------------------------------------------
CALL MPI_GATHER(mm,1,MPI_INTEGER,count,1,MPI_INTEGER,root,cworld,ierr)
! -----------------------------------------------------------
! Figure out displacement vector needed for gatherv
! -----------------------------------------------------------
if(rank.eq.0) THEN
ALLOCATE (buff(SUM(count)/2,2), disp(size), rdisp(size))
rdisp = count
disp(1) = 0
DO i = 2,size
disp(i) = disp(i-1) + count(i-1)
END DO
END IF
! -----------------------------------------------------------
! Rank-0 gathers msg
! -----------------------------------------------------------
CALL MPI_GATHERV(A,mm,MPI_INTEGER,buff,rdisp,disp,MPI_INTEGER,root,cworld,ierr)
! -----------------------------------------------------------
! Print buff
! -----------------------------------------------------------
if(rank.eq.0) THEN
DO i = 1,sum(count)/2
print*, buff(i,:)
end do
END IF
I have looked at Using Gatherv for 2d Arrays in Fortran but am a little confused with the explanation.
I’m not very familiar with the MPI details, but is there a "simple" way to gather all the matrices and place them in the correct memory position in buff?
**** Edit ****
Fallowing what Gilles Gouaillardet suggested. I'm trying to figure how to do that,
The derived type for sending the rows should look something like this (I think),
CALL MPI_TYPE_vector(2,1,2,MPI_INTEGER,MPI_ROWS,ierr)
CALL MPI_TYPE_COMMIT(MPI_ROWS,ierr)
Then I extend,
call MPI_Type_size(MPI_INTEGER, msg_size, ierr)
lb = 0
extent = 2*msg_size
call MPI_Type_create_resized(MPI_ROWS, lb, extent , MPI_ROWS_extend, ierr)
CALL MPI_TYPE_COMMIT(, MPI_ROWS_extend,ierr)
I’m trying to understand why I need the second derived type for receiving. I’m not sure how that one should look like.
Related
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
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
I need take te values of NPNOD, NELEM, and the others. and take the values of the next matrix
$DIMENSIONES DEL PROBLEMA
DIMENSIONES : NPNOD= 27 , NELEM= 8 , NMATS= 1 , \
NNODE= 8 , NDIME= 3 , \
NCARG= 1 , NGDLN= 3, NPROP= 5, \
NGAUS= 1 , NTIPO= 1 , IWRIT= 1 ,\
INDSO= 10 , NPRES= 9
$---------------------------------------------------------
GEOMETRIA
$ CONECTIVIDADES ELEMENTALES
$ ELEM. MATER. SECUENCIA DE CONECTIVIDADES
1 1 8 6 12 20 18 15 23 25
2 1 19 8 20 24 26 18 25 27
3 1 5 2 6 8 14 11 15 18
4 1 17 5 8 19 21 14 18 26
5 1 7 4 9 13 8 6 12 20
6 1 16 7 13 22 19 8 20 24
7 1 3 1 4 7 5 2 6 8
8 1 10 3 7 16 17 5 8 19
To read a mixture of Characters and numbers in fortran is done best by first reading the whole line into a character string and then to read the respective numerical values from this string. The details will depend a lot on the flexibility you need to have to deal with changing input formats. The more you can rely on the assumption that an input file will always be of identical structure the easier things get.
You did not specify in your question the details of the 10 numbers in the rows numbered 1 to 8. Lets assume that the first number is the row of the matrix , the second number the number of the current matrix and the remaining eight numbers are the elements. Lets further assume that the elements in one row of the matrix will always be listed in one single input line.
character(len=5), dimension(10) :: fields
character(len=80) :: string
character(len=1024) :: grand
integer, dimension(10) :: values
fields(1) = 'NPNOD' ! and so on ...
read(unit=ird, '(a)', iostat=ios) string ! read line 'DIMENSIONES...'
read(unit=ird, '(a)', iostat=ios) string ! read dummy string
grand(1:80) = string ! place into grand total
read(unit=ird, '(a)', iostat=ios) string ! read dummy string
grand(81:160) = string ! append to grand total
...! repeat for three more lines
grand(len_trim(grand)+1:len_trim(grand)+1) = ',' ! Append a final comma
do i=1,10 ! Loop over all field names
ilen = len_trim(field(i)) ! store length of field name, may vary?
ipos = index(grand, field(i)) ! Find start of field name
icom = index(grand(ipos+ilen+1:len(grand), ',') ! locate trailing comma
read(grand(ipos+ilen+1:ipos+ilen+icom-1),*) values(i) ! Read numerical value
enddo
read(unit=ird, '(a)', iostat=ios) string ! read dummy string
read(unit=ird, '(a)', iostat=ios) string ! read dummy string
read(unit=ird, '(a)', iostat=ios) string ! read dummy string
do i= 1, values(2) ! if NELEM is in fields(2)
read(ird, *) irow, imat, (array(i,j),j=1, values(2)) ! read leading two no's and elements
enddo
You still have to define the integer variables, ird, ilen, ipos, icom, irow, imat, ios, i, j, the matrix array or the many matrices you need to read.
Upon a read the value of the status variable ios should be inspected...
Essentially I do:
define a character variable field with all the names 'NPNOD' ...
read and concatenate the lines 'dimensiones' until 'INDSO' into the string "grand"
Loop over all field and
detect position of the field name and the position of the trailing comma
read from the grand string the subsection that contains only the numerical value
Loop over the rows with matrix elements to read the two first numbers and the matrix elements.
As I appended a final comma, that is missing in the line 'INDSO...', the loop over the field names does not have to bother with the special case of 'NPRES', which does not have a trailing comma in the original input file.
Your actual code should
check if there are never more than 10 fields
is 80 character the maximum length of any individual input line
will 1024 characters be neough for the concatenated list.
I have an input data file storing two columns (first column contains the names of the variables and the second column contains their values). I am trying to read this input file through my FORTRAN script and to print on the screen the variables I've just created.
Here are the input file, the script, as well as the terminal output displayed on the terminal at the execution:
input file:
a 7 2 4
b 150
vec1 1 2 3
vec2 4 5 6
c 56
script
program main
implicit none
character(16) :: cinput
integer :: a0,a1,a2,b0,c0,i,j
integer,dimension(:,:),allocatable :: gfd
open(9, file='inputdata.dat')
read(9,*) cinput,a0,a1,a2
read(9,*) cinput,b0
allocate(gfd(3,2))
read(9,*) cinput,gfd(:,1)
read(9,*) cinput,gfd(:,2)
read(9,*) cinput,c0
close(9)
write(*,*) 'a0=', a0,'a1=', a1,'a2=', a2,'b0=', b0,'c0=', c0
do j=1,2
do i=1,3
write(*,*) gfd(i,j)
enddo
enddo
end program main
Output on the terminal
a0 = 7, a1 = 2, a2 = 4, b0 = 150, c0 = 56
1
2
3
4
5
6
Now, this is good, but would there be a way to assign the values to the variable "gfd" without having to specify the size of the array in "allocate"? I could then modify the input file with a longer/smaller array, without having to modify the script when I allocate the variable "gfd".
Thank you for your support if you can help me!
ms518
EDIT: thanks for your answer, this procedure is working and it is now possible to work with various array sizes in the input file without having to modify the fortran script. Below are the modifications in inputfile, script and the result obtained.
input file:
size 5 2
a 7 2 4
b 150
vec1 1 2 3 4 5
vec2 6 7 8 9 10
c 56
script
program main
implicit none
character(16) :: cinput
integer :: a0,a1,a2,b0,c0,i,j, rows, cols
integer,dimension(:,:),allocatable :: gfd
open(9, file='inputdata.dat')
read(9,*) cinput,rows,cols
read(9,*) cinput,a0,a1,a2
read(9,*) cinput,b0
allocate(gfd(rows,cols))
read(9,*) cinput,gfd(:,1)
read(9,*) cinput,gfd(:,2)
read(9,*) cinput,c0
close(9)
write(*,*) 'a0=', a0,'a1=', a1,'a2=', a2,'b0=', b0,'c0=', c0
do j=1,cols
do i=1,rows
write(*,*) gfd(i,j)
enddo
enddo
end program main
Output on the terminal
a0 = 7, a1 = 2, a2 = 4, b0 = 150, c0 = 56
1
2
3
4
5
6
7
8
9
10
The best way to specify the size of the array would be to include its dimensions in the input file, read them, allocate the array, then read the array.
If you need assistance programming this, modify your question. You could, if you want, post your revised code to answer your own question.
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.