Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Parsing float 32 value from command line fails unless extra code is present

bluequartz
Beginner
432 Views

I have the following subroutine:

recursive subroutine GetVoltage(cell, rlp, verbose)
!DEC$ ATTRIBUTES DLLEXPORT :: GetVoltage
 
use io
 
IMPLICIT NONE
 
type(unitcell),pointer :: cell
type(gnode),INTENT(INOUT) :: rlp
logical,INTENT(IN),OPTIONAL :: verbose
real(kind=sgl) :: io_real(1)
 
call ReadValue('Enter the microscope accelerating voltage [kV, R] : ', io_real, 1)
cell%voltage = dble(io_real(1))
call CalcWaveLength(cell,rlp,verbose=.TRUE.)
end subroutine

 

and when that code hits, what ever number I enter on the command prompt (200.0 in my case) the cell%voltage value is 0.0. Now if I change the subroutine slight to put in the following code:

recursive subroutine GetVoltage(cell, rlp, verbose)
!DEC$ ATTRIBUTES DLLEXPORT :: GetVoltage
 
use io
 
IMPLICIT NONE
 
type(unitcell),pointer :: cell
type(gnode),INTENT(INOUT) :: rlp
logical,INTENT(IN),OPTIONAL :: verbose
real(kind=sgl) :: io_real(1)
 
call ReadValue('Enter the microscope accelerating voltage [kV, R] : ', io_real, 1)
cell%voltage = dble(io_real(1))
 
if (present(verbose)) then
if (verbose) then
write (*,*) 'cell%voltage : ', cell%voltage
end if
end if
call CalcWaveLength(cell,rlp,verbose=.TRUE.)
end subroutine

 

The the "200.0" value is parsed correctly. This is with Version 17 update 6 on VS2015 on Windows 10. I have not tried version 18 yet. Anybody have any ideas on why this might be happening?

 

Thanks

Mike Jackson

 

0 Kudos
4 Replies
Steve_Lionel
Honored Contributor III
432 Views

Since you haven't shown the procedure ReadValue and don't tell us at what point you notice the value is wrong, it's impossible to even guess as to what the issue might be.

Please step back a moment and come up with a small, self-contained example that we can build and run to reproduce the problem. It is a waste of everyone's time to go speculating based on no information.

The only thing I can comment on is that your use of OPTIONAL arguments requires that an explicit interface be visible to the caller. Given that you make the "verbose" argument optional in GetVoltage, I assume it is also optional in CalcWaveLength, but I see no evidence of an explicit interface.

0 Kudos
bluequartz
Beginner
432 Views

https://github.com/marcdegraef/EMsoft/blob/develop/Source/EMsoftLib/diffraction.f90

GetVoltage is at line 186.

CalcWageLength is at line 231

https://github.com/marcdegraef/EMsoft/blob/develop/Source/EMsoftLib/io.f90

ReadValue is in there somewhere (I am not familiar with how overloading works in fortran)

We first noticed the value was wrong inside of CaclWaveLength because the value for temp2 was 0.0 which it should not be based on other inputs. My collaborator uses GFortran on macOS and Linux and on those systems the code works just fine. On my Windows system we noticed that the wrong values were being calculated. I tracked through the code and found the point where the value was being read from the command line. Since I can not get Visual Studio to launch into a debugger for this code base I stepped back 20 years and used a  "write(*,*)"cell%voltage: ",cell%voltage" code line just after it was read from the command line. Low and behold now it works. Comment out the "write(*,*)" line and not it does not work. Oddly we get the correct value. If I take that line out of the GetVoltage subroutine and put that same line into the CalcWaveLength subroutine instead then the cell%voltage shows as 0.0 even though I type in 200.0 on the command line. So without a working debugger this is a bit difficult to figure out. All I _did_ figure out is that if I put in some sort of "write(*,*)...." statement then the program would start working. It is almost as if adding those lines causes a slightly different bit of assembly to be generated that effects the parsing/storage of the voltage variable?

