coarray fortran array doesn't get updated - fortran

I'm just learning to use coarry with Fortran. I have a very simple program. I have an array of length 9 that I want to distribute over 3 processes, do some calculations, and merge them back to a single array (basic MPI_scatter/MPI_gather like problem).
program name
implicit none
integer:: arr(9), local(3)[*]
integer:: i, j, k, iz
arr = [(i, i = 1, 9)]
local(:)[1] = arr(1:3)
local(:)[2] = arr(4:6)
local(:)[3] = arr(7:9)
iz = this_image()
local = local*iz
sync all
if(iz == 1) then
arr(1:3) = local(:)[1]
arr(4:6) = local(:)[2]
arr(7:9) = local(:)[3]
write(*,'(*(i3))')arr
endif
end program name
I'm compiling this with
gfortran -fcorray=lib -lcaf_mpi
and executing with this
mpirun -np 3 ./a.out
This should a print output like this
1 2 3 8 10 12 21 24 27
But, If I run the executable multiple times (without recompilation) sometimes it shows multiple results, like 1 2 3 4 5 6 21 24 27 etc. that is the values do not get updated with the calculation.
What I'm doing wrong here? How to fix this problem

Welcome to the wonderful world of shared memory programming!
You have a race condition. It is possible that one of the images is so far behind the others that it resets the (remote) data after the other image performs local = local*iz. Here's a way to fix it, being extra careful that only 1 process ever sets up a given part of the data:
ijb#ijb-Latitude-5410:~/work/stack$ cat caf.f90
program name
implicit none
integer:: arr(9), local(3)[*]
integer:: i, j, k, iz
iz = this_image()
! Only one image should ever write to a given memory location
! between synchronisation points. In a real code each different image
! would set up different parts of the array
If( iz == 1 ) Then
arr = [(i, i = 1, 9)]
local(:)[1] = arr(1:3)
local(:)[2] = arr(4:6)
local(:)[3] = arr(7:9)
End If
! Make sure the array is fully set up before you use it
sync all
local = local*iz
sync all
if(iz == 1) then
arr(1:3) = local(:)[1]
arr(4:6) = local(:)[2]
arr(7:9) = local(:)[3]
write(*,'(*(i3))')arr
endif
end program name
ijb#ijb-Latitude-5410:~/work/stack$ mpif90 -std=f2018 -fcheck=all -Wall -Wextra -O -g -fcoarray=lib caf.f90 -lcaf_openmpi
caf.f90:4:17:
4 | integer:: i, j, k, iz
| 1
Warning: Unused variable ‘j’ declared at (1) [-Wunused-variable]
caf.f90:4:20:
4 | integer:: i, j, k, iz
| 1
Warning: Unused variable ‘k’ declared at (1) [-Wunused-variable]
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27
ijb#ijb-Latitude-5410:~/work/stack$ mpirun -np 3 ./a.out
1 2 3 8 10 12 21 24 27

Related

Pi computation gives incorrect result with OpenMP

