Results of parallel calculations on Fortran + mpi are dependent on being/luck of unsignificant commands in code - multiprocessing

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.

Related

Is there room to further optimize the stochastic_rk Fortran 90 code?

I need to use a Fortran code to solve stochastic differential equation (SDE).
I looked at the famous Fortran code website by Burkardt,
https://people.math.sc.edu/Burkardt/f_src/stochastic_rk/stochastic_rk.html
I particular looked at the rk4_ti_step subroutine in stochastic_rk.f90 code,
https://people.math.sc.edu/Burkardt/f_src/stochastic_rk/stochastic_rk.f90
My optimized version is below,
subroutine rk4_ti_step_mod ( x, t, h, q, fi, gi, seed, xstar )
use random
implicit none
real ( kind = 8 ), external :: fi
real ( kind = 8 ), external :: gi
real ( kind = 8 ) h
real ( kind = 8 ) k1
real ( kind = 8 ) k2
real ( kind = 8 ) k3
real ( kind = 8 ) k4
real ( kind = 8 ) q
real ( kind = 8 ) r8_normal_01
integer ( kind = 4 ) seed
real ( kind = 8 ) t
real ( kind = 8 ) t1
real ( kind = 8 ) t2
real ( kind = 8 ) t3
real ( kind = 8 ) t4
real ( kind = 8 ) w1
real ( kind = 8 ) w2
real ( kind = 8 ) w3
real ( kind = 8 ) w4
real ( kind = 8 ) x
real ( kind = 8 ) x1
real ( kind = 8 ) x2
real ( kind = 8 ) x3
real ( kind = 8 ) x4
real ( kind = 8 ) xstar
real ( kind = 8 ) :: qoh
real ( kind = 8 ) :: normal(4)
real ( kind = 8 ), parameter :: a21 = 2.71644396264860D+00 &
,a31 = - 6.95653259006152D+00 &
,a32 = 0.78313689457981D+00 &
,a41 = 0.0D+00 &
,a42 = 0.48257353309214D+00 &
,a43 = 0.26171080165848D+00 &
,a51 = 0.47012396888046D+00 &
,a52 = 0.36597075368373D+00 &
,a53 = 0.08906615686702D+00 &
,a54 = 0.07483912056879D+00 &
,q1 = 2.12709852335625D+00 &
,q2 = 2.73245878238737D+00 &
,q3 = 11.22760917474960D+00 &
,q4 = 13.36199560336697D+00
real ( kind = 8 ), parameter, dimension(4) :: qarray = [ 2.12709852335625D+00 &
,2.73245878238737D+00 &
,11.22760917474960D+00 &
,13.36199560336697D+00 ]
real ( kind = 8 ) :: warray(4)
integer (kind = 4) :: i
qoh = q / h
normal = gaussian(4)
do i =1,4
warray(i) = normal(i)*sqrt(qarray(i)*qoh)
enddo
t1 = t
x1 = x
k1 = h * ( fi ( x1 ) + gi ( x1 ) * warray(1) )
t2 = t1 + a21 * h
x2 = x1 + a21 * k1
k2 = h * ( fi ( x2 ) + gi ( x2 ) * warray(2) )
t3 = t1 + ( a31 + a32 )* h
x3 = x1 + a31 * k1 + a32 * k2
k3 = h * ( fi ( x3 ) + gi ( x3 ) * warray(3) )
t4 = t1 + ( a41 + a42 + a43 ) * h
x4 = x1 + a41 * k1 + a42 * k2
k4 = h * ( fi ( x4 ) + gi ( x4 ) * warray(4) )
xstar = x1 + a51 * k1 + a52 * k2 + a53 * k3 + a54 * k4
return
end
Note that I use my module of random number, and gaussian is my random number function, this part does not matter.
I just wonder,
Can anyone give some suggestions as to can the code be further optimized?
Does anyone know what is the best/fastest SDE Fortran subroutine? Or what algorithm is the best?
Thank you very much!
The interdependence of x and c means you can't turn as much into linear algebra as I first thought, but I'd still expect some speedup by grouping everything into appropriate arrays as:
subroutine rk4_ti_step_mod ( x, t, h, q, fi, gi, seed, xstar )
use random
implicit none
integer, parameter :: dp = selected_real_kind(15,307)
integer, parameter :: ip = selected_int_kind(9)
real(dp), intent(in) :: x
real(dp), intent(in) :: t
real(dp), intent(in) :: h
real(dp), intent(in) :: q
real(dp), external :: fi
real(dp), external :: gi
integer(ip), intent(in) :: seed
real(dp), intent(out) :: xstar
real(dp), parameter :: as(4,5) = reshape([ &
& 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, &
& 2.71644396264860_dp, 0.0_dp, 0.0_dp, 0.0_dp, &
& -6.95653259006152_dp, 0.78313689457981_dp, 0.0_dp, 0.0_dp, &
& 0.0_dp, 0.48257353309214_dp, 0.26171080165848_dp, 0.0_dp, &
& 0.47012396888046_dp, 0.36597075368373_dp, 0.08906615686702_dp, 0.07483912056879_dp &
& ], [4,5])
real(dp), parameter :: qs(4) = [ &
& 2.12709852335625_dp, &
& 2.73245878238737_dp, &
& 11.22760917474960_dp, &
& 13.36199560336697_dp ]
real(dp) :: ks(4)
real(dp) :: r8_normal_01
real(dp) :: ts(4)
real(dp) :: ws(4)
real(dp) :: xs(4)
real(dp) :: normal(4)
real(dp) :: warray(4)
normal = gaussian(4)
warray = normal*sqrt(qs)*sqrt(q/h)
do i=1,4
ts(i) = t + sum(as(:i-1,i)) * h
xs(i) = x + dot_product(as(:i-1,i), ks(:i-1))
ks(i) = h * (fi(xs(i)) + gi(xs(i))*warray(i))
enddo
xstar = x + dot_product(as(:,5), ks)
end subroutine
although it's difficult to tell without knowing anything about fi and gi.
Also note you don't seem to be using the t1 to t4 variables.

