I have a string including the names of the variables I want read, and I would like to pass this string to the read function. This could allow me to change the name of the variables I read just changing the vector with the names of the variables.
An example could be:
PROGRAM test
implicit none
integer :: no, age
character(len=20) :: myname, vars
vars='no, myname, age'
read(*, '(i4,a20,i4)') vars
print*, no, myname, age
END PROGRAM test
Is this possible?
You can look into "NAMELIST" I/O, which maybe does what you're after. Often, namelist IO has various issues, and people often resort to writing their own custom IO routines anyway. But if it's enough for what you want, it's quite easy to use. E.g.
program nmltest
implicit none
real :: x
integer :: y
namelist /mynml/ x, y
x = 4711
y = 42
write(*, mynml)
end program nmltest
Fortran is a compiled language. It would be hard (to impossible) for the READ statement to extract variable addresses from the string list at run-time. That's why, as noted by janneb, Fortran provides the NAMELIST operator which became part of the language standard since Fortran 90 (some Fortran 77 also had support for namelists but it was non-standard and no compatibility was guaranteed between compilers). It is used like that:
...
NAMELIST /vars/ no, age, myname
...
READ(*, NML=vars)
...
The input should be something like this:
! Input can contain comments starting with exclamation marks
! And blank lines too
&vars
no = 12,
myname = 'sometext'/
Formatted input/output is not possible with NAMELIST though.
Related
I want to create a dynamic variable name using Fortran.
The variable name will be obtained by concatenating a string and another string/integer. Then I want to use this variable name to store a value or another variable.
e.g.
! assign values to 2 variables
my_string = h
my_integer = 1
! perform concatenation resulting in the dynamic variable name, h1
! Set the value of variable h1 to another integer value
h1 = 5
I fear that you will not be able to do this. Fortran requires that variables have names and types at compile time. You (or other SOers) may come up with some kludge to simulate what you want, but it will be a kludge.
Why do you want to do this in Fortran ? There are plenty of languages around which do permit this sort of variable declaration.
EDIT
Well, I thought about it some more, and here's a kludge, unfinished. First a UDT for 'dynamic' variables:
type dynamic_var
character(len=:), allocatable :: label
class(*), allocatable :: value
end type
declare some space for such variables:
type(dynamic_var), dimension(:), allocatable :: run_time_vars
and, working with your original data
allocate(run_time_vars(10)) ! No error checking, reallocate if necessary
! lots of code
write(run_time_vars(1)%label,'(a1,i1)') my_string, my_integer
allocate(run_time_vars(1)%value, source = my_value)
This compiles, but doesn't run and I'm not going to stay long enough to fix it, I'll leave that as an exercise to anyone who cares.
The write to the label field isn't right.
The sourced allocation to the value field doesn't seem to work correctly. Might need to write a 'decode' function to use like this:
allocate(run_time_vars(1)%value, source = decode(my_value))
Like I said, it's a kludge.
I think you want to use a data structure. If you have pairs or groups of values that go together, then create a derived data type which can hold both. There's an explanation on this page:
http://web.mse.uiuc.edu/courses/mse485/comp_info/derived.html
If you have a list of these pairs (like your string and int above), then you can create an array of these types. Example code below taken from the page linked above:
type mytype
integer:: i
real*8 :: a(3)
end type mytype
type (mytype) var
Array:
type (mytype) stuff(3)
var%i = 3
var%a(1) = 4.0d0
stuff(1)%a(2) = 8.0d0
An significant benefit of doing this is that you can pass the pairs/groups of items to functions/subroutines together. This is an important programming principle called Encapsulation, and is used extensively in the Object Oriented programming paradigm.
No, this is not possible in Fortran.
For more information, look into Reflection (computer programming).
Clearly, for reasons given above, this is not legit Fortran (and thus you're going into trouble ...). You may use smart (congrats guys!) kludges, but ...
Instead of using variables h concatenated with 1, 2 or whatever number, why not creating array h(1:N) where N does not have to be known at compilation time : you just have to declare array h as a allocatable.
This is, I think, the legit way in Fortran 90+.
An example code is as follows:
program main
implicit none
integer :: ufile
real :: a, b, c
namelist /my_nlt/ a, b, c
open(newunit=ufile,file='my_nlt.txt')
read(ufile,my_nlt)
close(ufile)
write(*,my_nlt)
end program main
And the input file my_nlt.txt contains:
&my_nlt
a=1.0
b=2.0
/
Here the variable c is missing in the input file.
Running the code compiled by gfortran gives no warnning/error. I am wondering whether there is a compiler option that can be used to raise an error/warning when encountering this situation?
I am not aware of such an option for gfortran (or any other Fortran compiler). I would also strongly recommend not relying on such an option should one be found.
Namelist formatting exists to give a certain simplicity and flexibility of input to specific objects. Desiring a warning with a namelist read not updating all variables is perhaps trying to use the tool inappropriately.
For the program and input of the question, the expected runtime behaviour is for a and b to be defined with the values stated, and for c to be undefined. Instead, we could define the three variables with a value prior to the read and see whether they are updated by the read:
real, parameter :: SENTINEL=HUGE(0.)
real :: a=SENTINEL, b=SENTINEL, c=SENTINEL
namelist /my_nlt/ a, b, c
open(newunit=ufile,file='my_nlt.txt')
read(ufile,my_nlt)
if (a==SENTINEL.or.b==SENTINEL.or.c==SENTINEL) ERROR STOP
Here SENTINEL would be a value undesired for the variables or unexpected in the input. A variable not included in a namelist record retains its value prior to the read.
This isn't the same thing as certainly not appearing (especially where there may be no out-of-range input value) but if you want to check that then you'll have to parse the input file manually. The structure of such a namelist file is well defined.
As a final consideration, is the variable c "present" in the following namelist input record?
&my_nlt a=1., b=2., c=1* /
I'm trying to write in from fortran a text file.
I did this short test program but of course it does not work, because it does not create a text file that could be readable :
PROGRAM teste
INTEGER(4) REC2,RECL1
character(20) :: charI, wanted
RECL1=10
DO REC2=1,10
OPEN(1,FILE='teste.txt',ACCESS="direct",RECL=RECL1);
write (charI, "(A5,I4)") "hello", REC2
wanted=trim(charI)
write(1,REC=REC2) wanted
close(1)
END DO
END PROGRAM teste
I read lot of different thing but it's still really unclear how it should be written.
Do I need to convert to string before writing ? if yes why ?
Try this
PROGRAM test
IMPLICIT NONE
INTEGER, PARAMETER :: ascii = selected_char_KIND ("ascii")
INTEGER, PARAMETER :: ucs4 = selected_char_KIND ('ISO_10646')
INTEGER :: ix
CHARACTER(len=5,kind=ucs4) :: greeting = ucs4_"hello"
OPEN(10,FILE='test.txt')
DO ix=1,10
WRITE (10,'(A5,I4)') greeting, ix
END DO
CLOSE(10)
END PROGRAM test
... a commentary ...
PROGRAM test
IMPLICIT NONE
All good Fortran programs include the line implicit none; the reason for this is explained in 101 Qs and As here on Stack Overflow and I won't repeat them here.
INTEGER, PARAMETER :: ascii = selected_char_KIND ("ascii")
INTEGER, PARAMETER :: ucs4 = selected_char_KIND ('ISO_10646')
The latest Fortran standard requires that compilers provide these two kinds of character. I'm honestly not sure if iso_10646 is the same as UTF-8 but if it isn't you're probably out of luck. Here, I'm defining two parameters for identifying the character kinds to use later in the program. For your purposes the first of these parameters is unnecessary but you ought to know about it too.
I suppose your compiler might support other character kinds, read the documentation.
(Aside: technically, there is a third character kind name, default. This is likely to set the character kind to either ascii or iso_10646, most likely the former, but if this is important to you check your compiler's documentation.)
INTEGER :: ix
CHARACTER(len=5,kind=ucs4) :: greeting = ucs4_"hello"
In the second of these lines I've defined a character variable with the text hello and of kind ucs4 (which, as you see above, is a local code for iso_10646). Without the prefix ucs4_ the string hello will be interpreted as being of kind default and then converted to ucs4 when stored into the variable greeting. In this case, where there is a 1:1 mapping between the (representation of) the characters in ascii and in ucs4 the prefix is strictly unnecessary but there will be other cases where it won't be.
OPEN(10,FILE='test.txt')
DO ix=1,10
WRITE (10,'(A5,I4)') greeting, ix
END DO
CLOSE(10)
I've removed all the guff about direct access and writing at particular records in a file. It's all unnecessary for what seems to be your immediate need. So this loop will write greeting (ie the ucs4 string hello) and a row index into the file test.txt 10 times.
END PROGRAM test
In your open statement you are opening a file for unformatted input/output. Because you have specified ACCESS="direct" the default is for unformatted, compared with the default as formatted when connected for sequential access.
To make the file "readable" you need to actively open for formatted access, and provide a format for the writing:
open(1,FILE='teste.txt',ACCESS="direct",RECL=RECL1, FORM='formatted')
...
write(1,fmt=...,REC=REC2) ...
I would like to use deferred-length character strings in a "simple" manner to read user input. The reason that I want to do this is that I do not want to have to declare the size of a character string before knowing how large the user input will be. I know that there are "complicated" ways to do this. For example, the iso_varying_string module can be used: https://www.fortran.com/iso_varying_string.f95. Also, there is a solution here: Fortran Character Input at Undefined Length. However, I was hoping for something as simple, or almost as simple, as the following:
program main
character(len = :), allocatable :: my_string
read(*, '(a)') my_string
write(*,'(a)') my_string
print *, allocated(my_string), len(my_string)
end program
When I run this program, the output is:
./a.out
here is the user input
F 32765
Notice that there is no output from write(*,'(a)') my_string. Why?
Also, my_string has not been allocated. Why?
Why isn't this a simple feature of Fortran? Do other languages have this simple feature? Am I lacking some basic understanding about this issue in general?
vincentjs's answer isn't quite right.
Modern (2003+) Fortran does allow automatic allocation and re-allocation of strings on assignment, so a sequence of statements such as this
character(len=:), allocatable :: string
...
string = 'Hello'
write(*,*)
string = 'my friend'
write(*,*)
string = 'Hello '//string
write(*,*)
is correct and will work as expected and write out 3 strings of different lengths. At least one compiler in widespread use, the Intel Fortran compiler, does not engage 2003 semantics by default so may raise an error on trying to compile this. Refer to the documentation for the setting to use Fortran 2003.
However, this feature is not available when reading a string so you have to resort to the tried and tested (aka old-fashioned if you prefer) approach of declaring a buffer of sufficient size for any input and of then assigning the allocatable variable. Like this:
character(len=long) :: buffer
character(len=:), allocatable :: string
...
read(*,*) buffer
string = trim(buffer)
No, I don't know why the language standard forbids automatic allocation on read, just that it does.
Deferred length character is a Fortran 2003 feature. Note that many of the complicated methods linked to are written against earlier language versions.
With Fortran 2003 support, reading a complete record into a character variable is relatively straight forward. A simple example with very minimal error handling below. Such a procedure only needs to be written once, and can be customized to suit a user's particular requirements.
PROGRAM main
USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY: INPUT_UNIT
IMPLICIT NONE
CHARACTER(:), ALLOCATABLE :: my_string
CALL read_line(input_unit, my_string)
WRITE (*, "(A)") my_string
PRINT *, ALLOCATED(my_string), LEN(my_string)
CONTAINS
SUBROUTINE read_line(unit, line)
! The unit, connected for formatted input, to read the record from.
INTEGER, INTENT(IN) :: unit
! The contents of the record.
CHARACTER(:), INTENT(OUT), ALLOCATABLE :: line
INTEGER :: stat ! IO statement IOSTAT result.
CHARACTER(256) :: buffer ! Buffer to read a piece of the record.
INTEGER :: size ! Number of characters read from the file.
!***
line = ''
DO
READ (unit, "(A)", ADVANCE='NO', IOSTAT=stat, SIZE=size) buffer
IF (stat > 0) STOP 'Error reading file.'
line = line // buffer(:size)
! An end of record condition or end of file condition stops the loop.
IF (stat < 0) RETURN
END DO
END SUBROUTINE read_line
END PROGRAM main
Deferred length arrays are just that: deferred length. You still need to allocate the size of the array using the allocate statement before you can assign values to it. Once you allocate it, you can't change the size of the array unless you deallocate and then reallocate with a new size. That's why you're getting a debug error.
Fortran does not provide a way to dynamically resize character arrays like the std::string class does in C++, for example. In C++, you could initialize std::string var = "temp", then redefine it to var = "temporary" without any extra work, and this would be valid. This is only possible because the resizing is done behind the scenes by the functions in the std::string class (it doubles the size if the buffer limit is exceeded, which is functionally equivalent to reallocateing with a 2x bigger array).
Practically speaking, the easiest way I've found when dealing with strings in Fortran is to allocate a reasonably large character array that will fit most expected inputs. If the size of the input exceeds the buffer, then simply increase the size of your array by reallocateing with a larger size. Removing trailing white space can be done using trim.
You know that there are "complicated" ways of doing what you want. Rather than address those, I'll answer your first two "why?"s.
Unlike intrinsic assignment a read statement does not have the target variable first allocated to the correct size and type parameters for the thing coming in (if it isn't already like that). Indeed, it is a requirement that the items in an input list be allocated. Fortran 2008, 9.6.3, clearly states:
If an input item or an output item is allocatable, it shall be allocated.
This is the case whether the allocatable variable is a character with deferred length, a variable with other deferred length-type parameters, or an array.
There is another way to declare a character with deferred length: giving it the pointer attribute. This doesn't help you, though, as we also see
If an input item is a pointer, it shall be associated with a definable target ...
Why you have no output from your write statement is related to why you see that the character variable isn't allocated: you haven't followed the requirements of Fortran and so you can't expect the behaviour that isn't specified.
I'll speculate as to why this restriction is here. I see two obvious ways to relax the restriction
allow automatic allocation generally;
allow allocation of a deferred length character.
The second case would be easy:
If an input item or an output item is allocatable, it shall be allocated unless it is a scalar character variable with deferred length.
This, though, is clumsy and such special cases seem against the ethos of the standard as a whole. We'd also need a carefully thought out rule about alloction for this special case.
If we go for the general case for allocation, we'd presumably require that the unallocated effective item is the final effective item in the list:
integer, allocatable :: a(:), b(:)
character(7) :: ifile = '1 2 3 4'
read(ifile,*) a, b
and then we have to worry about
type aaargh(len)
integer, len :: len
integer, dimension(len) :: a, b
end type
type(aaargh), allocatable :: a(:)
character(9) :: ifile = '1 2 3 4 5'
read(ifile,*) a
It gets quite messy very quickly. Which seems like a lot of problems to resolve where there are ways, of varying difficulty, of solving the read problem.
Finally, I'll also note that allocation is possible during a data transfer statement. Although a variable must be allocated (as the rules are now) when appearing in input list components of an allocated variable of derived type needn't be if that effective item is processed by defined input.
I'm working with fortran subroutines of a finite element analysis program. I have to share variables between the two subroutines so I'm using COMMON blocks (EDIT: module is better). The problem is that only some of the variables are passed to the other subroutine, others are not.
My code is like this:
First subroutine:
real knom, krot
COMMON /kVAR/ kmom, krot
SAVE /kVAR/
Second subroutine I use the same syntax. I'm controlling the results by writing kmom and krot values in each subroutine to a txt file:
write(6,*) 'I am in URDFIL', or 'I am in UFIELD'
1 KINC, kmom, krot
The results are:
I am in URDFIL 1 -16700 -2.3857285E-03
I am in UFIELD 2 -16700 -1155769886
So the value of krot is lost. Any advise is most welcome.
João
Solved:
module shared_var
implicit none
real*8 kmom, krot
save
end module shared_var
And in each subroutine:
use shared_var
Did you include the declaration of knom, krot in the second routine? Probably you are getting implicit typing and krot is being output as an integer. And it appears that you have a typo: knom versus kmom. That is why kmom is output as an integer in both cases -- implicit typing as an integer since knom is the real. If implicit typing is in effect these variables will be integers since they begin with "k". My strong recommendation is to not use implicit typing unless it is too much work to remove from legacy code. It is highly recommended to use "implicit none" so that the compiler will warn you if you forget to type a variable or make a typo in a variable name. Most compilers have options that are equivalent to "implicit none".