The MPI_IO write_all subarray and the component number - multiprocessing

I am tring to write a 4 * 4 array using MPI_SET_VIEW and MPI_WRITE_ALL. The xx is a 4 * 4 array and I expect xx = (0,1,2,3; 0,1,2,3; 0,1,2,3; 0,1,2,3) for this code. The globle_size and the local_size equal to 4 and 2. I first create a subarray 2 * 2 file type, so that I divide this 4 * 4 array into 4 parts which is 2 * 2. Then I set view of this file type, and write the xx. The result shold equal to (0,1,2,3; 0,1,2,3; 0,1,2,3; 0,1,2,3), however, it is not. Some of the results are right, and some are wrong.
1 When I do j=ls2,le2, i = ls1,le1, xx(i,j)=i, is array xx() a 4*4 array or 2 * 2 array? ls1=ls2=0,le1=le2=1.
2 For MPI_WRITE_ALL, Should I use 4 * 4 array or 2 * 2 array? and what should I put for the count?1 or 4?
3 For MPI_WRITE_ALL, Should I use filetype as typestyle?
integer::filesize,buffsize,i,Status(MPI_STATUS_SIZE),charsize,disp,filetype,j,count
integer::nproc,cart_comm,ierr,fh,datatype
INTEGER(KIND=MPI_OFFSET_KIND) offset
integer,dimension(dim):: sizes,inersizes,start,sb,ss
character:: name*50,para*100,zone*100
do j=local_start(2),local_end(2)
do i=local_start(1),local_end(1)
xx(i,j)=i
enddo
enddo
count=1
offset=0
start=cart_coords*local_length
call MPI_TYPE_CREATE_SUBARRAY(2,global_length,local_length,start,MPI_ORDER_FORTRAN,&
MPI_integer,filetype,ierr)
call MPI_TYPE_COMMIT(filetype,ierr)
call MPI_File_open(MPI_COMM_WORLD,'out.dat', &
MPI_MODE_WRONLY + MPI_MODE_CREATE,MPI_INFO_NULL,fh,ierr)
call MPI_File_set_view(fh,offset,MPI_integer,filetype,&
"native",MPI_INFO_NULL,ierr)
CALL MPI_FILE_WRITE(fh, xx,1, filetype, MPI_STATUS_ignore, ierr)

