fortran pass allocated array to main procedure - arrays

I have a module with a function which takes a starting and ending point and reads in a .txt some float value.
I wish that function to return a table which I do not know how large it will be before it starts.
I wish to use this function twice in the main program to make a third real array. But Fortran doesn't like it much.
Here is my code for the function :
module ReadData
!in this part, you need to know :
! -the starting (cannot be the first or second point)
! -end point
! -the file name (here : cham/comp or flow)
! change line 40 in case it is not AL026_Pd anymore
! -where it is on the file
implicit none
INTERFACE ReadP
MODULE PROCEDURE ReadDataPressure
END INTERFACE
private :: ReadDataPressure
contains
function ReadDataPressure (whereabout,StartingPoint,EndingPoint) result (P1)
!**********************
!**decla in variables**
character(50) :: whereabout !needed : cham/comp or flow
real(8) :: StartingPoint,EndingPoint
!************************
!**decla used variables**
character(50) :: FileNameConstructed
real(8) :: deltat,CurrentTime,pressure
integer(8) :: i,k
!**********************
!**decla out variable**
real(8),allocatable :: P1(:)
!start of the programe itself
write (FileNameConstructed,'(a,a,a)') "AL026_pd",whereabout,".txt"
open(20,file=FileNameConstructed,status='old',action='read')
read (20,*) deltat,pressure
read (20,*) CurrentTime,pressure
deltat=CurrentTime-deltat
!now deltaT is the loop counter, but we "lost" two usable line in the process
allocate (P1(1:int(((EndingPoint-StartingPoint)/deltat+1))))
k=1
do i=0,int((EndingPoint-2*deltat)/deltat)
read (20,*) CurrentTime,pressure
if (CurrentTime>StartingPoint) then
P1(k)=pressure
k=k+1
write(*,*) p1(k)
end if
end do
end function ReadDataPressure
End module
and I wish to do something like this in the main program
a=ReadP(comp,350,750)
b=ReadP(flow,350,750)
do i=1; lenght_of_a
m_ox(i)=squarreroot(a(i)-b(i))
end do
end then write it in another file.
I found : Share allocatable Arrays
FORTRAN - allocatable array in subroutine
but they did not help me.
One thinks perhaps
http://www.stanford.edu/class/me200c/tutorial_90/09_modules.html
is closer to the solution.
But they don't want a table at the end, they use Prod_A = PRODUCT(A) so you do not know the dimension of a, but can do product or sum. But I want to keep it whole.

In the main program you should be able to declare an allocatable array A and, if you have a Fortran 2003 compiler, do:
A = ReadDataPressure
Which is what you wish. This is allocation on assignment, which is part of Fortran 2003.
Why do you say that "fortran doesn't like it"? What are the specific error messages?
With compilers that don't support this it will be easier though less elegant to make the procedure a subroutine. Declare the array as allocatable in both the main program and the subroutine. Make it an intent (out) argument and allocate it in the subroutine.
P.S. Unless there are other aspects that you are not showing, setting up a module procedure for a single procedure seems pointless. I would leave off the interface and module procedure and make ReadDataPressure public so that it is directly called.

the mistake was :
character(50) :: whereabout
because there was
write (FileNameConstructed,'(a,a,a)') "AL026_pd",whereabout,".txt"
except that FileNameConstructed is also a character(50). (So i try to fit a 8+50+4 into 50).
But I was not able to see it before removing the private.
So thank MSB. You helped me a lot. I change whereabout in character(4) (since it feet my need perfectly) and so it is running

Related

Read file and find index of value in array in Fortran

