Related
Good day to everyone!
I perform parallel calculations using Fortran + mpi (technical details on compilator, OS are listed in the end of this question) and I have the following problem: the result of calculations is changed dramatically if I add or remove a line in my code, that is absolutely irrelevant for very calculations.
The whole code consists of three parts:
the main program IntColl.f90 containing parallel fragments of the code
module m.f90 containing lots of functions to perform specific calculations. One of functions in this module contains the lines being or lack of which in the code is reflected on results of calculations.
module Constants.f90 containing various constants.
The code contains about 2k lines so I only can to show some fragments, which in my opinion have the most significant mean to the question.
Here are code snippets from the main program file IntColl.f90 with parallel calculations:
DO counter1 = 1, NG
IF ( MOD ( counter1, CN ) .EQ. RANK ) THEN
YDOT ( counter1 ) = FACTOR * ABt ( dmgw ( counter1 ) ) + &
FACTOR1 * CIng ( dmgw ( counter1 ) )
YDOT ( counter1 + NG ) = FACTOR * ABMt ( dmgw ( counter1 ) )
END IF
END DO
DO counter = 1, ( CN - 1 )
IF ( RANK .EQ. counter ) THEN
CALL MPI_SEND ( &
YDOT ( counter ), &
1, &
MPI_DP_VEC, &
0, &
1, &
MPI_COMM_WORLD, &
IERROR &
)
END IF
IF ( RANK .EQ. 0 ) THEN
CALL MPI_RECV ( &
YDOT ( counter ), &
1, &
MPI_DP_VEC, &
counter, &
1, &
MPI_COMM_WORLD, &
MPI_STATUS_IGNORE, &
IERROR &
)
END IF
END DO
CALL MPI_BCAST ( &
YDOT ( 1 ), &
2 * NG, &
MPI_DOUBLE_PRECISION, &
RANK, &
MPI_COMM_WORLD, &
IERROR &
)
CN is the number of threads.
Next, here is the function CIng ( p ) from module m.f90 called within parallel piece of the code:
REAL ( DP ) FUNCTION CIng ( p ) ! Collisional integral for \nu + \gamma
IMPLICIT NONE
INTEGER :: i, CTR
REAL ( DP ) :: p ! p is coordinate momentum of initial neutrino: nu ( p ) + gamma ( k ) --> nu ( q ) + e^- ( q1 ) + e^+ ( q2 )
REAL ( DP ) :: const_A
REAL ( DP ) :: const_i
REAL ( DP ) :: const
REAL ( DP ) :: a, b
REAL ( DP ) :: z1, z2, z3, z4, z5, z6, z7
i = 0
CTR = 0
const_A = 128.D+00 * PI * FSC * G_F ** 2 * ( M_E / X ) ** 2
const_i = ( DSQRT ( YMAX ** 2 + X ** 2 ) - X ) ** 2 * YMAX / 2.D+00 ** 8 / PI ** 5 / p * ( M_E / X ) ** 3
const = const_A * const_i
a = 0.D+00
z1 = 0.D+00
z2 = 0.D+00
z3 = 0.D+00
z4 = 0.D+00
z5 = 0.D+00
z6 = 0.D+00
z7 = 0.D+00
DO i = 1, NS
b = 0.D+00
z1 = x1 ( i )
z2 = x2 ( i )
z3 = x3 ( i )
z4 = x4 ( i )
z5 = x5 ( i )
z6 = x6 ( i )
z7 = x7 ( i )
b = UndInt ( p, z1, z2, z3, z4, z5, z6, z7 )
a = a + b
IF ( b .NE. 0.D+00 ) THEN
CTR = CTR + 1
WRITE ( 9, "(2ES23.15)" ) x2 ( i ), x3 ( i ) ! This #1
END IF
END DO
print *, p, CTR, 'q' ! This #2
CIng = const * a / NS
END FUNCTION CIng
The thing is when I comment lines marked with labels This #1 and This #2 the result of calculations I obtain differs catastrophically from the results obtained when these lines are not commented. Note: results of calculations obtained are "good" in my opinion if at least one of these two lines are not commented.
Some clarification: the result of my calculations is some physical dependence which should be at least piecewise smooth. I really obtain points which lie on a piecewise smooth curve at some conditions (third level of optimization at compilation and not commented line This #1), and such result I guess "good". When I comment I/O instructions points become similar to noise without any visual dependence. And I consider intuitively such the result "bad".
The function CIng ( p ) calls one more function UndInt ( p, z1, z2, z3, z4, z5 ,z6, z7 ) which in turn calls next functions, but all these functions just perform some calculations.
Arrays x1 ( i ), x2 ( i ), ... are filled with numbers from a file in IntColl.f90. These arrays are declared in the module Constants.f90 and this module are used in the main program IntColl.f90 and in the module m.f90.
I have to say that the result of calculations is also dependent on level 'n' of optimization at compilation (-O<n>). When both lines #This 1 and #This 2 are commented results of calculations are bad at any level of optimization.
I tried to add options -Wall and -Wextra when compiling. These options showed lots of warnings of following types:
<variable> may be uninitialized in this function
and
Inequality comparison for REAL(8) at (1).
Adding of options -fbacktrace -fcheck=all -g when compiling lead to "bad" result even if one of lines This #1 and This #2 are not commented.
The major part of these warnings are related to functions from fortran libraries I use in my program (e.g., DLSODA).
I also want to specify that time of calculation of value CIng ( dmgw ( counter1 ) ) grows monotonously when counter1 goes from 1 to NG (NG is 96 if it matters).
Here are a few technical details:
The code is written on Fortran90, I compile it using the command
mpif90.mpich *.f90 *.f -O3 -o <name>
and I execute it using the command
mpirun -np <number of threads> ./<name>,
in terminal of my computer with the OS Ubuntu 18.04.04 LTS, version of mpirun is 3.3a2;
on the version of compiler: mpif90 --version reports GNU Fortran (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0.
Please, say me if it is needed any additional information.
I will be grateful for any answer/comment on this qestion or for information about same problems known earlier.
UPD
I am very ashamed, but it has been found out that my problem is absolutely not related with multiprocessing.
The thing is I had in program a variable that could stay uninitialized when program is executed.
Namely, in module m.f90 I have a function UndInt_ ( ... ) containing internal variables a and b.
If these variables are not initialized immediately after their declaration their initialization is performed within a chain of quite intricate nested IF conditions:
REAL ( DP ) FUNCTION UndInt_ ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 )
IMPLICIT NONE
REAL ( DP ), INTENT ( IN ) :: p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2
REAL ( DP ) :: q1 ! q1 is the coordinate momentum of electron ( the momentum of electron multiplied by ( X / M_E ) )
REAL ( DP ) :: q2 ! q2 is the coordinate momentum of positron
REAL ( DP ) :: sinTh1
REAL ( DP ) :: sinTh2
REAL ( DP ) :: cosph1
REAL ( DP ) :: cosph2
REAL ( DP ) :: cosThk ! cos of the polar angle of electron
REAL ( DP ) :: q ! the absolute value of coordinate momentum of outgoing neutrino
REAL ( DP ) :: a, b
a = 0.0 ! This variable
b = 0.0 ! And this variable
q1 = DSQRT ( eps1 ** 2 - X ** 2 )
q2 = DSQRT ( eps2 ** 2 - X ** 2 )
sinTh1 = DSQRT ( 1.D+00 - cosTh1 ** 2 )
sinTh2 = DSQRT ( 1.D+00 - cosTh2 ** 2 )
cosph1 = DCOS ( phi1 )
cosph2 = DCOS ( phi2 )
IF ( ( k ** 2 * ( q1 * cosTh1 + q2 * cosTh2 - p ) ** 2 + &
k ** 2 * ( q1 * sinTh1 * cosph1 + q2 * sinTh2 * cosph2 ) ** 2 &
) .LT. &
( p * ( k - eps1 - eps2 ) - k * ( eps1 + eps2 ) + eps1 * eps2 + X ** 2 + &
p * q1 * cosTh1 + p * q2 * cosTh2 - &
q1 * q2 * ( sinTh1 * sinTh2 * DCOS ( phi1 - phi2 ) + cosTh1 * cosTh2 ) &
) ** 2 &
) THEN
a = 0.0
b = 0.0
ELSE
IF ( ( cosThk1 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) .GT. 1.D+00 ) &
.OR. ( cosThk1 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) .LT. -1.D+00 ) &
.AND. ( cosThk2 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) .GT. 1.D+00 ) &
.OR. ( cosThk2 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) .LT. -1.D+00 ) &
) THEN
a = 0.0
b = 0.0
ELSE
IF ( ( DABS ( p + k - eps1 - eps2 - &
q_1 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) &
) / &
( p + k - eps1 - eps2 ) &
) .LT. 1.D-015 &
) THEN
cosThk = cosThk1 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 )
q = q_1 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 )
a = UndInt1 ( p, k, q, eps1, eps2, cosThk, cosTh1, cosTh2, phi1, phi2 )
END IF
IF ( ( DABS ( p + k - eps1 - eps2 - &
q_2 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) &
) / &
( p + k - eps1 - eps2 ) &
) .LT. 1.D-015 .AND. &
( DABS ( &
( cosThk1 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) - &
cosThk2 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) ) / &
cosThk1 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 ) &
) &
) .GT. 1.D-015 &
) THEN
cosThk = cosThk2 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 )
q = q_2 ( p, k, eps1, eps2, cosTh1, cosTh2, phi1, phi2 )
b = UndInt1 ( p, k, q, eps1, eps2, cosThk, cosTh1, cosTh2, phi1, phi2 )
END IF
END IF
END IF
UndInt_ = a + b
END FUNCTION UndInt_
It looks like for some cases these variables has been stayed uninitialized within the function UndInt_ and were "dirty".
Finally a value of variable UndInt_ that is returned by finction UndInt_ ( ... ) is defined with variables a and b, so a junk from these variables has been passed to variable UndInt_.
That's it.
I understand, that this bug could be fixed immediately if I used options -fbacktrace -fcheck=all -g at compilation.
I would like to say thank you one more time for answers and comments.
I am going to be more careful in future.
I am new to fortran and I am trying to write code using random data instead of binned data in x, y, z as shown in my sample code.
implicit real*8(a-h,o-z)
dimension rm(4),rp1(4),rip1(4),rp2(4),rip2(4),rp3(4),rip3(4),
d rn(4),u1(4),u2(4),u3(4)
do ix= 1000,25000,1000
x = ix/1000000.
do iy= 1000,25000,1000
y = iy/100000.
do iz= 1,1000,25
z = iz/10000.
a=(x**2+y**2)/z
b=x*y*z
c=x*y**2+y*z**2+z*x**2
fr=(a*b)/c
if(fr.ge.0.05.and.fr.le.23)then
write(40,*)x,y,x,fr
else
endif
end do
end do
end do
stop
How to convert such code having binned data to a code using random draws.
As an example binned data here means possible fixed values of x are {1000/1000000.,2000/1000000., .....,25000/1000000.} i.e. 25 possible values in range {.001, .025} but they are not random values
In case of random values 25 points will be drawn from the range {.001, .025} randomly.
This my assumption about doing the analysis with random draws(previously I was not familiar with this ).
Something like
ian#eris:~/work/stack$ cat data.f90
Program random_data
Use, Intrinsic :: iso_fortran_env, Only : wp => real64
Implicit None
Real( wp ), Parameter :: min_rand = 0.001_wp
Real( wp ), Parameter :: max_rand = 0.025_wp
Integer, Parameter :: n_samples = 25
Real( wp ) :: x, y, z
Real( wp ) :: a, b, c
Real( wp ) :: fr
Integer :: i_sample
Do i_sample = 1, n_samples
Call Random_number( x )
Call Random_number( y )
Call Random_number( z )
x = x * ( max_rand - min_rand ) + min_rand
y = y * ( max_rand - min_rand ) + min_rand
z = z * ( max_rand - min_rand ) + min_rand
a=(x**2+y**2)/z
b=x*y*z
c=x*y**2+y*z**2+z*x**2
fr=(a*b)/c
If( fr >= 0.05_wp .And. fr <= 23.0_wp )Then
Write( 40, * ) x, y, x, fr
Endif
End Do
End Program random_data
ian#eris:~/work/stack$ gfortran-10 -Wall -Wextra -fcheck=all -std=f2008 -g -finit-real=snan data.f90
ian#eris:~/work/stack$ ./a.out;more fort.40
more: stat of fort.40 failed: No such file or directory
Unfortunately none of the random numbers in this run produced an output that lay in the desired range - however I did test it with 2500 samples and then a couple did.
I'm trying to implement a modified Dijkstra's algorithm to find the shortest path with highest weighted value between all nodes of an undirected graph.
My problem is that I don't know how to properly change my original Fortran code (that finds the minimum path with the lowest weight value). I would like to ask if you could help me with ideas to revise this code, mainly the subroutines find_nearest and update_mind, as well the code to run all over the nodes.
c ***************************************************************************
subroutine dijkstra (nmols, matrixS)
implicit none
include 'COMMONP.dat'
integer nmols, i, j, k1, k2, step, md, mv
logical connected(nmols)
integer, parameter :: i4_huge = 2147483647
dimension mind(nmolsp), ohd(nmolsp, nmolsp)
c
ohd(1:nmols,1:nmols) = i4_huge
c
do i = 1, nmols
ohd(i,i) = 0
end do
c
c Loading the weighted matrix
c
do 14 k1 = 1, nmols
do 15 k2 = 1, nmols
if matrixS(k1,k2).ne.0 then
ohd(k1,k2) = matrixS(k1,k2)
15 continue
14 continue
c
c carry out the algorithm
c start out with only node 1 connected to the tree.
c
do 33 node = 1, nmols
connected(1:nmols) = .false.
connected(node) = .true.
c
c initialize the minimum distance to the one-step distance
c
mind(1:nmols) = ohd(node,1:nmols)
c
c attach one more node on each interaction
do step = 1, nmols
call find_nearest (nmols, mind, connected, md, mv)
if ( mv == -1 ) then
write ( *, '(a)' ) ' '
write ( *, '(a)' ) 'DIJKSTRA_DISTANCE - Warning!'
write ( *, '(a)' ) ' Search terminated early.'
write ( *, '(a)' ) ' Graph might not be connected.'
return
end if
c
c Mark this node as connected
c
connected(mv) = .true.
c
c Having determined the minimum distance to node MV, see
c what is the highest weighted path to other nodes.
c
call update_mind ( nmols, connected, ohd, mv, mind )
end do
! Print the results.
!
write ( *, '(a)' ) ' '
write ( *, '(a)' ) ' Minimum path from node i:'
write ( *, '(a)' ) ' '
do i = 1, nmols
write ( *, '(2x,i2,2x,i2)' ) i, mind(i)
end do
33 continue
!
stop
end
c ***************************************************************************
subroutine find_nearest (nmols, mind, connected, md, mv)
implicit none
integer ( kind = 4 ) nmols
logical ( kind = 4 ) connected(nmols)
integer ( kind = 4 ) d
integer ( kind = 4 ) i
integer ( kind = 4 ), parameter :: i4_huge = 2147483647
integer ( kind = 4 ) mind(nmols)
integer ( kind = 4 ) v
d = i4_huge
v = -1
do i = 1, nmols
if ( .not. connected(i) .and. mind(i) < d ) then
d = mind(i)
v = i
end if
end do
return
end
c ***************************************************************************
subroutine update_mind ( nmols, connected, ohd, mv, mind )
implicit none
integer ( kind = 4 ) nmols
logical ( kind = 4 ) connected(nmols)
integer ( kind = 4 ) i
integer ( kind = 4 ), parameter :: i4_huge = 2147483647
integer ( kind = 4 ) mind(nmols)
integer ( kind = 4 ) mv
integer ( kind = 4 ) ohd(nmols,nmols)
do i = 1, nmols
if ( .not. connected(i) ) then
c
if ( ohd(mv,i) < i4_huge ) then
if ( mind(mv) + ohd(mv,i) < mind(i) ) then
mind(i) = mind(mv) + ohd(mv,i)
end if
end if
end if
end do
return
end
c
I'm looking for a way/method to fit my response data (Image is shown below). So using f(t) = (square(2*pi*f*t)+1) to filter my raw data. However, cftool don't recognize this kind of function. So please help me thanks!
The function below might allow to fit the data. It is continuous, but not differentiable everywhere. The steps tend to fall to the right, while OPs data does not. This might require some extra work. Moreover, steps have to be equidistant, which, however, seems to be the case.
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
def f( x, a, b ): # test function (that would be the one to fit, actually + a shift of edge position)
return a + b * x**3
def f_step( x, l, func, args=None ):
y = ( x - l / 2. ) % l - l / 2.
y = y / l * 2.
p = np.floor( ( x-l/2.) / (l) ) + 1
centre = p * l
left = centre - l / 2.
right = centre + l / 2.
fL = func( left, *args )
fR = func( right, *args )
fC = func( centre, *args )
out = fC + sharp( y , fL - fC, fR - fC , 5 )
return out
def sharp( x, a, b , p, epsilon=1e-1 ):
out = a * ( 1. / abs( x + 1 + epsilon )**p - ( 2 + epsilon)**( -p ) ) / ( epsilon**( -p ) - ( 2 + epsilon )**( -p ) )
out += b * ( 1. /abs( x - 1 - epsilon )**p - ( 2 + epsilon)**( -p ) ) / ( epsilon**( -p ) - ( 2 + epsilon )**( -p ) )
return out
l=0.57
xList = np.linspace( -1, 1.75, 500 )
yList = [ f_step( x, l, f, args=(2, -.3 ) ) for x in xList ]
fig1 = plt.figure( 1 )
ax = fig1.add_subplot( 1, 1, 1 )
ax.plot( xList, yList )
ax.plot( xList, f(xList, 2,-.3) )
plt.show()
Looks like:
This question describe the gabor filter family and its application pretty well. Though, there is nothing described about the wavelength (spatial frequency) of the filter. The creation of gabor wavelets are done in the following for loop:
for v = 0 : 4
for u = 1 : 8
GW = GaborWavelet ( R, C, Kmax, f, u, v, Delt2 ); % Create the Gabor wavelets
figure( 2 );
subplot( 5, 8, v * 8 + u ),imshow ( real( GW ) ,[]); % Show the real part of Gabor wavelets
GW_ALL( v*8+u, :) = GW(:);
end
figure ( 3 );
subplot( 1, 5, v + 1 ),imshow ( abs( GW ),[]); % Show the magnitude of Gabor wavelets
end
I know that the second loop variable is the orientation with pi/8 intervals. Though, I don't know how the first loop variable is linked with the spatial frequency (wavelength) in this code and its function [pixels/cycle]. Can anyone help?
I found the answer finally. The GaborWavelet function is defined as follows:
function GW = GaborWavelet (R, C, Kmax, f, u, v, Delt2)
k = ( Kmax / ( f ^ v ) ) * exp( 1i * u * pi / 8 );% Wave Vector
kn2 = ( abs( k ) ) ^ 2;
GW = zeros ( R , C );
for m = -R/2 + 1 : R/2
for n = -C/2 + 1 : C/2
GW(m+R/2,n+C/2) = ( kn2 / Delt2 ) * exp( -0.5 * kn2 * ( m ^ 2 + n ^ 2 ) / Delt2) * ( exp( 1i * ( real( k ) * m + imag ( k ) * n ) ) - exp ( -0.5 * Delt2 ) );
end
end
The Kmax is the maximum frequency, f is the spacing factor and v is the resolution. The spacing factor f is usually considered as sqrt(2).
Based on this paper, k= 2*pi*f*exp(i*ϑ) and in the code Kmax=fmax*2*pi which is not described and is the key to find the wavelength of the filter. I also read this implementation and noticed that wavelength can easily be found using f = 1/lambda where lambda is wavelength of sinusoid.
So for example, if Kmax=pi/2 and v=0, so the k=Kmax*exp(1i*u*pi/8) and considering the above mentioned formula, lambda = 2*pi/Kmax = 4 [pixel/cycle].