Converting character string to integer - fortran

This is a follow up to my get_command_argument() question.
I'm reading a command line argument (arg) into a Fortran program. Then I want to store the value of arg as an integer. ichar() doesn't do the job.
This seems kind of basic, so clearly I'm doing something wrong. Any hints?
program test_get_command_argument
integer :: i,j
character(len=32) :: arg
i = 0
do
call get_command_argument(i,arg)
if (LEN_TRIM(arg) == 0) EXIT
write (*,*) trim(arg)
i = i + 1
end do
j = ichar(arg)
end program

You want to use the "internal files" capability.
You should have a statement like read(arg,*) j.
This will read the character variable arg as if it were a file
and store the result into j.

This isn't an answer but an extended comment:
That's a bizarre way to loop over the command line arguments. What's wrong with the straightforward and obvious
do i = 1, command_argument_count()
call get_command_argument(i,arg)
! do funky stuff
end do

Related

Fortran character(:), dimension(:) vs character, dimension(:,:)

I was trying to copy contents of a file to a string array and I couldn't manage to fully copy the file (it was only copying the first characters in every line). I feel like something is wrong with my syntax and its possible to do it with character, dimension(:,:) but it worked with character(:), dimension(:).
This doesn't work as expected:
character, allocatable :: list(:,:)
integer :: i, line_count, line_length
open(1, "input.txt", status="old", action="read")
line_count = count_file_lines(1) ! function that returns integer
line_length = longest_line_length(1) ! function that returns integer
allocate(list(line_count, line_length))
do i = 1, line_count
read(1, *) list(i,:)
end do
close(1)
This works as expected:
character(:), allocatable :: list(:)
integer :: i, line_count, line_length
open(1, "input.txt", status="old", action="read")
line_count = count_file_lines(1) ! function that returns integer
line_length = longest_line_length(1) ! function that returns integer
allocate(character(line_length) :: list(line_count))
do i = 1, line_count
read(1, *) list(i)
end do
close(1)
I've tried switching indexes in the first example and it still didn't work. I understand that the first example is a rank 2 character array but what is the array in the second example? Maybe they both are the same type of array and I got the indexing wrong for the first one. Can someone clarify this?
In the first example you have a 2D array of single characters, of character strings of size 1. In the other example you have a 1D array of longer character strings. See Difference between "character*10 :: a" and "character :: a(10)" for the difference.
The readstatement regards each of the character in the 2D array as a separate variable it tries to read. That is why it appears storing only the first character each time. The list-directed format * you are using is not good enough for reading a character array.
You can actually read a line to a character array, but you have to read it as an array and use the appropriate format
read(1, '(*(a))') str(i,:)
You are responsible to make sure that three are enough characters on each line of your file for your arrays.
You must also be careful when printing the content, which you do not show.
Be aware that using unit 1 for your files is poor form. Unit numbers below 10 are often pre-connected by the compiler to standard input, standard output, standard error and possibly other files.

How can I create a function in Fortran, that reads from file and works with it [duplicate]

This question already has answers here:
Passing character strings of different lengths to functions in Fortran
(2 answers)
Closed 2 years ago.
I have a bunch of files, which contain numbers in rows. I need to write a function, that
reads from file for the first time to find amount of elements in file;
allocates an array and reads numbers from file into array;
returns an array
My function gets a string - name of the file - as an input.
So, the function that I wrote is:
function arrays_proc(name) result(arr)
character(len=128), intent(in) :: name
integer :: i, tmp, ios
character(len=30) :: line
double precision, dimension(:), allocatable :: arr
open(unit=09, file=name, status='old', iostat=ios)
if ( ios /= 0) stop "error opening file"
tmp = 0
do
read(09, '(A)', iostat=ios) line
if (ios /= 0) exit
tmp = tmp + 1
end do
allocate(arr(tmp))
rewind(09)
do i=1, tmp
read(09, '(A)') arr(i)
end do
close(09)
return
end function arrays_proc
Then, in the main program I write
...
real(8), dimension(:), allocatable :: points, potent
points = arrays_proc(trim('carbon_mesh.txt'))
potent = arrays_proc(trim('carbon_pot.txt'))
...
When I run my program, I get instant "error opening file".
I assume the problem is with names of files or how I put them in my function.
Anyway, I hope someone can help me
When compiling your code with a minimal program, GFortran prints the following warnings:
a.f90:4:25:
4 | points = arrays_proc(trim('carbon_mesh.txt'))
| 1
Warning: Character length of actual argument shorter than of dummy argument ‘name’ (15/128) at (1)
a.f90:5:25:
5 | potent = arrays_proc(trim('carbon_pot.txt'))
| 1
Warning: Character length of actual argument shorter than of dummy argument ‘name’ (14/128) at (1)
Trying to print the value of name inside arrays_proc shows that it is filled with garbage. So, guided by the warnings, you can try to change the length of the name parameter to *, which allows a string of any length to be used as input.
With that change, the function manages to open the files.
See also: Passing character strings of different lengths to functions in Fortran

Read signed exponential