Below is a code which I think does what you want. It is based upon what you posted yesterday and then deleted - please don't do this, rather edit the question to improve it. I have also changed to using a 6x4 global size and a 3x2 process grid as rectangular grids are more likely to catch bugs.
Anyway to answer your questions
1 - You only store a part of the array locally, so the array needs to be declared as only (1:2,1:2) - this is almost the whole point of distributed memory programming, each process only holds a part of the whole data structure
2 - You only have a 2x2 array locally, so it should be a 2x2 array holding whatever data is to be stored locally. You are writing an array of integers, so I think it is simplest to say you are writing 4 integers
3 - See above - You are writing an array of integers, so I think it is simplest to say you are writing 4 integers. The filetype is (in my experience) only used in the call to MPI_File_set_view to describe the layout of the data in the file via the filetype argument. When you actually write data just tell mpi_file_write and friends what you are writing
ijb#ijb-Latitude-5410:~/work/stack$ mpif90 --version
GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ijb#ijb-Latitude-5410:~/work/stack$ mpif90 --showme:version
mpif90: Open MPI 4.0.3 (Language: Fortran)
ijb#ijb-Latitude-5410:~/work/stack$ cat mpiio.f90
Program test
Use mpi
Implicit None
Integer::rank,nproc,ierr,filetype,cart_comm
Integer::fh
Integer(kind=mpi_offset_kind):: offset=0
Integer,Dimension(2,2)::buff
Integer::gsize(2)
Integer::start(2)
Integer::subsize(2)
Integer::coords(2)
Integer:: nprocs_cart(2)=(/3,2/)
Integer :: i, j
Logical::periods(2)
Character( Len = * ), Parameter :: filename = 'out.dat'
gsize= [ 6,4 ]
subsize= [ 2,2 ]
periods = [ .False., .False. ]
offset=0
Call MPI_init(ierr)
Call MPI_COMM_SIZE(MPI_COMM_WORLD, nproc, ierr)
Call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
Call MPI_Dims_create(nproc, 2, nprocs_cart, ierr)
Call MPI_Cart_create(MPI_COMM_WORLD, 2, nprocs_cart, periods, .True., &
cart_comm, ierr)
Call MPI_Comm_rank(cart_comm, rank, ierr)
Call MPI_Cart_coords(cart_comm, rank, 2, coords, ierr)
start=coords * subsize
Do j = 1, 2
Do i = 1, 2
buff( i, j ) = ( start( 1 ) + ( i - 1 ) ) + &
( start( 2 ) + ( j - 1 ) ) * gsize( 1 )
End Do
End Do
Call MPI_TYPE_CREATE_SUBARRAY(2,gsize,subsize,start,MPI_ORDER_FORTRAN,&
MPI_integer,filetype,ierr)
Call MPI_TYPE_COMMIT(filetype,ierr)
! For testing make sure we have a fresh file every time
! so don't get confused by looking at the old version
If( rank == 0 ) Then
Call mpi_file_delete( filename, MPI_INFO_NULL, ierr )
End If
Call mpi_barrier( mpi_comm_world, ierr )
! Open in exclusive mode making sure the delete has occurred
Call MPI_File_open(MPI_COMM_WORLD,filename,&
MPI_MODE_WRONLY + MPI_MODE_CREATE + MPI_MODE_EXCL, MPI_INFO_NULL, fh,ierr)
Call MPI_File_set_view(fh,offset,MPI_integer,filetype,&
"native",MPI_INFO_NULL,ierr)
Call MPI_FILE_WRITE_all(fh, buff, 4, mpi_integer, MPI_STATUS_ignore, ierr)
Call MPI_File_close(fh,ierr)
Call MPI_FINALIZE(ierr)
End Program test
ijb#ijb-Latitude-5410:~/work/stack$ mpif90 -Wall -Wextra -fcheck=all -O -g -std=f2008 -fcheck=all mpiio.f90
ijb#ijb-Latitude-5410:~/work/stack$ mpirun --oversubscribe -np 6 ./a.out
ijb#ijb-Latitude-5410:~/work/stack$ od -v -Ad -t d4 out.dat
0000000 0 1 2 3
0000016 4 5 6 7
0000032 8 9 10 11
0000048 12 13 14 15
0000064 16 17 18 19
0000080 20 21 22 23
0000096

Related

Algorithm for progressive matrix