I have tried pulling out a minimum number of the subroutines to stick into a small program and of course it works just fine. Is there an object file I can post for people to take a look at? I can compile with and without the "if(verbose)" stuff and maybe that will see a difference?

here is the output when it works correctly:

C:\Users\mjackson\Workspace\EMsoftPrivate-Build\Release\Bin>EMxtalinfo.exe

  Enter xtal file name : Si.xtal
 Enter the microscope accelerating voltage [kV, R] : 200.0
 cPlank      :   6.626069570000000E-034
 cRestmass   :   9.109382910000000E-031
 cCharge     :   1.602176565000000E-019
 cLight      :    299792458.000000
 temp1       :    1.22642593849536
 temp2       :   0.195695126933142
 voltage     :    200.000000000000
 mRelcor     :    1.39139025386628
 mPsihat     :    239139.025386628

Here is the output when it does not work:

C:\Users\mjackson\Workspace\EMsoftPrivate-Build\Debug>cd Bin && EMxtalinfo.exe

  Enter xtal file name : Si.xtal

 Enter the microscope accelerating voltage [kV, R] : 200.0
 cPlank      :   6.626069570000000E-034
 cRestmass   :   9.109382910000000E-031
 cCharge     :   1.602176565000000E-019
 cLight      :    299792458.000000
 temp1       :    1.22642593849536
 temp2       :   0.000000000000000E+000
 voltage     :   0.000000000000000E+000
 mRelcor     :    1.00000000000000
 mPsihat     :   0.000000000000000E+000

 

I hope this provides more information. I'm a developer, but a long time C++ developer. I only have to work in Fortran in passing when things like this pop up so my Fortran skills are "new". I do understand the value of a small reproducible test case but I there are so many moving parts in this project I have no idea where to start.

Just looking for ideas. Anything from "update your compiler", to " you are smashing the stack" somewhere.

Thanks

Mike Jackson

0 Kudos
Steve_Lionel
Honored Contributor III
432 Views

Thanks for the code.

One interesting thing I see is that in GetVoltage and in CalcWaveLength, cell is a pointer. This will require that some other part of the code has allocated or pointer-assigned cell before calling GetVoltage. I don't see that part of the code.

The "fix" you checked in isn't a fix, but might be a workaround that shifts where things are allocated. I would be interested to see what the value of io_real(1) is after the call to ReadValue.

ReadValue is fairly straightforward, using list-directed READ. What exactly are you typing in at the prompt? Add:

WRITE (*,*) io_real(1)

after the call to ReadValue and show us the console log with the prompt, your input and the output.

Please also build this with the /check option enabled.

0 Kudos
mecej4
Honored Contributor III
432 Views

Steve Lionel (Ret.) wrote:
 One interesting thing I see is that in GetVoltage and in CalcWaveLength, cell is a pointer. This will require that some other part of the code has allocated or pointer-assigned cell before calling GetVoltage. I don't see that part of the code.

See https://github.com/marcdegraef/EMsoft/blob/develop/Source/Utilities/EMxtalinfo.f90. Lines 117 and 118 nullify and allocate the variable cell.

I suspect one of the following: (i) some subroutine has been called with an incorrect interface,  (ii) an uninitialized variable has been used or (iii) an array has its bounds exceeded. Without a compact and complete reproducer, probably little progress can be made.

BlueQuartz wrote:
Is there an object file I can post for people to take a look at? I can compile with and without the "if(verbose)" stuff and maybe that will see a difference?
We will see a difference in the object code, but it will probably not tell us much. Looking at local differences in OBJ files does not seem appropriate. Instead, follow Steve's recommendations, compile with /check, etc., and run. When something as mundane as reading a real number from the console is not working correctly, some memory corruption is probably occurring.

BlueQuartz wrote:
Since I can not get Visual Studio to launch into a debugger for this code base...

Why not? Please explain.

 

 

0 Kudos
Reply