I am making user subroutine file of Abaqus.
However, in reading a file I met with a difficulty.
Since, it is Fortran 77 based, it is so hard to find exact solution.
My intention is to read a file where an 1X1 array is include. Then, to find an index of a value in the array.
My code to read a file is :
open (unit=99,file='D:\SIMULATION\dist.txt',status='old')
read (99,*) dist
close (99)
And the code for finding index of value in array is:
loc=minloc(abs(dist-1),1)
I think minloc is for Fortran 90, right?
Is there any function in Fortran 77 similar to minloc?
The code you've shown should compile and run as expected. I'm assuming that you are actually reading a 1xN array and that when you said "1X1" it was a typo - otherwise, there's no point in using minloc.
However, the error message you reported in a comment (An array-valued argument is required in this context) only occurs if you use the minloc intrinsic on a scalar value. Thus, my guess is that you did not declare dist as an array. Here is a quick example of what I mean:
! The contents of 'values.txt' are: -3.1, 4.1, 5.9, 2.6, -5.4
! Values may be separated by commas or blanks.
program get_min_dist
implicit none
real :: x ! <-- Cannot be used to represent an array.
real, dimension(5) :: a ! <-- An array of 5 reals. Do this instead.
integer :: loc, funit1
open(newunit=funit1, file="values.txt", status="old")
read(funit1,*) x
rewind(funit1)
read(funit1,*) a
close(funit1)
loc = minloc(abs(a-1),1) ! <-- I'm assuming there is a reason to
! subtract 1 from all values in the array
! loc = minloc(abs(x-1),1) ! <-- Error 'An array-valued arg is required`
print*, "x=",x
print*, "a=",a
print*, "index=", loc
print*, "value=", a(loc)
end program get_min_dist
With read(funit1,*) x the first value will be assigned when the file is read, resulting in the error message you have seen. With the array a, however, you get the expected output.
Your confusion regarding the need to use F77 compatible code may be due to the fact that Abaqus continues to provide examples and docs with F77-style fixed-formatting, and requires Fortran source code to be given the .f or .for extension1. By default, this extension tells ifort to expect fixed-format code2. However, any Fortran features supported by the version of the compiler you use is still valid - even in fixed-format, if you must. For further information about the availability of features from different Fortran versions, see your (Intel Fortran) documentation.
1 I'd be glad to know if this can be changed somehow, e.g. to allow the .f90 extension.
2 This setting can be changed in the Abaqus environment file, at least for the versions I've used (6.9-6.14). I don't think that has changed with newer releases, but maybe. I don't recommend changing it if you share the environment with other users without their consent, especially for newbies.

Fortran derived type constructor defined though C function (II)

Following question Fortran derived type constructor defined though C function, I came up to this non working example, with gfortran 4.9:
module my_module
use iso_c_binding
type, bind(c) :: my_double
real(c_double) :: x
real(c_double) :: y
end type my_double
interface my_double
procedure my_module_fortran_new_my_double
end interface
interface
type(my_double) function my_module_fortran_new_my_double (v) bind ( c )
use iso_c_binding
import :: my_double
real (c_double), intent(in) :: v
end function my_module_fortran_new_my_double
end interface
end module my_module
program main
use my_module
type(my_double) x
x = my_double(12)
end program main
Following the previous question Fortran derived type constructor defined though C function, the module defintion works fine. However, the defined constructor is not recognized by my compiler.
Here is the compiler output:
$ gfortran -std=f2008 test.f90 -o test.o -c
test.f90:22.6:
x = my_double(12)
1
Error: No initializer for component 'y' given in the structure constructor at (1)!
This does seem that my used defined constructor is not taken into account. Could someone help me understanding what I have done wrong (again) ?
For a specific constructor to match
my_double(12)
there must be a procedure with interface
type(my_double) function something(i, ...) ...
integer ... :: i
..., optional, ... :: ...
end function
as the single component source given is of type integer.
The only non-default specific constructor provided is the one with one non-optional component source of type real(c_double).
To solve, two approaches:
add a specific procedure which takes a default integer; or
specify an appropriate argument to the non-default constructor.
For this latter:
x = my_double(12._c_double) ! c_double from intrinsic iso_c_binding
It's worth noting why this problem comes about. You may happily try
x = my_double(12,13) ! Using the normal constructor
x = my_double(12) ! Using the normal constructor if default
! initialization applies for component y
as with the implied constructor there is conversion of the source term (following the rules of intrinsic assignment) to the type/parameters of the component itself. Such conversion does not apply in the case of resolving generics.

Can't write to file in Fotran90