I want to construct a matrix like so:
[ 0 1 2 3 4 5 ....
1 2 3 4 5 6 ....
2 3 4 5 6 7 ....
3 4 5 6 7 8 ....
4 5 6 7 8 9 ....
5 6 7 8 9 10 ... ] etc
The main goal is to use the algorithm to put to the power the elements of an already existing matrix.
I am programming in Fortran, and I used the following code but it's not working:
do i = 1, m+1
do j = 1, m+1
do while ( w < 2*m )
if ( i > j ) then
ma(i,j) = 0
else
w = i-1
ma(i, j) = w
w = w +1
end if
end do
end do
end do
I suggest you to use an implied-do in the array constructor syntax, possibly initialized in the same declaration:
integer, parameter :: n = 10, m = 5
integer :: i, j
integer :: ma(m,n) = reshape([((i+j, j=0, m-1), i=0, n-1)], [m,n])
The [...] syntax is posible in Fortran 2003 or higher. (/.../) should be used otherwise. My result with gfortran v7.1.1 is:
do i = 1, m
print *, ma(i, :)
end do
$gfortran test.f90 -o main
$main
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
2 3 4 5 6 7 8 9 10 11
3 4 5 6 7 8 9 10 11 12
4 5 6 7 8 9 10 11 12 13
Note: The initialization in the declaration would only be possible if n and m are constants (parameter). You could initialize it normally in the program body, otherwise, with the same implied-do syntax.
If you plan to read the values of m and n at runtime, you should make ma an allocatable array.
While there is nothing wrong with Rodrigo's answer personally I think it much clearer to just use two loops
ian#eris:~/work/stackoverflow$ cat floyd.f90
Program yes
Implicit None
Integer, Parameter :: n = 5
Integer, Dimension( 1:n, 1:n ) :: elp
Integer :: base, offset
Integer :: i, j
Do i = 1, n
base = i - 1
Do j = 1, n
offset = j - 1
elp( j, i ) = base + offset
End Do
End Do
Do j = 1, n
Write( *, '( 1000( i3, 1x ) )' ) elp( j, : )
End Do
End Program yes
ian#eris:~/work/stackoverflow$ gfortran -Wall -Wextra -std=f2003 -fcheck=all -O floyd.f90 -o genesis
ian#eris:~/work/stackoverflow$ ./genesis
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
I've seen that others already made an algorithm that solves your problem. But i also bring another algorithm that works for a non-square matrix. NI is the number of columns of the matrix, and NJ is the number of lines. MAT is the matrix you want.
PROGRAM MATRIX
IMPLICIT NONE
INTEGER :: I, J, NI, NJ
INTEGER, ALLOCATABLE :: MAT(:,:)
NI = 8
NJ = 5
ALLOCATE(MAT(NI,NJ))
DO I = 1, NI
MAT(I,1) = I-1
ENDDO
DO J = 2,NJ
MAT(:,J) = MAT(:,J-1) + 1
ENDDO
DO J = 1, NJ
WRITE(*,'(8I3)') MAT(:,J)
ENDDO
END PROGRAM
Thanks for the feedback, I managed to do it using the following code:
do i = 1, m+1
w = i-1
do j = 1, m+1
ma(i, j) = u**w
w = w+1
end do
end do
I would like to state that i'm using Fortran 90 and only 90 because of my circumstances, otherwise I would've went with c++, (university life !!).
Please note that I used the desired series to put to the power the elements of the matrix.
Finally, I noticed some "complex" answers maybe, or maybe I'm just a beginner, but i would really love to learn if there are some rules and or dos and don'ts and or advice to get better at coding ( scientific code, not development code).
Thank you very much for the feed back, and waiting for any responses.

Mathematical operation to reflect loop iterator about midpoint of number of iterations