I new to OpenMP and wondering what is wrong with this code. It works in serial. I am using Ubuntu Linux and gfortran.
!
program test_rand
use omp_lib
implicit none
integer, parameter :: num_threads =36
integer*8,parameter :: nc = 1000000000
integer*8 ncirc,ncircs(0:35)
integer i,thread_num,istart,iend,ppt
real*8 x,y,dist,pi
integer,parameter :: seed = 864
call srand(seed)
do i=1,4
ncircs(i)=0
end do
ncirc=0
ppt=(nc+num_threads-1)/num_threads
istart=1
iend=nc
thread_num=1
!$ call omp_set_num_threads(num_threads)
!$omp parallel default(none) private(istart,iend,thread_num,i, &
!$omp dist,x,y,ncircs) shared(ppt,ncirc)
!$ thread_num = omp_get_thread_num()
!$ istart=thread_num*ppt+1
!$ iend = min(nc,thread_num*ppt+ppt)
print*,thread_num
do i=istart,iend
x=rand()
y=rand()
dist=sqrt((x-0.5)**2+(y-0.5)**2)
if (dist.le.0.5) ncircs(thread_num)=ncircs(thread_num)+1
end do
!$omp critical
!$ print*, "thread_num=",thread_num, "istart=",istart," iend=",iend,ncircs(thread_num+1)
ncirc=ncirc+ncircs(thread_num)
!$omp end critical
!$omp end parallel
print*,ncircs
pi=4*dble(ncirc)/dble(nc)
print *,pi,ncirc
end program test_rand
Output:
lakshmi#lakshmiVM:~/Documents/fortran$ gfortran -o pi pi.f95
lakshmi#lakshmiVM:~/Documents/fortran$ time ./pi
1
2 785398441 0 0 0 16777216 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 268435456 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3.1415937640000000 785398441
real 0m25.211s
user 0m25.152s
sys 0m0.000s
lakshmi#lakshmiVM:~/Documents/fortran$ gfortran -o pi_omp pi.f95 -fopenmp
lakshmi#lakshmiVM:~/Documents/fortran$ time ./pi_omp
3
21
25
30
35
18
4
17
11
34
12
28
7
33
29
24
31
27
8
23
10
19
0
6
26
32
16
14
1
13
5
20
15
2
9
22
thread_num= 6 istart= 166666669 iend= 194444446 0
thread_num= 11 istart= 305555559 iend= 333333336 0
thread_num= 5 istart= 138888891 iend= 166666668 0
thread_num= 27 istart= 750000007 iend= 777777784 0
thread_num= 19 istart= 527777783 iend= 555555560 0
thread_num= 25 istart= 694444451 iend= 722222228 0
thread_num= 2 istart= 55555557 iend= 83333334 0
thread_num= 1 istart= 27777779 iend= 55555556 0
thread_num= 21 istart= 583333339 iend= 611111116 0
thread_num= 18 istart= 500000005 iend= 527777782 0
thread_num= 20 istart= 555555561 iend= 583333338 0
thread_num= 24 istart= 666666673 iend= 694444450 0
thread_num= 29 istart= 805555563 iend= 833333340 0
thread_num= 28 istart= 777777785 iend= 805555562 0
thread_num= 26 istart= 722222229 iend= 750000006 0
thread_num= 12 istart= 333333337 iend= 361111114 0
thread_num= 22 istart= 611111117 iend= 638888894 0
thread_num= 23 istart= 638888895 iend= 666666672 0
thread_num= 10 istart= 277777781 iend= 305555558 0
thread_num= 3 istart= 83333335 iend= 111111112 0
thread_num= 34 istart= 944444453 iend= 972222230 0
thread_num= 17 istart= 472222227 iend= 500000004 0
thread_num= 15 istart= 416666671 iend= 444444448 0
thread_num= 14 istart= 388888893 iend= 416666670 0
thread_num= 8 istart= 222222225 iend= 250000002 0
thread_num= 7 istart= 194444447 iend= 222222224 0
thread_num= 30 istart= 833333341 iend= 861111118 0
thread_num= 32 istart= 888888897 iend= 916666674 0
thread_num= 9 istart= 250000003 iend= 277777780 0
thread_num= 4 istart= 111111113 iend= 138888890 0
thread_num= 16 istart= 444444449 iend= 472222226 0
thread_num= 0 istart= 1 iend= 27777778 93851473435152
thread_num= 13 istart= 361111115 iend= 388888892 0
thread_num= 35 istart= 972222231 iend= 1000000000 4600331172021844405
thread_num= 33 istart= 916666675 iend= 944444452 0
thread_num= 31 istart= 861111119 iend= 888888896 0
139938624438272 0 0 0 0 139942555560952 10 140720670311236 3933000496 0 139942559675136 466005475 139942562579304 140720670311528 139942559716466 140720670311360 140720670311376 139942562705897 3 139942555561536 1 0 1 139942562578432 361825296 139942555561536 139942562578432 139942562579304 0 140720670311656 139942559737213 140720308486145 4294967295 139942562705897 139942557392112 139942562581024
375409.03530958400 93852258827396
real 6m57.907s
user 8m35.083s
sys 219m5.670s
lakshmi#lakshmiVM:~/Documents/fortran$
I'm afraid there's quite a lot wrong with your program, both in terms of errors and of style. Let's first see how you can use the compiler to pick up some of the problems, then discuss the problems this compiler can't help you with, and then talk about style. Finally I'll show how I would solve this.
So first off I would recommend when developing turning on all the compiler warning and error detecting flags. There's quite a lot of these. Let's see what -Wall -Wextra tells you about your code:
ijb#ijb-Latitude-5410:~/work/stack$ gfortran-11 --version
GNU Fortran (GCC) 11.1.0
Copyright © 2021 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$ gfortran-11 -Wall -Wextra -fopenmp -O -g pi_orig.f90
pi_orig.f90:20:7:
20 | ppt=(nc+num_threads-1)/num_threads
| 1
Warning: Integer division truncated to constant ‘27777778’ at (1) [-Winteger-division]
pi_orig.f90:30:12:
30 | !$ iend = min(nc,thread_num*ppt+ppt)
| 1
Warning: Possible change of value in conversion from INTEGER(8) to INTEGER(4) at (1) [-Wconversion]
I'm not worried about the first warning, but the second is telling me that iend might not be a long enough integer to store the iteration numbers you require - and by implication neither is i and a number of other variables. Thus if you increase nc after a certain point you just won't get increased accuracy.
However your program is not written in standard Fortran. Following the standard will in the long run make your life much easier. So let's add -std=2008 to use the compiler to detect where you are not using standard Fortran:
ijb#ijb-Latitude-5410:~/work/stack$ gfortran-11 -Wall -Wextra -std=f2008 -fopenmp -O -g pi_orig.f90
pi_orig.f90:8:12:
8 | integer*8,parameter :: nc = 1000000000
| 1
Error: GNU Extension: Nonstandard type declaration INTEGER*8 at (1)
pi_orig.f90:9:12:
9 | integer*8 ncirc,ncircs(0:35)
| 1
Error: GNU Extension: Nonstandard type declaration INTEGER*8 at (1)
pi_orig.f90:11:9:
11 | real*8 x,y,dist,pi
| 1
Error: GNU Extension: Nonstandard type declaration REAL*8 at (1)
pi_orig.f90:37:23:
37 | if (dist.le.0.5) ncircs(thread_num)=ncircs(thread_num)+1
| 1
Error: Syntax error in IF-clause after (1)
pi_orig.f90:45:15:
45 | print*,ncircs
| 1
Error: Function ‘ncircs’ requires an argument list at (1)
pi_orig.f90:27:12:
27 | !$omp dist,x,y,ncircs) shared(ppt,ncirc)
| 1
Error: Symbol ‘dist’ at (1) has no IMPLICIT type
pi_orig.f90:20:9:
20 | ppt=(nc+num_threads-1)/num_threads
| 1
Error: Symbol ‘nc’ at (1) has no IMPLICIT type
pi_orig.f90:18:7:
18 | ncirc=0
| 1
Error: Symbol ‘ncirc’ at (1) has no IMPLICIT type
pi_orig.f90:46:4:
46 | pi=4*dble(ncirc)/dble(nc)
| 1
Error: Symbol ‘pi’ at (1) has no IMPLICIT type; did you mean ‘i’?
pi_orig.f90:27:14:
27 | !$omp dist,x,y,ncircs) shared(ppt,ncirc)
| 1
Error: Symbol ‘x’ at (1) has no IMPLICIT type
pi_orig.f90:27:16:
27 | !$omp dist,x,y,ncircs) shared(ppt,ncirc)
| 1
Error: Symbol ‘y’ at (1) has no IMPLICIT type
pi_orig.f90:14:12:
14 | call srand(seed)
| 1
Warning: The intrinsic ‘srand’ at (1) is not included in the selected standard but a GNU Fortran extension and ‘srand’ will be treated as if declared EXTERNAL. Use an appropriate ‘-std=’* option or define ‘-fall-intrinsics’ to allow this intrinsic. [-Wintrinsics-std]
pi_orig.f90:14:12: Warning: The intrinsic ‘srand’ at (1) is not included in the selected standard but a GNU Fortran extension and ‘srand’ will be treated as if declared EXTERNAL. Use an appropriate ‘-std=’* option or define ‘-fall-intrinsics’ to allow this intrinsic. [-Wintrinsics-std]
pi_orig.f90:14:18:
14 | call srand(seed)
| 1
Warning: The intrinsic ‘srand’ at (1) is not included in the selected standard but a GNU Fortran extension and ‘srand’ will be treated as if declared EXTERNAL. Use an appropriate ‘-std=’* option or define ‘-fall-intrinsics’ to allow this intrinsic. [-Wintrinsics-std]
pi_orig.f90:16:5:
16 | ncircs(i)=0
| 1
Error: Function ‘ncircs’ at (1) has no IMPLICIT type
pi_orig.f90:34:11:
34 | x=rand()
| 1
Warning: The intrinsic ‘rand’ at (1) is not included in the selected standard but a GNU Fortran extension and ‘rand’ will be treated as if declared EXTERNAL. Use an appropriate ‘-std=’* option or define ‘-fall-intrinsics’ to allow this intrinsic. [-Wintrinsics-std]
pi_orig.f90:34:11: Warning: The intrinsic ‘rand’ at (1) is not included in the selected standard but a GNU Fortran extension and ‘rand’ will be treated as if declared EXTERNAL. Use an appropriate ‘-std=’* option or define ‘-fall-intrinsics’ to allow this intrinsic. [-Wintrinsics-std]
pi_orig.f90:34:7:
34 | x=rand()
| 1
Warning: The intrinsic ‘rand’ at (1) is not included in the selected standard but a GNU Fortran extension and ‘rand’ will be treated as if declared EXTERNAL. Use an appropriate ‘-std=’* option or define ‘-fall-intrinsics’ to allow this intrinsic. [-Wintrinsics-std]
pi_orig.f90:34:7:
34 | x=rand()
| 1
Error: Function ‘rand’ at (1) has no IMPLICIT type
pi_orig.f90:35:7:
35 | y=rand()
| 1
Error: Function ‘rand’ at (1) has no IMPLICIT type
pi_orig.f90:41:70:
41 | !$ print*, "thread_num=",thread_num, "istart=",istart," iend=",iend,ncircs(thread_num+1)
| 1
Error: Function ‘ncircs’ at (1) has no IMPLICIT type
pi_orig.f90:42:20:
42 | ncirc=ncirc+ncircs(thread_num)
| 1
Error: Function ‘ncircs’ at (1) has no IMPLICIT type
pi_orig.f90:27:17:
27 | !$omp dist,x,y,ncircs) shared(ppt,ncirc)
| 1
Error: Object ‘ncircs’ is not a variable at (1)
ijb#ijb-Latitude-5410:~/work/stack$
Oh dear! In fact there's only really 3 errors:
Real*8 is not, and has never been, part of standard Fortran. It is supported by gfortran, but might not be by other compilers. Don't use it!
Integer*8 is not, and has never been, part of standard Fortran. It is supported by gfortran, but might not be by other compilers. Don't use it!
srand and rand are not a standard Fortran intrinsic function. It is supported by gfortran, but might not be by other compilers. Don't use it!
Number 3 can be addressed by using the standard intrinsic Random_number (but see below). Numbers 1 and 2 are solved by using kinds - see Fortran 90 kind parameter . And because 1 and 2 affect variable declarations all lines that use variables declared by these erroneous lines are now flagged as errors themselves, hence the cascade of errors.
Fixing these solves some things, but I'm afraid there are more errors. In particular there are accesses of arrays outside their bounds. You can automatically detect these by use of -fcheck=all which I very strongly recommend while debugging, but note it will slow down your program a lot, so when running production runs omit it. If I fix the errors noted above, and then use -fcheck=all when I run the program I get:
ijb#ijb-Latitude-5410:~/work/stack$ gfortran-11 -Wall -Wextra -std=f2008 -fcheck=all -fopenmp -O -g pi2.f90
pi2.f90:22:7:
22 | ppt=(nc+num_threads-1)/num_threads
| 1
Warning: Integer division truncated to constant ‘2778’ at (1) [-Winteger-division]
ijb#ijb-Latitude-5410:~/work/stack$ ./a.out
1
28
14
26
32
9
5
8
10
35
21
29
0
22
17
4
19
thread_num= 14 istart= 38893 iend= 41670 0
thread_num= 21 istart= 58339 iend= 61116 0
thread_num= 28 istart= 77785 iend= 80562 0
20
12
7
24
23
15
34
25
thread_num= 26 istart= 72229 iend= 75006 0
thread_num= 23 istart= 63895 iend= 66672 0
thread_num= 10 istart= 27781 iend= 30558 0
thread_num= 15 istart= 41671 iend= 44448 0
thread_num= 1 istart= 2779 iend= 5556 0
thread_num= 25 istart= 69451 iend= 72228 0
thread_num= 9 istart= 25003 iend= 27780 0
16
33
30
thread_num= 0 istart= 1 iend= 2778 0
27
thread_num= 7 istart= 19447 iend= 22224 0
31
2
6
thread_num= 17 istart= 47227 iend= 50004 0
3
13
11
thread_num= 27 istart= 75007 iend= 77784 0
thread_num= 30 istart= 83341 iend= 86118 0
thread_num= 32 istart= 88897 iend= 91674 0
thread_num= 4 istart= 11113 iend= 13890 0
thread_num= 19 istart= 52783 iend= 55560 0
thread_num= 2 istart= 5557 iend= 8334 0
18
thread_num= 6 istart= 16669 iend= 19446 0
thread_num= 5 istart= 13891 iend= 16668 0
thread_num= 3 istart= 8335 iend= 11112 0
thread_num= 24 istart= 66673 iend= 69450 0
thread_num= 8 istart= 22225 iend= 25002 0
thread_num= 34 istart= 94453 iend= 97230 0
thread_num= 11 istart= 30559 iend= 33336 0
thread_num= 29 istart= 80563 iend= 83340 0
thread_num= 22 istart= 61117 iend= 63894 0
thread_num= 16 istart= 44449 iend= 47226 0
thread_num= 20 istart= 55561 iend= 58338 0
thread_num= 12 istart= 33337 iend= 36114 0
At line 45 of file pi2.f90
Fortran runtime error: Index '36' of dimension 1 of array 'ncircs' above upper bound of 35
Error termination. Backtrace:
#0 0x7f580fce1d01 in ???
#1 0x7f580fce2849 in ???
#2 0x7f580fce2ec6 in ???
#3 0x4015ab in MAIN__._omp_fn.0
at /home/ijb/work/stack/pi2.f90:45
#4 0x7f580fb4a77d in ???
#5 0x7f580fab1608 in start_thread
at /build/glibc-YbNSs7/glibc-2.31/nptl/pthread_create.c:477
#6 0x7f580f9d6292 in ???
#7 0xffffffffffffffff in ???
So you can use the compiler to find a lot of problems. However there are more that it can't catch. Most importantly you scope the array ncircs as private, but you don't initialise it within the parallel region - When you enter the parallel region each thread will generate their own new version of a private variable, and by default any initialisation outside the parallel region will be forgotten. So you are using an uninitialized variable. Even without that also note in the code as presented you only initialise part of ncircs, not all that you use, and you are off by one in the indexing.
Over and above the errors noted above, however, this is not really how you should write openmp code. OpenMP provides methods to automatically share out the work in loops, you really shouldn't be sharing out the iterations manually as you have done in your code. Further it provides reductions to perform exactly this sort of calculation, critical should only be used where it is needed, not for the specialist case shown here for which reduce excels. There is also no need for the ncircs array - each thread only needs one value for it, so why declare an array of them? As a rule of thumb if you declare memory that increases in size with the number of threads you are probably doing something wrong. Finally I also wouldn't burn the number of threads into the code, I would use the environment variable to set the number of threads so it can be changed without a recompile.
So here is how I would solve your problem, and showing that it compiles and runs correctly:
ijb#ijb-Latitude-5410:~/work/stack$ cat pi_ijb.f90
Program pi_calc
Use, Intrinsic :: iso_fortran_env, Only : wp => real64, li => int64
Use omp_lib
Implicit None
Real( wp ), Parameter :: pi_exact = 4.0_wp * Atan( 1.0_wp )
Integer( li ), Parameter :: n_sample = 1000000000_li
Integer , Parameter :: seed = 864
Real( wp ), Dimension( 1:2 ) :: rand
Real( wp ) :: dist
Real( wp ) :: pi_approx
Integer( li ) :: ncirc
Integer( li ) :: i_sample
Integer( li ) :: start, finish, rate
Integer :: thread_num
Integer :: n_seed
Integer :: i
! Assume using the maximum number of threads made available
Write( *, * ) 'Running on ', omp_get_max_threads(), ' threads'
ncirc = 0
Call system_clock( start, rate )
! Create threads
!$omp parallel default( none ) private( thread_num, n_seed, i, rand, dist ) reduction( +:ncirc )
! Set up the random number generator. Assume it is thread safe
thread_num = omp_get_thread_num()
Call Random_seed( size = n_seed )
Call Random_seed( put = [ ( i * seed * ( thread_num + 1 ), i = 1, n_seed ) ] )
! Workshare the loop
!$omp do
Sampling_loop: Do i_sample = 1, n_sample
Call Random_number( rand )
rand = rand - 0.5_wp
dist = rand( 1 ) * rand( 1 ) + rand( 2 ) * rand( 2 )
If( dist <= 0.5_wp * 0.5_wp ) Then
ncirc = ncirc + 1
End If
End Do Sampling_loop
!$omp end do
! Close down the parallel region
!$omp end parallel
Call system_clock( finish, rate )
pi_approx = 4.0_wp * Real( ncirc, wp ) / Real( n_sample, wp )
Write( *, * ) 'Using ', n_sample, ' sampling points: '
Write( *, * ) 'Approx pi ', pi_approx
Write( *, * ) 'Exact pi ', pi_exact
Write( *, * ) 'Error ', Abs( pi_approx - pi_exact )
Write( *, * ) 'This took ', Real( finish - start ) / Real( rate ), ' seconds'
End Program pi_calc
ijb#ijb-Latitude-5410:~/work/stack$ gfortran-11 -Wall -Wextra -fcheck=all -O -g -fopenmp pi_ijb.f90
ijb#ijb-Latitude-5410:~/work/stack$ export OMP_NUM_THREADS=4
ijb#ijb-Latitude-5410:~/work/stack$ ./a.out
Running on 4 threads
Using 1000000000 sampling points:
Approx pi 3.1415474360000002
Exact pi 3.1415926535897931
Error 4.5217589792923008E-005
This took 5.21012735 seconds
ijb#ijb-Latitude-5410:~/work/stack$ gfortran-11 -Wall -Wextra -O -g -fopenmp pi_ijb.f90
ijb#ijb-Latitude-5410:~/work/stack$ export OMP_NUM_THREADS=1
ijb#ijb-Latitude-5410:~/work/stack$ ./a.out
Running on 1 threads
Using 1000000000 sampling points:
Approx pi 3.1415804920000001
Exact pi 3.1415926535897931
Error 1.2161589793002747E-005
This took 18.5533371 seconds
ijb#ijb-Latitude-5410:~/work/stack$ export OMP_NUM_THREADS=2
ijb#ijb-Latitude-5410:~/work/stack$ ./a.out
Running on 2 threads
Using 1000000000 sampling points:
Approx pi 3.1416029320000001
Exact pi 3.1415926535897931
Error 1.0278410206954192E-005
This took 8.87815666 seconds
ijb#ijb-Latitude-5410:~/work/stack$ export OMP_NUM_THREADS=4
ijb#ijb-Latitude-5410:~/work/stack$ ./a.out
Running on 4 threads
Using 1000000000 sampling points:
Approx pi 3.1415474360000002
Exact pi 3.1415926535897931
Error 4.5217589792923008E-005
This took 4.49851656 seconds
Finally note I have assumed the standard Random number generator is thread safe, for simplicitly. However it is my understanding that this is not gauranteed, and if you want to do this kind of thing seriously you should look into providing your own,