I can't understand why my Fortran90 program does not write to file anymore. It used to work some hours ago. I haven't modified that part of the code, nor I have introduced some conditions by virtue of which it should not write to file . On the next line i have put a print command which writes on terminal the same values that should be written to file, and this works.
open(500, file='data.dat')
write(500,fmt='(E14.4,E14.4)') A,B !this SHOULD be printed on unit 500
write(*, fmt='(E14.4,E14.4)') A,B ! this is printed on terminal
I have tried to change unit, but nothing changes. I have tried to open a new file with a new name and writing onto it, also in other parts of the code, even at the beginning, just after variables declaration. This does not seem to work either. It is so frustrating, because everything worked properly previously. What could have happened?
Using gfortran 5.3 under Linux and the following program (that is your code copy-pasted and the minimal boilerplate).
program hop
implicit none
double precision :: A, B
A = 1
B = 2
open(500, file='data.dat')
write(500,fmt='(E14.4,E14.4)') A,B !this SHOULD be printed on unit 500
write(*, fmt='(E14.4,E14.4)') A,B ! this is printed on terminal
end program hop
outputs 0.1000E+01 0.2000E+01 in the terminal and the exact same content in the file data.dat.
Is the write instruction in a program that hangs? Not seeing output might be related to i/o buffering.
Is the behaviour changing if you add the line
flush(500)
after the write instruction?
I have to write to file in a cycle. Now I open the file in the cycle having added position='append' and I close it at the end of the cycle. Just like
program pro
implicit none
integer (kind=2) :: i, A, B
do i=1,10
A=i
b=i+1
open(500, file='file.dat', position='append')
write(500, *) A, B
close(500)
enddo
That seems to work now.

writing file with output function haskell

I would like to write to a file the output of my program automatically, but some errors are appearing. I'm New to haskell.
A really simple example:
func = do
writeFile "file.txt" show(calc)
calc = do return (1+1)
I wanted something like this. When I execute the function, creating a file and write on it
The error is:
ERROR "test.hs":5 - Syntax error in input (unexpected `=')
Thanks.
There are several errors in this code:
You should remove the dos to simplify func and calc. Technically this is not an error but you should not use unnecessary dos because they just clutter up your code.
show has the type Show a => a -> String, whereas calc has the type IO String. Because the types mismatch, your program would not compile.
This is a program with the same functionality which compiles:
func :: IO () -- is an IO action
func = writeFile "file.txt" (show calc) -- removed the do
calc :: Integer -- has type integer, meaning "show" is able to operate on it
calc = 1+1 -- removed do and return
The reason to remove the return is that return does not behave like return in C-like languages. return in Haskell wraps a value in a monadic action whereas in C-like languages it just returns the value of an expression or a variable as result of a function. I would recommend reading this chapter for further information as it covers in- and output in Haskell pretty well.

Writing in two different places unformatted files in Fortran

I am trying to write in two different places (the main program and a subroutine) unformatted files in my Fortran code. The problem is that when I do it, the results change and I suspect that it is because the memory assignment is overwriting the data that I am using to make the simulation in my CFD code. I ask: Is it possible that one can just use the unformatted file (to write) once in the code? I mean, I have to use the same file to save all my data and not with different files.
I copy and past the two parts of the code to show what I am want to describe:
In the main program, the loop is:
call numcar (isave,suffix)
longueur=index(nchamp,' ')-1
nfichier=nchamp(1:longueur)//suffix
longueur=index(nfichier,' ')-1
open(10,file=nfichier(1:longueur),form='unformatted')
write(10) real(uxn,4),real(uyn,4),real(wzn,4),real(ppo,4)
close(10)
! *****************************************
isave=isave+1
and in the subroutine, the loop is:
call numcar (isavediv,suffix1)
longueur1=index(ndiv,' ')-1
nfichier1=ndiv(1:longueur1)//suffix1
longueur1=index(nfichier1,' ')-1
open(20,file=nfichier1(1:longueur1),form='unformatted')
write(20) real(ppm,4)
close(20)
! *****************************************
isavediv=isavediv+1
All the variables all declared as IMPLICIT NONE in both main program and subroutine.
I solved my problem.
The problem was that I was using the channel number 20 and a colleague of mine told me that this channel is used by the computer or some devices to process data.
I changed it for channel number 10 and it worked good again.
Thank you for your comments.
Now it looks so:
open(10,file=nfichier1(1:longueur1),form='unformatted')
write(10) real(ppm,4)
close(10)

Resources