Imagine we have a loop with index variable n counting from 1 to 6. As I got through this loop I want to print the values
1
2
3
3
2
1
Is there a elegant mathematical operation (i.e. avoiding if statements) which can implement this? I know for example if I print
1 + modulo(n-1,3)
it would print
1
2
3
1
2
3
but I want that second half reversed. The loop will always have an even number of iterations if that helps. I am writing in Fortran 90.
How about the following:
do i=1,n
print *, int(abs(i-n/2.0-0.5)+0.5)
end do
This will print the expected result for even n and introduces a ZERO for odd n.
Is the following elegant enough? I think this is much clearer than obfuscated maths
ian-admin#agon ~/work/stack $ cat merge.f90
Program test
Implicit None
Integer :: n
Integer :: i
Write( *, * ) 'n?'
Read ( *, * ) n
Do i = 1, n
Write( *, * ) Merge( i, n - ( i - 1 ), i <= n / 2 )
End Do
End Program test
ian-admin#agon ~/work/stack $ gfortran -std=f2003 -Wall -Wextra merge.f90
ian-admin#agon ~/work/stack $ ./a.out
n?
6
1
2
3
3
2
1
ian-admin#agon ~/work/stack $ ./a.out
n?
7
1
2
3
4
3
2
1
ian-admin#agon ~/work/stack $
Consider
min(n, 7-n)
This expression produces 1, 2, 3, 3, 2, 1 as n goes from 1 to 6. More generally, if N is the (even) upper bound for the variable n, the formula becomes:
min(n, N+1-n)
which produces
1, 2, ..., N/2, N/2, N/2 - 1, ..., 2, 1
as n runs between 1 and N.
In the case where N is odd, the same formula generates the sequence
1, 2, ..., (N+1)/2, (N-1)/2, ..., 2, 1.
For example:
1, 2, 3, 4, 3, 2, 1
for N=7.
n = 6
for i in range(1,n+1):
print(min(i, n + 1 - i))
or (// is integer division equivalent to bitshift right)
print(n//2 - abs(n + 1 - 2 * i)//2)
>> 1 2 3 3 2 1
For odd length - the first approach works as is, the second way requires changing to (n+1)//2 (it does not break work for even length)
Bit trick to find min of two 32-bit integers:
min = b+((a-b)&((a-b)>>31))

Understanding this discrete distribution issue.

Hello I am reading the book about programming in java and I found one issue which I cannot understand. The question is like this:
Write a program DiscreteDistribution.java that takes a variable number of integer command-line arguments and prints the integer i with probability proportional to the ith command-line argument.
I have no clue what this i with probability proportinoal to the ith command-line argument. Can someone help me understand it? Thanks so much.
Your program should accept a list of integers as input parameter. E.g.
<program> 1 4 5 3 7
<program> 5 4 2 8 9 0 1
are all valid inputs. Let's call the parameters A. A[x] is the x-th parameter.
Then you should print one single number i with the following probability.
P(i) = A[i] / sum(A[x])
Take the first input as example.
P(0) = 1 / 20
P(1) = 4 / 20
P(2) = 5 / 20
P(3) = 3 / 20
P(4) = 7 / 20

Fortran passing parameters with brackets prevents changes

In this question I asked about a method to explicitly prevent passed arguments to change. An obvious solutions is defining copies of the arguments and operate the algorithm on those copies. However in the comment I was pointed to the fact, that I could call the function and wrap the argument I didn't want to change in brackets. This would have the same effect as creating a copy of that passed variables so that it would not change. But I don't understand how it works and what the brackets are actually doing. So could someone explain it to me?
Here is a simple example where the behaviour occurs as I described.
1 program argTest
2 implicit none
3 real :: a, b, c
4
5 interface !optional interface
6 subroutine change(a,b,c)
7 real :: a, b, c
8 end subroutine change
9 end interface
10
11 write(*,*) 'Input a,b,c: '
12 read(*,*) a, b, c
13
14 write(*,*) 'Values at start:'
15 write(*,*)'a:', a
16 write(*,*)'b:', b
17 write(*,*)'c:', c
18
19
20 call change((a),b,c)
21 write(*,*)'Values after calling change with brackets around a:'
22 write(*,*)'a:', a
23 write(*,*)'b:', b
24 write(*,*)'c:', c
25
26
27 call change(a,b,c)
28 write(*,*)'Values after calling change without brackets:'
29 write(*,*)'a:', a
30 write(*,*)'b:', b
31 write(*,*)'c:', c
32
33 end program argTest
34
35
36 subroutine change(a,b,c)
37 real :: a, b, c
38
39 a = a*2
40 b = b*3
41 c = c*4
42
43 end subroutine change
44
45
46
The syntax (a), in the context of the code in the question, is an expression. In the absence of pointer results, an expression is evaluated to yield a value. In this case the value of the expression is the same as the value of the variable a.
While the result of evaluating the expression (a), and the variable a, have the same value, they are not the same thing - the value of a variable is not the same concept as the variable itself. This is used in some situations where the same variable needs to be supplied as both an input argument and as a separate output argument, that would otherwise run afoul of Fortran's restrictions on aliasing of arguments.
HOWEVER - as stated above - in the absence of a pointer result, the result of evaluating an expression is a value, not a variable. You are not permitted to redefine a value. Conceptually, it makes it no sense to say "I am going to change the meaning of the value 2", or "I am going to change the meaning of the result of evaluating 1 + 1".
When you use such an expression as an actual argument, it must not be associated with a dummy argument that is redefined inside the procedure.
Inside the subroutine change, the dummy argument that is associated with the value of the expression (a) is redefined. This is non-conforming.
Whether a copy is made or not is an implementation detail that you cannot (and must not) count on - the comment in the linked question is inaccurate. For example, a compiler that is aware of this restriction discussed above knows the subroutine change cannot actually change the first argument in a conforming way, may know that a is not otherwise visible to change, and therefore decide that it doesn't need to make a temporary copy of a for the expression result.
If you need to make a temporary copy of something, then write the statements that make a copy.
real :: tmp_a
...
tmp_a = a
call change(tmp_a, b, c)
I think the explanation is this, though I can't point to a part of the standard that makes it explicit, ...
(a) is an expression whose result is the same as a. What gets passed to the subroutine is the result of evaluating that expression. Fortran is disallowing an assignment to that result, just as it would if you passed cos(a) to the subroutine. I guess that the result of (a) is almost exactly the same as a copy of a, which might explain the behaviour that is puzzling OP.
I don't have Fortran on this computer, but if I did I'd try a few more cases where the difference between a and (a) might be important, such as
(a) = some_value
to see what the compiler makes of them.
#IanH's comment, below, points out the relevant part of the language standard.
It may be interesting to actually print the address of the actual and dummy arguments using (non-standard) loc() function and compare them, for example:
program main
implicit none
integer :: a
a = 5
print *, "address(a) = ", loc( a )
call sub( 100 * a )
call sub( 1 * a )
call sub( 1 * (a) )
call sub( (a) )
call sub( a )
contains
subroutine sub( n )
integer :: n
n = n + 1
print "(2(a,i4,3x),a,i18)", "a=", a, " n=", n, "address(n) =", loc( n )
end subroutine
end program
The output become like this, which shows that a temporary variable containing the result of an expression is actually passed to sub() (except for the last case).
# gfortran-6
address(a) = 140734780422480
a= 5 n= 501 address(n) = 140734780422468
a= 5 n= 6 address(n) = 140734780422464
a= 5 n= 6 address(n) = 140734780422460
a= 5 n= 6 address(n) = 140734780422456
a= 6 n= 6 address(n) = 140734780422480
# ifort-16
address(a) = 140734590990224
a= 5 n= 501 address(n) = 140734590990208
a= 5 n= 6 address(n) = 140734590990212
a= 5 n= 6 address(n) = 140734590990216
a= 5 n= 6 address(n) = 140734590990220
a= 6 n= 6 address(n) = 140734590990224
# Oracle fortran 12.5
address(a) = 6296328
a= 5 n= 501 address(n) = 140737477281416
a= 5 n= 6 address(n) = 140737477281420
a= 5 n= 6 address(n) = 140737477281424
a= 5 n= 6 address(n) = 140737477281428
a= 6 n= 6 address(n) = 6296328
(It is interesting that Oracle uses a very small address for a for some reason... though other compilers use very similar addresses.)
[ Edit ] Acoording to the above answer by Ian, it is illegal to assign a value to the memory resulting from an expression (which is a value = constant, not a variable). So please take the above code just as an attempt to confirm that what is passed with (...) is different from the original a.

READ statement doesn't read last number from file

Suppose you have this program
Subroutine readDIM which reads the dimensions (rows, columns) of a matrix from a txt file. (In order to simplify, let it be an INTEGER). ReadDIM works using tokens and it works fine by assumption.
A text file containing for example:
1 2 3 4
1 2 20 5
3 0 333 3
Returns nrow = 3, ncol = 4
Since readDIM has given the true dimensions of the matrix, I want to allocate space to:
REAL, DIMENSION (:,:), ALLOCATABLE :: vMatrix
To read the matrix from a txt file and to store it into the 2d-array. So I've written the following
SUBROUTINE buildVMatrix
OPEN(UNIT=1, FILE = filename, STATUS ='OLD',IOSTAT=ios);
ALLOCATE(vMatrix(nrow,ncol));
WRITE(*,*) "Register matrix from file:", filename;
WRITE(*,*) "-------------------------------------------------------";
DO i = 1, UBOUND(vMatrix,1)
READ(1,*, IOSTAT = ios) (vMatrix(i,j),j=1,UBOUND(vMatrix,2));
!IF(ios /= 0 ) EXIT
END DO
CLOSE(1)
END SUBROUTINE
When I print vMatrix the output is:
matrix.txt : 1 2 3 4 buildVMatrix output (once printed) 1 2 3 4
1 2 20 5 1 2 20 5
3 0 333 3 3 0 333 0
It doesn't read the last number. I know it's caused by the DO loop inside buildVMatrix, but can't explain myself this and have no idea how to fix it writing a different code.
It's because there's no line ending at the last line in your txt file, try to type a return after the last number.

Resources