Runtime error claiming a negative or zero argument to the logarithm function in Box-Mueller algorithm - debugging

The following code is a part of a Fortran 90 program that I wrote in Plato IDE:
It is just the Box-Mueller algorithm to generate Gaussian random numbers.
Program brownstep2_single_stage
Integer:: i,j,m,n,countsucc!,a
Real:: dt,D,epsa,r1,r2,w,fptsum,fptdef1,fptdef2
Real,Dimension(0:100002) :: fx !gt
!T=1000.0 and n*dt=T
dt=0.001
m=100000
n=100000
D=1.0
!a=7
w=2
epsa=0.00001
fx(0)=6.0
!gt(0)=0
fptsum=0
countsucc=0
Call random_seed()
Do i=0,m
!Call random_seed(a)
Do j=0,n
Do while (w>=1.0.and.w<0.0)
Call random_number(r1)
Call random_number(r2)
!r=rand()
r1=2.0*r1-1
r2=2.0*r2-1
w=r1*r1+r2*r2
End do
w=sqrt((-2.0*log(w))/w)
r1=r1*w
r2=r2*w
If(mod(j,2)==0) then
w=r1
Else if(mod(j,2)==1) then
w=r2
End if
fx(j+1)=fx(j)+w*sqrt(2.0*D*dt)
If(fx(j+1)<epsa) then
fptsum=fptsum+(j+1)*dt
countsucc=countsucc+1
exit
End if
print *,i,j
End do
End do
fptdef1=fptsum/m
fptdef2=fptsum/countsucc
print *,'The value of fpt by 1st definition is:',fptdef1
print *,'The value of fpt by 2nd definition is:',fptdef2
print *,'The number of successful events is:',countsucc
print *,'The total number of events is:',m
End program brownstep2_single_stage
During compilation, it shows no error, but when run, it shows the following runtime error, claiming a negative or zero argument to the logarithm function.
Runtime error from program:e:\my files\sample2brownstep_gauss.exe
Run-time Error
Error: Negative or zero argument to logarithm routine
BROWNSTEP2_SINGLE_STAGE - in file sample2brownstep_gauss.f90 at line 31 [+02cc]
What should I do to avoid this?

The changed code above still has problems. w is still not set before the do while loop is reached for the first time and w is used in the condition. Use an 'infinite' do loop with an exit statement. This ensures that one attempt at w is always attempted. This would be better:
do
Call random_number(r1)
Call random_number(r2)
r1=2.0*r1-1
r2=2.0*r2-1
w=r1*r1+r2*r2
if (w .lt. 1.0) exit
End do
w=sqrt((-2.0*log(w))/w)
r1=r1*w
r2=r2*w

Related

Myhdl: assigning a bitslice to a signed variable fails with negative values

