min and max of input array file (.dat) with subroutine - arrays

I try to implement a code that read in a number n, creates a vector to store n double precision numbers, read this number, call a subroutine printminmax() to find min and max. My code work perfect for normal numbers (integer,real etc) but when i have scientific notation (0.3412E+01) stack.Why? I thought with * read all the formats. Thanks
implicit none
integer, dimension(:), allocatable :: x
integer :: n
open (unit=77, file='input2.dat', action='read', status='old')
read(77,*), n
allocate(x(n))
call printminmax(n)
deallocate(x)
end
subroutine printminmax(y)
implicit none
integer, dimension(:), allocatable :: x
integer :: y,max,min,i
allocate(x(y))
read(77,*) x
!print *,'Maximun=', maxval(x)
!print *,'Minimun=', minval(x
!initialize the value max & min
max=x(1)
min=x(1)
do i=2,y
if (x(i)>max) max=x(i)
if (x(i)<min) min=x(i)
end do
write(*,*) 'Maximum=',max
write(*,*) 'Minimum=',min
end subroutine printminmax
one example of the stack input is
1000
5.39524398466520e-01
9.85099770130787e-01
7.38946122872518e-01
6.47771620257608e-01
8.80871051119695e-01
2.99375585725816e-02
the error that i take for scientific notation is
At line 13 of file io.f90 (unit = 77, file = 'input3.dat')
Fortran runtime error: Bad integer for item 1 in list input

ok i found it.I should have double precision on x, no integer.

Related

Error Message about Array Arguments in Code for Mean

I have a variable length (L) that changes for each particle in a group of a few hundred thousand particles with every time step. I'm trying to add a code that will tell me the average length of the particles at each time step in the model. I keep getting this error: "An array-valued argument is required in this context" for my mean equation. What does this mean? It seems to have a problem with my length variable, which I extract from the model using get_state. Here is my code:
function checkstatus(ng,g,time) result(validsim)
use utilities
implicit none
logical :: validsim
integer, intent(in) :: ng
type(igroup), intent(in) :: g(ng)
real(sp), intent(in) :: time
real(sp), pointer :: L(:)
real(sp), dimension(ng) :: mean
integer, pointer :: istatus(:)
integer, allocatable :: mark(L)
integer :: n,NI
integer, save :: dumphead = 0
do n=1,ng
NI = g(n)%Nind
call get_state('L',g(n),L)
mean(NI) = sum(L(NI)) / size(L(NI))
end do
write(*,103)time,mean(NI)
In your code, L is a pointer to a one-dimensional real array, and so L(NI) is a scalar real. The intrinsics sum and size take array arguments, so the statement sum(L(NI)) / size(L(NI)) is invalid.

Fortran shape matching rules violated

What am I trying to achieve
Im trying to write a subroutine that takes an Matrix (2D array) as input and prints it nicely to the standard console output.
Problem
error #6634: The shape matching rules of actual arguments and dummy arguments have been violated. ['U']
Code
The subroutine printing the matrix is in this module
Module
MODULE LinearSystems
IMPLICIT NONE
private
...
public showMatrix
...
contains
subroutine showMatrix(a, n, m, name)
implicit none
double precision, dimension(:,:), intent(in) :: a
character, dimension(:), intent(in), optional :: name
integer, intent(in) :: n,m
integer :: i, j
write(*,*) "*** Show Matrix ", name, " ***"
do i = 1, n
do j = 1, m
write(*,'(F8.4)',advance="no") a(i,j)
end do
write(*,*)
end do
end subroutine showMatrix
and the main program calls it
Main Program
program PoisonEquation
...
use LinearSystems
implicit none
double precision, dimension(:,:), allocatable :: u,...
integer :: n = 700
allocate(u(n-1,n-1))
...
call showMatrix(u, n-1,n-1, "U")
I'm looking forward to receive tipps on how to improve this code snipped and get it bug free.
The name dummy argument is an assumed shape array (see the dimension(:) declaration). The "U" literal used for the actual argument is scalar (the error message refers to this literal).
If a dummy argument is an assumed shape array, the rank of the actual argument shall be the same as the rank of the dummy argument (F2018 15.5.2.4p16).
Figure out whether you want to pass/receive an array or a scalar, and fix the code.
Problem solved
The problem was in the character initialisation and after fixing this issue as well as fixing a issue in the main program, which lead to u being deallocated before it was passed to the subroutine the code now works and the subroutine for printing looks like this:
subroutine showMatrix(a, name)
implicit none
double precision, dimension(:,:), intent(in) :: a
character(*), intent(in), optional :: name
integer :: i, j
write(*,*) "*** Show Matrix ", name, " ***"
do i = 1, size(a,1)
do j = 1, size(a,2)
write(*,'(F8.4)',advance="no") a(i,j)
end do
write(*,*)
end do
end subroutine showMatrix

Read a matrix from a text file and print it

I want to write an 3 x 4 matrix from a 12 line txt numerical file
I have written a Fortran 90 program for the same
program array
implicit none
integer, parameter :: I4B = selected_int_kind(4)
integer (I4B), allocatable, dimension (:,:) :: arr
integer (I4B) :: i
open(unit=99, file='1.txt')
open(unit=100, file='out.txt')
Allocate (arr(3,4))
do i=1, 12
read(99,*)arr(3,4)
write(100,*),arr(3,4)
enddo
close (99)
deAllocate (arr)
stop
endprogram array
but it's giving an error
At line 10 of file array.f90 (unit = 99, file = '1.txt')
Fortran runtime error: End of file
Line number 10 is read(99,*)arr(3,4).
Here's a very simple implementation of your array. It uses the fact that the first index is the fastest changing. So I just keep reading until all 12 elements of the array are filled.
Then, for output, I specify a format that it should write 3 values per line.
program readfile
implicit none
integer, dimension(:, :), allocatable :: arr
open(unit=99, file='1.txt', action='READ', status='OLD')
open(unit=100, file='out.txt', action='WRITE', status='NEW')
allocate(arr(3, 4))
read(99, *) arr
write(100, '(3I4)') arr
close(99)
close(100)
end program readfile
If you want to do it explicitly, you have to calculate the two indices independently for each value read:
program readfile
implicit none
integer, dimension(:, :), allocatable :: arr
integer :: i, row, col
open(unit=99, file='1.txt', action='READ', status='OLD')
open(unit=100, file='out.txt', action='WRITE', status='NEW')
allocate(arr(3, 4))
! Read the elements:
do i = 1, 12
row = mod(i-1, 3)+1
col = (i-1) / 3 + 1
read(99, *) arr(row, col)
end do
! write the elements:
do i = 1, 4
write(100, '(3I4)') arr(:, i)
end do
close(99)
close(100)
end program readfile
By the way, your code:
do i = 1, 12
read(99, *) arr(3, 4)
write(100, *) arr(3, 4)
end do
would just 12 times read a single number from the input file, store it in the last location of the array, then write that same number back to the output file.
Also, your error message suggests that you have tried to read past the end of the file. Either your 1.txt doesn't contain 12 lines, or you might have read something else first, for example to find out how many elements there are. In that case, you would need to add a rewind(99) before you start reading the actual numbers.

finding specific indices with pointer array

I am relatively new to Fortran and break my head about one thing for hours now:
I want to write a subroutine for finding the indexes for specific elements in a real 1D array (given to the routine as input).
I have generated an array with 100 random reals, called arr, and now want to determine the indexes of those elements which are greater than a real value min, which is also passed to subroutine.
Plus, in the end I would like to have a pointer I'd allocate in the end, which I was said would be better than using an array indices containing the indexes once found.
I just didn't find how to solve that, I had following approach:
SUBROUTINE COMP(arr, min)
real, intent(in) :: arr(:)
real, intent(in) :: min
integer, pointer, dimension(:) :: Indices
integer :: i, j
! now here I need a loop which assigns to each element of the pointer
! array the Indices one after another, i don't know how many indices there
! are to be pointed at
! And I dont know how to manage that the Indices are pointed at one after another,
! like Indices(1) => 4
! Indices(2) => 7
! Indices(3) => 32
! Indices(4) => 69
! ...
! instead of
! Indices(4) => 4
! Indices(7) => 7
! Indices(32) => 32
! Indices(69) => 69
! ...
DO i = 1, size(arr)
IF (arr(i) > min) THEN
???
ENDIF
ENDDO
allocate(Indices)
END SUBROUTINE COMP
If succinctness (rather than performance) floats your boat... consider:
FUNCTION find_indexes_for_specific_elements_in_a_real_1D_array(array, min) &
RESULT(indices)
REAL, INTENT(IN) :: array(:)
REAL, INTENT(IN) :: min
INTEGER, ALLOCATABLE :: indices(:)
INTEGER :: i
indices = PACK([(i,i=1,SIZE(array))], array >= min)
END FUNCTION find_indexes_for_specific_elements_in_a_real_1D_array
[Requires F2003. Procedures that have assumed shape arguments and functions with allocatable results need to have an explicit interface accessible where they are referenced, so all well behaved Fortran programmers put them in a module.]
A simple way to get the indices of a rank 1 array arr for elements greater than value min is
indices = PACK([(i, i=LBOUND(arr,1), UBOUND(arr,1))], arr.gt.min)
where indices is allocatable, dimension(:). If your compiler doesn't support automatic (re-)allocation than an ALLOCATE(indices(COUNT(arr.gt.min)) would be needed before that point (with a DEALLOCATE before that if indices is already allocated).
As explanation: the [(i, i=...)] creates an array with the numbers of the indices of the other array, and the PACK intrinsic selects those corresponding to the mask condition.
Note that if you are doing index calculations in a subroutine you have to be careful:
subroutine COMP(arr, min, indices)
real, intent(in) :: arr(:)
real, intent(in) :: min
integer, allocatable, intent(out) :: indices(:)
!...
end subroutine
arr in the subroutine will have lower bound 1 regardless of the bounds of the actual argument (the array passed) (which could be, say VALS(10:109). You will also then want to pass the lower bound to the subroutine, or address that later.
[Automatic allocation is not an F90 feature, but in F90 one also has to think about allocatable subroutine arguments
I think you're on the right track, but you're ignoring some intrinsic Fortran functions, specifically count, and you aren't returning anything!
subroutine comp(arr, min)
real, intent(in) :: arr(:)
real, intent(in) :: min
! local variables
integer, allocatable :: indices(:)
integer :: i,j, indx
! count counts the number of TRUE elements in the array
indx = count(arr > min)
allocate(indices(indx))
! the variable j here is the counter to increment the index of indices
j=1
do i=1,size(arr)
if(arr(i) > min) then
indices(j) = i
j = j+1
endif
enddo
end subroutine comp
Then you can use the array indices as
do i=1,size(indices)
var = arr(indices(i))
enddo
Note that since you are not returning indices, you will lose all the information found once you return--unless you plan on using it in the subroutine, then you're okay. If you're not using it there, you could define it as a global variable in a module and the other subroutines should see it.

Share allocatable Arrays

I have some allocatable arrays which I need to share between some subroutines. I usually would just pass them as arguments or maybe write everything in a Module, but I'm afraid this isn't possible in my situation.
I only write some own subroutines and use subroutines provided and described by an FEM-Solver. So i cannot alter the arguments of this subroutines or wrap them in a Module.
As far as i know it also isn't possible to Build common blocks with array of unknown size at compile time.
Is there something else to pass my arrays?
Update:
At the moment my program environment looks like this:
I have a subroutine, provided by the FEM-program, which is called after each increment, this calls several of my subroutines where I compute some values for each node or for a subset of those.
To display these values in the post-Simulation, i have to pass them to another subroutine. This subroutine is called by the FEM-solver for each node at the end of the increment. So shifting my code to this Subroutine would produce a lot of overhead.
My idea is to compute the values once, store the Values in an array and pass this array to the second subroutine where they will be written to the database of the computation.
Update
Some Pseudo-code:
Assumed from program behaviour:
Program FEM-solver
*magic*
call ENDINC(ar1,ar2)
*something*
do NodeID=1,Sum_Of_Nodes
do valueID=1,Sum_Of_User_Computed_Values !(defined in preprocessing)
call nodeval(NodeID,valueID,Value,ar3,...,arN)
end do
end do
*voodoo*
end program FEM-solver
Written and working:
Subroutine ENDINC(ar1,ar2)
*Computation of some node values*
*Calling of own Subroutines, which compute more values*
*Writing an array with results values for some/each node(s)*
nodersltArr(NodeID,rslt)=*some Value*
end Subroutine ENDINC
Needed, writng the computed Values to the Node solution database:
Subroutine nodeval(NodeID,valueID,Value,ar3,...,arN)
*called for each NodeID and valueID*
value=noderslArr(NodeID,valueID)
end subroutine nodeval
You can pass an allocatable array to procedure that isn't declared to use allocatable arrays, as long as the array is allocated before the call. (Of course, you can't use the array as an allocatable array in the procedure in which it is declared without that property.) Perhaps that will solve your problem. Allocate the array in the code that you write, than pass it as an argument to the FEM solver.
Example code: (I'd normally put the function into a module but you say that you can't do that, so I write an example showing the case of not using a module.)
function MySum ( RegArray )
real :: MySum
real, dimension (:), intent (in) :: RegArray
MySum = sum (RegArray)
end function MySum
program TestArray
implicit none
interface AFunc
function MySum ( SomeArray )
real :: MySum
real, dimension (:), intent (in) :: SomeArray
end function MySum
end interface AFunc
real, dimension (:), allocatable :: AllocArray
integer :: N
real :: answer
write (*, '("Input array size: ")', advance="no")
read (*, *) N
allocate ( AllocArray (1:N) )
AllocArray = 1.0
answer = MySum ( AllocArray )
write (*, *) answer
end program TestArray
---------- EDIT: Second Concept ---------
Sharing an allocatable array between two subroutines, without the calling routine being "aware" of the array.
module MySubs
real, allocatable, dimension (:,:) :: array
contains
subroutine One ( x, y, ... N, M )
integer, intent (in) :: N, M
if ( .NOT. allocated (array) ) allocate ( array (N, M) )
end subroutine One
subroutine Two ( .... )
end subroutine Two
end module MySubs
UPDATE: note: This approach can be used to pass information between the two routines without the main program having access the module ... for the question, without modifying the original main prpgram. Part of the example is how to allocate the arrays: the example does that by having the subroutine that would first use the array test whether the array is allocated -- if not, it allocates the array.
The three examples below all work with gfortran. The second may fail on some compilers as it uses a F2003 feature (allocatable dummy arguments), and not all compilers are 100% F2003 compliant. However, most implement ISO TR 15581 (which includes this feature).
First version, you can use a common pointer to allocatable array.
program hip
implicit none
double precision, dimension(:, :), pointer :: p
common /hiphop/ p
double precision, allocatable, dimension(:, :), target :: a
allocate(a(100, 100))
a(1, 1) = 3.1416d0
p => a
call hop
deallocate(a)
end program
subroutine hop
implicit none
double precision, dimension(:, :), pointer :: p
common /hiphop/ p
print *, size(p, 1), size(p, 2), p(1, 1)
end subroutine
Second version, allocating in a subroutine then calling another. One still needs to declare the array in main program.
program hip
implicit none
interface
subroutine hip_alloc(arr)
double precision, allocatable, dimension(:, :) :: arr
end subroutine
end interface
double precision, dimension(:, :), pointer :: p
common /hiphop/ p
double precision, allocatable, dimension(:, :) :: a
p => null()
print *, "a:", allocated(a)
print *, "p:", associated(p)
call hip_alloc(a)
print *, "a:", allocated(a)
print *, "p:", associated(p)
call hop
deallocate(a)
end program
subroutine hip_alloc(arr)
implicit none
double precision, dimension(:, :), pointer :: p
common /hiphop/ p
double precision, allocatable, dimension(:, :), target :: arr
allocate(arr(100, 100))
arr(1, 1) = 3.1416d0
p => arr
end subroutine
subroutine hop
implicit none
double precision, dimension(:, :), pointer :: p
common /hiphop/ p
print *, size(p, 1), size(p, 2), p(1, 1)
end subroutine
Third version, here we first call a function returning a pointer, then pass this pointer to a subroutine through a common. The function does the allocation, as in second example. The pointer is deallocated in main program, but could be elsewhere.
program hip
implicit none
interface
function hip_alloc(n)
integer :: n
double precision, dimension(:, :), pointer :: hip_alloc
end function
end interface
double precision, dimension(:, :), pointer :: p
common /hiphop/ p
p => null()
print *, "p:", associated(p)
p => hip_alloc(100)
print *, "p:", associated(p)
call hop
deallocate(p)
end program
function hip_alloc(n)
implicit none
integer :: n
double precision, dimension(:, :), pointer :: hip_alloc
allocate(hip_alloc(n, n))
hip_alloc(1, 1) = 3.1416d0
end function
subroutine hop
implicit none
double precision, dimension(:, :), pointer :: p
common /hiphop/ p
print *, size(p, 1), size(p, 2), p(1, 1)
end subroutine
I do not understand why writing a MODULE would not work, but have you considered CONTAINS? Everything above the CONTAINS declaration is visible to the subroutines below the CONTAINS:
PROGRAM call_both
INTEGER,DIMENSION(2) :: a, b
a = 1
b = 2
PRINT *,"main sees", a, b
CALL subA
CALL subB
CONTAINS
SUBROUTINE subA
PRINT *,"subA sees",a,b
END SUBROUTINE subA
SUBROUTINE subB
PRINT *,"subB sees",a,b
END SUBROUTINE subB
END PROGRAM call_both
The output would be
main sees 1 1 2 2
subA sees 1 1 2 2
subB sees 1 1 2 2
This works with ALLOCATABLE arrays as well.

Resources