How to convert rotation matrix to quaternion

Can I convert rotation matrix to quaternion?
I know how to convert quaternion to rotation matrix but I can't find way to do opposite that.
I can show you the code how to convert quaternion to rotation matrix as bellow.
Example(C++): Quaterniond quat; MatrixXd t; t = quat.matrix();
I want to know way to convert rotation matrix to quaternion like this.
A numerically stable algorithm for converting a direction cosine matrix D into a quaternion q is as follows:
T = D(1,1) + D(2,2) + D(3,3)
M = max( D(1,1), D(2,2), D(3,3), T )
qmax = (1/2) * sqrt( 1 – T + 2*M )
if( M == D(1,1) )
qx = qmax
qy = ( D(1,2) + D(2,1) ) / ( 4*qmax )
qz = ( D(1,3) + D(3,1) ) / ( 4*qmax )
qw = ±( D(3,2) - D(2,3) ) / ( 4*qmax )
elseif( M == D(2,2) )
qx = ( D(1,2) + D(2,1) ) / ( 4*qmax )
qy = qmax
qz = ( D(2,3) + D(3,2) ) / ( 4*qmax )
qw = ±( D(1,3) - D(3,1) ) / ( 4*qmax )
elseif( M == D(3,3) )
qx = ( D(1,3) + D(3,1) ) / ( 4*qmax )
qy = ( D(2,3) + D(3,2) ) / ( 4*qmax )
qz = qmax
qw = ±( D(1,3) - D(3,1) ) / ( 4*qmax )
else
qx = ±( D(3,2) - D(2,3) ) / ( 4*qmax )
qy = ±( D(1,3) - D(3,1) ) / ( 4*qmax )
qz = ±( D(2,1) - D(1,2) ) / ( 4*qmax )
qw = qmax
endif
Note that there is a sign ambiguity inherent in quaternions. The algorithm above arbitrarily picks the sign of the largest element qmax to be positive, but it is equally valid to pick this sign as negative (i.e., essentially flipping all of the signs of the result). It is up to the user to determine which is the more appropriate selection based on the application.
The ± selection is made based on the quaternion convention you are using:
Choose + for Hamilton Left Chain Convention or JPL Right Chain Convention
Choose - for Hamilton Right Chain Convention or JPL Left Chain Convention
Hamilton Convention means the quaternion elements i, j, k behave in a right-handed manner for multiplication (like cross products):
i * j = k , j * k = i , k * i = j
JPL Convention means the quaternion elements i, j, k behave in a left-handed manner for multiplication (negative of cross products):
i * j = -k , j * k = -i , k * i = -j
Right Chain means the quaternion rotation operation on a vector has the unmodified quaternion on the right side:
D * v1 = v2 = q^-1 * v1 * q
Left Chain means the quaternion rotation operation on a vector has the unmodified quaternion on the left side:
D * v1 = v2 = q * v1 * q^-1
For completeness, here is the algorithm for the other direction, converting a quaternion to a direction cosine matrix:
D = (qw^2 - dot(qv,qv))*I3 + 2*qv*qv^T ± 2*qw*Skew(qv)
where ^T means transpose (for outer product in that term) and
qv = [qx]
[qy]
[qz]
I3 = [1 0 0]
[0 1 0]
[0 0 1]
Skew(qv) = [ 0 -qz qy]
[ qz 0 -qx]
[-qy qx 0]

How to find the minimum path with the highest sum of edge weights?

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

How to fit response plot using square wave

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:

How to calculate the Spatial frequency in Gabor filter?

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

Resources