The code added fails with a ValueError and i have no idea whats going wrong. Here is what i want to do:
In my fpga i receive data via spi.
Data is a bipolar signal (in the sense of a measurement signal) arriving in a 16 bit register rxdata.
the task is to interpret this signal as being signed and only the upper 12 bits (including sign) are needed. The variable bipolar is therefore 12bit wide and signed i.e. declared like in the code. Then i assign:
bipolar.next=rxdata[:4].signed()
my problem is, that the assignment of the 12bit slice fails as soon as data becomes negative (i.e most significant bit becomes 1).
With data 0x8fff for instance at runtime i get:
'ValueError: intbv value 2303 >= maximum 2048'
I don't expect this, as both sides are declared signed and data fits into the variable bipolar.
Is there another way to do this?
(by the way: bipolar[:].next=rxdata[:4].signed() i get 0 as a result which i would not expect either)
#testcase.py sk 09.12.2020
#assign a slice to a signed signal (bipolar) fails at runtime with negative numbers
from myhdl import *
nspi=16
n=12
tend=1e-6
#block
def testcase():
CLK = Signal(bool(0))
RESET = ResetSignal(1,active = 0, isasync=True)
bipolar=Signal(intbv(0,min=-2**(n-1),max=2**(n-1)))
rxdata = Signal(intbv(0)[nspi:0]) #received data is bipolar, transferred via spi into rxdata
''' Clock driver 16MHz'''
#always(delay(31))
def driver():
CLK.next = not CLK
#instance
def init():
rxdata.next=0x8fff #0x7fff i.e. positive passes, 0x8fff i.e negative fails runtime check
yield delay(100)
#always_seq(CLK.negedge,reset=RESET)
def assign():
#bipolar[:].next=rxdata[:(nspi-n)].signed() #this passes - but result is 0! (unexpected for me)
bipolar.next=rxdata[:(nspi-n)].signed() #this fails with negative numbers (unexpected for me)
print(bipolar, 'bipolar=', int(str(bipolar),16))
return instances()
tc = testcase()
tc.run_sim(tend*1e9)
print('Simulated to tend='+str(tend))
Just found the way to do it: use shadow signals! i.e use round brackets () instead of square ..[]
#testcase.py sk 12.12.2020
#assign a slice to a signed signal (bipolar) fails at runtime with negative numbers
#-> use shadow signals instead! #bipolar[:].next=rxdata[:(nspi-n)].signed() #this passes - but result is 0! (unexpected for me)
from myhdl import *
nspi=16
n=12
tend=1e-6
#block
def testcase():
CLK = Signal(bool(0))
RESET = ResetSignal(1,active = 0, isasync=True)
bipolar=Signal(intbv(0,min=-2**(n-1),max=2**(n-1)))
#rxdata = Signal(intbv(0)[nspi:0]) #received data is bipolar, transferred via spi into rxdata
rxdata = Signal(intbv(0,min=0,max=2**nspi))
''' Clock driver 16MHz'''
#always(delay(31))
def driver():
CLK.next = not CLK
#instance
def init():
rxdata.next=0xffff #0x7fff i.e. positive passes, 0x8fff i.e negative fails runtime check when not using shadow
yield delay(100)
#always_seq(CLK.negedge,reset=RESET)
def assign():
#bipolar.next=rxdata[:(nspi-n)].signed() #this fails in runtime check -> number too big
#bipolar[:].next=rxdata[:(nspi-n)].signed() #this passes - but result is 0! (unexpected for me)
bipolar.next=rxdata(nspi,(nspi-n)).signed() #this is the way: use shadow signal !
print(bipolar, 'bipolar=', int(str(bipolar),16))
return instances()
tc = testcase()
tc.run_sim(tend*1e9)
print('Simulated to tend='+str(tend))

Why error() works faster then assert() in Lua?

Assertion of condition is well known way to design application in strategic way. You could be completely sure that your code will work correctly a day after release, but also when other dev in your team will change this code.
There are 2 common ways to put assertion in Lua code:
assert(1 > 0, "Assert that math works")
if 1 <= 0 then
error("Assert that math doesn't work")
end
I would expect this thing similar from performance point of view.
Consider it only matter of style. But it happens to be not true.
assert works longer on my machine:
function with_assert()
for i=1,100000 do
assert(1 < 0, 'Assert')
end
end
function with_error()
for i=1,100000 do
if 1 > 0 then
error('Error')
end
end
end
local t = os.clock()
pcall(with_assert)
print(os.clock() - t)
t = os.clock()
pcall(with_error)
print(os.clock() - t)
>> 3.1999999999999e-05
>> 1.5e-05
Why does it happen?
Look at the source code of assert and error: assert does some work and then calls error.
But the loop in your code serves no purpose: throwing an error during the first iteration means that the rest of the iterations don't run. Perhaps you meant to put the loop around the pcalls as below. Then you'll find hardly any difference between the times.
function with_assert()
assert(1 < 0, 'Assert')
end
function with_error()
if 1 > 0 then
error('Error')
end
end
function test(f)
local t = os.clock()
for i=1,100000 do
pcall(f)
end
print(os.clock() - t)
end
test(with_assert)
test(with_error)

Scattering matrix column by column in MPI using Fortran and contiguous datatype