Incorrect reading of a variable from a txt (Fortran)

I'm trying to read this txt:
Fecha dia mes ano hora min
03/06/2016 00:00 3 6 2016 0 0
03/06/2016 00:05 3 6 2016 0 5
03/06/2016 00:10 3 6 2016 0 10
03/06/2016 00:15 3 6 2016 0 15
03/06/2016 00:20 3 6 2016 0 20
03/06/2016 00:25 3 6 2016 0 25
03/06/2016 00:30 3 6 2016 0 30
03/06/2016 00:35 3 6 2016 0 35
03/06/2016 00:40 3 6 2016 0 40
03/06/2016 00:45 3 6 2016 0 45
03/06/2016 00:50 3 6 2016 0 50
03/06/2016 00:55 3 6 2016 0 55
03/06/2016 01:00 3 6 2016 1 0
With the following code:
program fecha
implicit none
integer, dimension(13):: dia, mes, ano, hora, minuto
character*50 :: formato = '(11x,5x,1x,i1,1x,i1,1x,i4,1x,i1,1x,i2)'
open (unit = 10, file = 'datos.txt')
read(10,*)
read(unit = 10, fmt = formato) dia, mes, ano, hora, minuto
write(*,*) dia
close(10)
end program
Why this code read 'dia' in this way:
3 6 2016 0 0 3 6 2016 0 5 3 6 2016
(I know how it's reading but not why)
You need to skip two lines at the beginning as well as reading the values line by line.
The following example is a slight modification of your program which runs smoothly.
program fecha
implicit none
integer :: i, iounit
integer, parameter :: n = 13
integer, dimension(n) :: dia, mes, ano, hora, minuto
open (newunit = iounit, file = 'datos.txt')
read (iounit, *)
read (iounit, *)
do i = 1, n
read (unit = iounit, fmt = '(16x, i5, i4, i7, 2i5)') dia(i), mes(i), ano(i), hora(i), minuto(i)
print *, dia(i), mes(i), ano(i), hora(i), minuto(i)
end do
close (iounit)
end program
My output is
$ gfortran -g3 -Wall -fcheck=all a.f90 && ./a.out
3 6 2016 0 0
3 6 2016 0 5
3 6 2016 0 10
3 6 2016 0 15
3 6 2016 0 20
3 6 2016 0 25
3 6 2016 0 30
3 6 2016 0 35
3 6 2016 0 40
3 6 2016 0 45
3 6 2016 0 50
3 6 2016 0 55
3 6 2016 1 0

Pandas grouped differences with variable lags

I have a pandas data frame with three variables. The first is a grouping variable, the second a within group "scenario" and the third an outcome. I would like to calculate the within group difference between the null condition, scenario zero, and the other scenarios within the group. The number of scenarios varies between the different groups. My data looks like:
ipdb> aDf
FieldId Scenario TN_load
0 0 0 134.922952
1 0 1 111.787326
2 0 2 104.805951
3 1 0 17.743467
4 1 1 13.411849
5 1 2 13.944552
6 1 3 17.499152
7 1 4 17.640090
8 1 5 14.220673
9 1 6 14.912306
10 1 7 17.233862
11 1 8 13.313953
12 1 9 17.967438
13 1 10 14.051882
14 1 11 16.307317
15 1 12 12.506358
16 1 13 16.266233
17 1 14 12.913150
18 1 15 18.149811
19 1 16 12.337736
20 1 17 12.008868
21 1 18 13.434605
22 2 0 454.857959
23 2 1 414.372215
24 2 2 478.371387
25 2 3 385.973388
26 2 4 487.293966
27 2 5 481.280175
28 2 6 403.285123
29 3 0 30.718375
... ... ...
29173 4997 3 53.193992
29174 4997 4 45.800968
I will also have to write functions to get percentage differences etc. but this has me stumped. Any help greatly appreciated.
You can get the difference with the scenario 0 within groups using groupby and transform like:
df['TN_load_0'] = df['TN_load'].groupby(df['FieldId']).transform(lambda x: x - x.iloc[0])
df
FieldId Scenario TN_load TN_load_0
0 0 0 134.922952 0.000000
1 0 1 111.787326 -23.135626
2 0 2 104.805951 -30.117001
3 1 0 17.743467 0.000000
4 1 1 13.411849 -4.331618
5 1 2 13.944552 -3.798915
6 1 3 17.499152 -0.244315

Keep first record when event occurrs

I have the following data in Stata:
clear
* Input data
input grade id exit time
1 1 . 10
2 1 . 20
3 1 2 30
4 1 0 40
5 1 . 50
1 2 0 10
2 2 0 20
3 2 0 30
4 2 0 40
5 2 0 50
1 3 1 10
2 3 1 20
3 3 0 30
4 3 . 40
5 3 . 50
1 4 . 10
2 4 . 20
3 4 . 30
4 4 . 40
5 4 . 50
1 5 1 10
2 5 2 20
3 5 1 30
4 5 1 40
5 5 1 50
end
The objective is to take the first row foreach id when a event occurs and if no event occur then take the last report foreach id. Here is a example for the data I hope to attain
* Input data
input grade id exit time
3 1 2 30
5 2 0 50
1 3 1 10
5 4 . 50
1 5 1 10
end
The definition of an event appears to be that exit is not zero or missing. If so, then all you need to do is tweak the code in my previous answer:
bysort id (time): egen when_first_e = min(cond(exit > 0 & exit < ., time, .))
by id: gen tokeep = cond(when_first_e == ., time == time[_N], time == when_first_e)
Previous thread was here.

Comparison of two CSV files in Python

I want to compare two csv files looking like below.
Here I want to find out unmatched signals.
I need some help in python. Please help me.
File 1
2
USER Name
7/31/2015 0:00
<XXXXXXX>
1 Signal_1 10
2 Signal_2 1 2 3 4 5
3 Signal_3 X 5 10 15 20 25 Y 6 11 16 21 26
1 Signal_4 20
1 Signal_5 30
2 Signal_6 6 7 8 9 10 11 12 13
2 Signal_7 55 1.05 1.6 14.1
3 Signal_8 X 30 40 50 60 40 Y 14 15 26 14 26
2 Signal_9 1 1 2 3 2
1 Signal_10 40
File 2
2
USER Name
7/31/2015 0:00
<XXXXXXX>
3 Signal_3 X 20 10 15 17 25 Y 6 11 16 21 26
1 Signal_5 5
2 Signal_7 55 1.05 1.6 14.1
1 Signal_1 10
3 Signal_8 X 30 40 50 60 40 Y 14 15 26 14 26
1 Signal_10 14
2 Signal_9 1 1 2 3 2
2 Signal_6 6 7 8 59 10 15 12 13
1 Signal_4 20
2 Signal_2 1 2 3 4 5
Result:
File
3 Signal_3 X 5 10 15 20 25 Y 6 11 16 21 26
1 Signal_5 30
1 Signal_10 40
2 Signal_6 6 7 8 9 10 11 12 13
File 2
3 Signal_3 X 20 10 15 17 25 Y 6 11 16 21 26
1 Signal_5 5
1 Signal_10 14
2 Signal_9 1 1 2 3 2
If you want to check for fairly exact comparisons, you can use sets quite easily:
def sigset(fname):
with open(fname, 'rb') as f:
data = set(' '.join(line.split()) for line in f
if 'Signal' in line)
return data
s1 = sigset('sig1.txt')
s2 = sigset('sig2.txt')
print('File 1')
for line in sorted(s1 - s2):
print(line)
print('')
print('File 2')
for line in sorted(s2 - s1):
print(line)
with open('Sample1.csv', 'r') as t1, open('Sample2.csv', 'r') as t2:
fileone = t1.readlines()
filetwo = t2.readlines()
print fileone
print filetwo
with open('update.csv', 'w') as outFile:
for line in filetwo:
if line not in fileone:
outFile.write(line)
for line in fileone:
if line not in filetwo:
outFile.write(line)