I am having trouble reading exponential from a text file using Fortran.
The entry in the text file looks like the following
0.02547163e+06-0.04601176e+01 0.02500000e+02 0.00000000e+00 0.00000000e+00 3
And the code that I am using looks like the following
read(iunit,'(ES20.8,ES20.8,ES20.8,ES20.8,ES20.8,I2)') dummy1, dummy2, Thermo_DB_Coeffs_LowT(iS,1:3),temp
The error I am getting is
Fortran runtime error: Bad value during floating point read
How can I read these values?
Well here is what I usually do when it is too painful to hand edit the file...
CHARACTER(LEN=256) :: Line
INTEGER, PARAMETER :: Start = 1
INTEGER :: Fin, Trailing_Int, I
DOUBLE, DIMENSION(6) :: Element
...
Ingest_All_Rows: DO WHILE(.TRUE.)
READ(...) Line ! Into a character-string
<if we get to the end of the file, then 'EXIT Ingest_All_Rows'>
Start =1
Single_Row_Ingest: DO I = 1, 6
Fin = SCAN(Line,'eE')+3 !or maybe it is 4?
IF(I ==6) Fin = LEN_TRIM(Line)
READ(Line(Start:Fin),*) Element(I) !fron the string(len-string) to the double.
Line = Line((Fin+1):)
IF(I ==6) Trailing_Int = Element(6)
ENDDO Single_Row_Ingest
<Here we shove the row's 5 elements into some array, and the trailing int somewhere>
ENDDO Ingest_All_Rows
You will have to fill in the blanks, but I find that SCAN and LEN_TRIM can be useful in these cases

Simple read function error

I imagine this is something silly I've missed but I've asked my whole class and noone can seem to work it out. Making a simple program calling in a subroutine and I'm having trouble with the do loop reading in the entries of the matrix.
program Householder_Program
use QR_Factorisation
use numeric_kinds
complex(dp), dimension(:,:), allocatable :: A, Q, R, V
integer :: i, j, n, m
print *, 'Enter how many rows in the matrix A'
read *, m
print *, 'Enter how many columns in the matrix A'
read *, n
allocate(A(m,n), Q(m,n), R(n,n), V(n,n))
do i = 1,m
do j = 1,n
Print *, 'Enter row', i, 'and column', j, 'of matrix A'
read *, A(i,j)
end do
end do
call Householder_Triangularization(A,V,R,n,m)
print *, R
end program
It will ask me for A(1,1) but when I type in a number it will not ask me for A(1,2), it will leave a blank line. When I try to put in a 2nd number it will error and say :
Enter row 1 and column 1 of matrix A
1
2
At line 22 of file HouseholderProgram.f90 (unit = 5, file = 'stdin')
Fortran runtime error: Bad repeat count in item 1 of list input
Your variable A is (an array) of type complex. This means that when you attempt to do the list-directed input of the element values you cannot just specify a single number. So, in your case the problem is not with the program but with the input.
From the Fortran 2008 standard, 10.10.3
When the next effective item is of type complex, the input form consists of a left parenthesis followed by an ordered pair of numeric input fields separated by a comma (if the decimal edit mode is POINT) or semicolon (if the decimal edit mode is COMMA), and followed by a right parenthesis.
Input, then, must be something like (1., 12.).
You are trying to read in complex numbers (A is complex)! As such, you should specify complex numbers to the code... Since you are providing just one integer, the program does not know what to do.
Providing (1,0) and (2,0) instead of 1 and 2 will do the trick.
In case the user input is always real, and you want to read it into a complex type array you can do something like this:
Print *, 'Enter row', i, 'and column', j, 'of matrix A'
read *, dummy
A(i,j)=dummy
where dummy is declared real. This will save the user from the need to key in the parenthesis required for complex numbers. ( The conversion to complex is automatic )

FFTW fortran 90: allocatable cut in half when N>20

Hi everyone and happy new year !
I'm trying to use the fftw library in a simple fortran 90 code (yes, an old fortran...).
This is a very simple code computing the FFT of vector in=1,2,..., N. I'm surprise by the fact that, for N<20, it works. For N >= 20, it does not work anymore. I guess I missed something important but can't figure out what... And was wondering if you could help me...
I compile my code with this command
ifort test.f90 -o test -lfftw3f
And the code is the following
program test
implicit none
include "fftw3.f"
integer, parameter :: fp =4
integer*8 :: N
double complex, allocatable, dimension (:) :: in, out, aux
integer*8 :: plan
integer*8 :: i, errflag
N=10
allocate(in(N), stat=errflag)
allocate(out(N), stat=errflag)
do i=1,N
in(i) = i
end do
call sfftw_plan_dft_1d(plan, N, in, out, -1, 0)
do i=1,N
print *, in(i)
end do
print *, "================================================"
do i=1,N
print *, out(i)
end do
call sfftw_execute_dft(plan, in, out)
call sfftw_destroy_plan(plan)
deallocate(in, out)
end program test
Surpringly (for me), the vector "in" is modified after the line
call sfftw_plan_dft_1d(plan, N, in, out, -1, 0)
Indeed, the vector is "cut in half" as soon as N>20, in the sense that:
in(i) = 0 if i < N/2
in(i) = i otherwise
However, with N =10 for example, the result seems to be good (same as the one obtained with scilab fft function).
I'm kind of lost and not totally familiar with fortran. Did I missed something important ?
Thank you so much in advance !
edit : whoups, bad copy/paste in the code...
Looking around for what your flags meant, I found this here
http://www.fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags
Important: the planner overwrites the input array during planning unless a saved plan (see Wisdom) is available for that problem, so you should initialize your input data after creating the plan. The only exceptions to this are the FFTW_ESTIMATE and FFTW_WISDOM_ONLY flags, as mentioned below.
Maybe try
call sfftw_plan_dft_1d(plan, N, in, out, -1, 0)
do i=1,N
in(i) = i
end do
Or I may be misreading something completely out of contect, but I guess it's worth a try :)