I'm trying to generate a matrix full of random numbers, of dimensions (mysize)x(Np), where Np is a given number (say,5). Mysize comes from the number of processes. And then each processor should take its own column, of size 1xNp.
My first idea was to create a vector data type but then I realized this can be done by using the contiguous data type. The code runs with no errors, but it prints only some of the numbers that were supposed to be there. I'm quite sure the problem lies on the indicators (type_column, MPI_REAL, etc.) and how should they actually be but I can't figure this out. Anyone care to help?
The code:
program main
use mpi
integer :: ierr,myrank,mysize
integer :: Np=5, type_column
integer*8, external :: seedgen
real*8, dimension(:,:), allocatable :: x_init
real*8, dimension(:), allocatable :: block_x
character(4) :: rank
integer, dimension(1) :: new_seed
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD,mysize,ierr)
allocate(block_x(0:Np-1))
if (myrank==0) then
allocate(x_init(0:Np-1,0:mysize-1))
new_seed = seedgen(myrank)
write(*,*) new_seed !This is to check if the seed changes each time
call random_seed(put=new_seed)
call random_number(x_init)
open(unit=1111, file='./x_tot.txt')
write(1111,*) x_init
close(1111) !Up to this point, everything works
end if
call MPI_TYPE_CONTIGUOUS(Np,MPI_REAL,type_column,ierr)
call MPI_TYPE_COMMIT(type_column,ierr)
call MPI_SCATTER(x_init(:,myrank),Np,MPI_REAL,block_x,Np,type_column,0,MPI_COMM_WORLD,ierr)
write(rank,'(I4)') myrank
write(*,*) 'I, process ',myrank,' received ', block_x(0:Np-1)
open(unit=myrank, file='./x_teste_'//trim(adjustl(rank))//'.txt')
write(myrank,*) block_x
close(myrank)
call MPI_TYPE_FREE(type_column,ierr)
call MPI_FINALIZE(ierr)
end program main
!!! You may ignore what is down below, just a function to generate random seeds.
function seedgen(myrank)
use iso_fortran_env
implicit none
integer(kind=int64) :: seedgen
integer, intent(IN) :: myrank
integer :: s
call system_clock(s)
seedgen = abs( mod((s*181)*((myrank-83)*359), 104729) )
end function seedgen
The output (after running with 3 processors, thus mysize=3)
I, process 0 received 0.247272870046176
0.386432141459887 8.816221414742263E-316 0.000000000000000E+000
0.000000000000000E+000
I, process 1 received 2.737792569698344E-008
I, process 2 received 5.231628354959370E-002
0.454932876242927 3.330771999738651E-315 0.000000000000000E+000
0.000000000000000E+000
3.352416881721526E+270 5.298272496856962E-315 0.000000000000000E+000
0.000000000000000E+000
The matrix x_tot:
0.247272870046176 0.386432141459887 0.473788032900533
0.239586263133600 0.851724848335892 5.231628354959370E-002
0.454932876242927 0.702720716936168 0.559915585253771
0.605745282251549 0.253298270763062 0.809867899324171
0.590174190311136 0.125210425650182 8.138975171285148E-002
So you can see that some numbers are the good ones, the rest is garbage.
Using MPI_DOUBLE as suggested above and changing the writing as below worked fine. Thanks again
open(unit=myrank, file='./x_teste_'//trim(adjustl(rank))//'.txt')
do i=0,Np-1
write(myrank,*) block_x(i)
end do
close(myrank)

Why do I need to run this function twice to get the expected output?

In system-verilog i have a random number generator like this:
task set_rand_value(output bit [7:0] rand_frms, output bit [13:0] rand_bcnt);
begin
bit [7:0] rand_num;
// Set the random value between 2 and 254
rand_num=$urandom_range(254,2);
rand_bcnt=$urandom_range(2047,1);
// Check to ensure number is even
if ((rand_num/2)*2 != rand_num) begin
rand_num=rand_num+1;
$display("Generated %d frames. 8'h%h", rand_num, rand_num);
$display("Packets generated with 0x%4h bytes.", rand_bcnt);
end
// Set the random frame number
else begin
rand_frms = rand_num;
$display("Generated %d frames. 8'h%h", rand_num, rand_num);
$display("Packets generated with 0x%4h bytes.", rand_bcnt);
end
end
endtask // set_rand_value
For some reason the first time I run this (and the third and fifth... etc) it returns a value of zero even though a number is properly generated.
I am calling it like this:
bit [ 7:0] num_frms;
bit [13:0] size_val;
// Generate random values
set_rand_value(num_frms, size_val); // Run twice to correct initial write error
$display("Error correction for packets sent: 0x%h", num_frms);
set_rand_value(num_frms, size_val);
$display("The number of packets being sent: 0x%h", num_frms);
Which gives me this output:
Generated 214 frames. 8'hd6
Packets generated with 0x05b2 bytes.
Error correction for packets sent: 0x00
Generated 252 frames. 8'hfc
Packets generated with 0x011f bytes.
The number of packets being sent: 0xfc
0x80fc011f // Expected number
I have tried quite a few things to correct it but for some reason the only way i can get it to behave the way i expect it to is to just run it twice every time i need to use it.
You only set num_frms if the random number is even. Why not just do
function void set_rand_value(output bit [7:0] rand_frms, output bit [13:0] rand_bcnt);
begin
// Set the random value between 2 and 254
rand_frms=$urandom*2;
rand_bcnt=$urandom_range(2047,1);
endfunction
P.S Only use tasks for routines that may block.
The reason why the code above did not work was you were not assigning rand_frms = rand_num; in the first half of the if condition . So only for 50% of the times read_frm would have a value in it. [ 50 % just been approximate ] .

Getting fortran runtime error: end of file

I have recently learned how to work with basic files in Fortran
and I assumed it was as simple as:
open(unit=10,file="data.dat")
read(10,*) some_variable, somevar2
close(10)
So I can't understand why this function I wrote is not working.
It compiles fine but when I run it it prints:
fortran runtime error:end of file
Code:
Function Load_Names()
character(len=30) :: Staff_Name(65)
integer :: i = 1
open(unit=10, file="Staff_Names.txt")
do while(i < 65)
read(10,*) Staff_Name(i)
print*, Staff_Name(i)
i = i + 1
end do
close(10)
end Function Load_Names
I am using Fortran 2008 with gfortran.
A common reason for the error you report is that the program doesn't find the file it is trying to open. Sometimes your assumptions about the directory in which the program looks for files at run-time will be wrong.
Try:
using the err= option in the open statement to write code to deal gracefully with a missing file; without this the program crashes, as you have observed;
or
using the inquire statement to figure out whether the file exists where your program is looking for it.
You can check when a file has ended. It is done with the option IOSTAT for read statement.
Try:
Function Load_Names()
character(len=30) :: Staff_Name(65)
integer :: i = 1
integer :: iostat
open(unit=10, file="Staff_Names.txt")
do while(i < 65)
read(10,*, IOSTAT=iostat) Staff_Name(i)
if( iostat < 0 )then
write(6,'(A)') 'Warning: File containts less than 65 entries'
exit
else if( iostat > 0 )then
write(6,'(A)') 'Error: error reading file'
stop
end if
print*, Staff_Name(i)
i = i + 1
end do
close(10)
end Function Load_Names
Using Fortran 2003 standard, one can do the following to check if the end of file is reached:
use :: iso_fortran_env
character(len=1024) :: line
integer :: u1,stat
open (newunit=u1,action='read',file='input.dat',status='old')
ef: do
read(u1,'A',iostat=stat) line
if (stat == iostat_end) exit ef ! end of file
...
end do ef
close(u1)
Thanks for all your help i did fix the code:
Function Load_Names(Staff_Name(65))!Loads Staff Names
character(len=30) :: Staff_Name(65)
integer :: i = 1
open(unit=10, file="Staff_Names.txt", status='old', action='read')!opens file for reading
do while(i < 66)!Sets Set_Name() equal to the file one string at a time
read(10,*,end=100) Staff_Name(i)
i = i + 1
end do
100 close(10)!closes file
return!returns Value
end Function Load_Names
I needed to change read(10,*) to read(10,*,END=100)
so it knew what to do when it came to the end the file
as it was in a loop I assume.
Then your problem was that your file was a row vector, and it was likely
giving you this error immediately after reading the first element, as #M.S.B. was suggesting.
If you have a file with a NxM matrix and you read it in this way (F77):
DO i=1,N
DO j=1,M
READ(UNIT,*) Matrix(i,j)
ENDDO
ENDDO
it will load the first column of your file in the first row of your matrix and will give you an error as soon as it reaches the end of the file's first column, because the loop enforces it to read further lines and there are no more lines (if N<M when j=N+1 for example). To read the different columns you should use an implicit loop, which is why your solution worked:
DO i=1,N
READ(UNIT,*) (Matrix(i,j), j=1,M)
ENDDO
I am using GNU Fortran 5.4.0 on the Ubuntu system 16.04. Please check your file if it is the right one you are looking for, because sometimes files of the same name are confusing, and maybe one of them is blank. As you may check the file path if it is in the same working directory.

Resources