Write array to file by columns - arrays

Is there a way to write columns to a file one by one? For example, I would like to write:
write(1,*) 1
write(1,*) 2
And then write (possibly in another subroutine)
write(1,*) 3
write(1,*) 4
in such a way that will produce an output file in the format:
1 3
2 4
without combining the arrays (e.g.)
write(1,*) 1,3
write(1,*) 2,4
I'm thinking that there may be a way to move the "pointer" (of file location) back to the beginning and add spaces or something, but I really have no idea if this is possible. Any help is greatly appreciated!
So far, this is my attempt to make a subroutine to make this work:
subroutine writeArrayToNthColumn(arr,u,n)
implicit none
real(dpn),dimension(:),intent(in),target :: arr
real(dpn),dimension(:),pointer :: parr
integer,intent(in) :: u,n
integer :: i,s
s = size(arr)
allocate(parr(s))
parr = arr
rewind(u)
if (n.eq.1) then
do i=1,s
write(u,'(1F20.10)') parr(i)
enddo
else
do i=1,s
write(u,'(1F40.10)') parr(i)
enddo
endif
end subroutine
But upon calling the subroutine a second time, the first column is deleted..

The comments above from George, and High Performance Mark are exactly right. I'm posting this as an answer, because it has source code, but it should be considered an extended comment, whose only purpose is to demonstrate how right they are.
You can do this, in a sense, although under no circumstances should you do so. Moving around within a file - a so called seek - is an incredibly expensive operation. On a local hard drive, this can take 10-20 milliseconds or so per operation (eg, in this case, per entry); if you are using a large shared system it can be much larger than that.
Moving things around in memory, however, is much less expensive. A well-tuned transpose function will do most of the moving around in cache, with operation that take a few nanoseconds; the data will get batched into and from main memory in fewer operations which each take ~100ns or so. Even a seek on a modern SSD will take something like dozens of microseconds.
In other words, there is no situation in which doing the transpose in your file I/O will be less than hundreds of times slower than doing the transpose in memory (and then back if needed). You still have to do the file/IO in the end, but if you are writing out in one batch, this is much faster.
So let's try some examples in Fortran, since that's the language of this question. Fortran, sensibly, makes this somewhat harder by making it difficult to access file locations directly, and even to explicitly output in carriage returns; I've used direct-access IO here and hard-coded in a non-portable way of doing the carriage returns.
Here's doing the transpose in your I/O:
program badiotxt
implicit none
integer, parameter :: asize = 200
integer, dimension(asize, asize) :: a
integer :: i, j
integer :: record
forall (i=1:asize, j=1:asize)
a(i,j) = (i-1)*asize+j
end forall
open(unit=7,file="bad.txt", status="new", access="direct", &
form="formatted", action="write", recl=10)
do j=1,asize
do i=1,asize-1
record=(j-1)*asize+i
write(7, rec=record, fmt="(2X,I7,1X)") a(i,j)
enddo
enddo
i = asize
do j=1,asize
record=(j-1)*asize+i
write(7, rec=record, fmt="(1X,I7,A1,A1)") a(i,j), char(13), char(10)
enddo
close(7)
end program badiotxt
and here's one done by transposing the array:
program goodiotxt
implicit none
integer, parameter :: asize = 200
integer, dimension(asize, asize) :: a
integer :: i, j
integer :: record
forall (i=1:asize, j=1:asize)
a(i,j) = (i-1)*asize+j
end forall
open(unit=7,file="good.txt", status="new", &
form="formatted", action="write")
a = transpose(a)
do i=1,asize
write(7,fmt="(1X,200(2X,I7))") (a(i,j), j=1,asize)
enddo
a = transpose(a)
close(7)
end program goodiotxt
Note that the good version is cleaner code, and that these are not large arrays by any stretch. The resulting times are:
Transpose in memory: 0.05s
Transpose on disk: 1.70s
Slowdown: 34x

I've a bit more time now than when I first commented on this question. This is, however, an extended comment rather than a full-blown answer.
Even IF (that's a big if) I had to write a data file column-by-column I wouldn't use direct access IO as #Jonathan Dursi's answer proposes. That (direct access IO) is for situations where it is difficult to predict, at the time the code is written, the ordering of writes to a file. In OP's case the ordering of writes seems to be entirely predictable.
I would:
Write column 1, element-by-element, to a file.
2.1 Open a second file for writing, and the first file for reading.
2.2 Read the first line from the first file, write it to the second file and append the first element of the next column.
2.3 Repeat 2.2 until I got to the end of the column/file.
2.4 Close the second file (which now contains columns 1 and 2) and the first file.
3.1 Open the second file for reading, and perform a destructive open on the first file for writing.
... by now you should have got the picture.

Related

Fortran 90 - Algebra operation with scalar and arrays

I am working with a Fortran 90 program that, amongst many others, has the following variables declared:
real(r8) :: smp_node_lf
real(r8), pointer :: sucsat(:,:)
real(r8), pointer :: h2osoi_vol(:,:)
real(r8), pointer :: watsat(:,:)
real(r8), pointer :: bsw(:,:)
And at some point in the program, there is an algebra operation that looks like this:
do j = 1,nlevgrnd
do c = 1,fn
...
smp_node_lf = -sucsat(c,j)*(h2osoi_vol(c,j)/watsat(c,j))**(-bsw(c,j))
...
end do
end do
I am trying to "translate" a dozen lines of this program to R, but the above excerpt in particular made me confused.
What is the dimension of smp_node_lf? Is it an scalar? Does it inherit the dimensions of the arrays sucsat,h2osoi_vol,watsat and bsw?
There is a lack of dimensions for smp_node_lf because it is a scalar, and it is receiving the value of that scalar operation multiple times, being rewritten, if there is nothing to save its value to a vector or something.
It will never inherit the dimensions of any of those elements, there is never a vector to be inherited, everything it is receiving is scalar
if you have to retrieve its value, assuming the original code is capable of it as it is, there should be another part inside this very loop that saves that value before it is overwritten by another pass.
If there is not such thing, implement it, you might be dealing with incomplete code that does nothing it was said to do.
I've dealt with my fair share of "perfect code" that "did miracles when I used last time" with not a single miracle to be found within its lines of code.

Assumed size arrays in fortran [duplicate]

I am writing code to add on a closed-source Finite-Element Framework that forces me (due to relying on some old F77 style approaches) in one place to rely on assumed-size arrays.
Is it possible to write an assumed-size array to the standard output, whatever its size may be?
This is not working:
module fun
implicit none
contains
subroutine writer(a)
integer, dimension(*), intent(in) :: a
write(*,*) a
end subroutine writer
end module fun
program test
use fun
implicit none
integer, dimension(2) :: a
a(1) = 1
a(2) = 2
call writer(a)
end program test
With the Intel Fortran compiler throwing
error #6364: The upper bound shall not be omitted in the last dimension of a reference to an assumed size array.
The compiler does not know how large an assumed-size array is. It has only the address of the first element. You are responsible to tell how large it is.
write(*,*) a(1:n)
Equivalently you can use an explicit-size array
integer, intent(in) :: a(n)
and then you can do
write(*,*) a
An assumed-size array may not occur as a whole array reference when that reference requires the shape of the array. As an output item in a write statement that is one such disallowed case.
So, in that sense the answer is: no, it is not possible to have the write statement as you have it.
From an assumed-size array, array sections and array elements may appear:
write (*,*) a(1:2)
write (*,*) a(1), a(2)
write (*,*) (a(i), i=1,2)
leading simply to how to get the value 2 into the subroutine; at other times it may be 7 required. Let's call it n.
Naturally, changing the subroutine is tempting:
subroutine writer (a,n)
integer n
integer a(n) ! or still a(*)
end subroutine
or even
subroutine writer (a)
integer a(:)
end subroutine
One often hasn't a choice, alas, in particular when associating a procedure with a dummy procedure with a specific interface . However, n can get into the subroutine through any of several other ways: as a module or host entity, or through a common block (avoid this one if possible). These methods do not require modifying the interface of the procedure. For example:
subroutine writer(a)
use aux_params, only : n
integer, dimension(*), intent(in) :: a
write(*,*) a(1:n)
end subroutine writer
or we could have n as an entity in the module fun and have it accesible in writer through host association. In either case, setting this n's value in the main program before writer is executed will be necessary.

fortran read statement not stopping

program not stopping to read "ar". help please. even after allocating that it has definite number of elements. what may be the reason? is there something a could have missed?
program summer_a39
implicit none
integer:: n, i, l, k
integer, allocatable, dimension(:)::ar
print*, 'Enter size of array:'
read*, n
allocate (ar(n))
print*, 'Enter values:'
read*, ar
l=1
3 do i=l,n-1
if (l==n) then
goto 4
end if
if (ar(i)<=ar(i+1)) then
goto 1
else
goto 2
end if
end do
1 do i=l,n-1
do while (ar(i)<=ar(i+1))
k=k+1
end do
l=k
end do
print*, 'Increases to', l
goto 3
2 do i=l,n
do while (ar(i)>=ar(i+1))
k=k+1
end do
l=k
end do
print*, 'Decreases to', l
goto 3
4 print*, 'The End'
deallocate(ar)
end program
Uhm... Wow... Well...
That code makes no sense at all.
I hate to say it, but you still have a lot of learning and understanding to do.
First of all: STOP USING GOTO. It breaks the code flow and makes reading it a mess.1)
Secondly: Even without checking, I'm confident that the read statement is not the reason your program hangs. It hangs between the various loops.
Even without the goto statements, this snippet alone is a surefire way to get the program to hang:
do while (ar(i)>=ar(i+1))
k=k+1
end do
This loop keeps repeating for as long as ar(i) is larger or equal to ar(i+1) -- but in the body of the loop, neither value changes (only k, but k is not part of the condition). So if the condition is true once, it will stay true forever, and the loop will never ever terminate.
Then you keep jumping back to the beginning of a loop. Each time you do that, the loop starts again from scratch. Again, you never come to a conclusion.
I contemplated showing how to use subroutines to do what I think you want to do, but I thought better of it. You need a lot more time to understand what's going on, and I suggest you find some dedicated resources that teach programming.
It doesn't have to be Fortran specific, any tutorial for any procedural language will help you understand program flow, which is what you need to analyse this mess.
1) a good programmer might know when to use goto. You are not a good programmer yet.
After your comments to my previous answer, I got a better idea of your situation.
Here's what I understand so far:
You have an exercise for a Fortran training/lessons/etc.
The exercise is to create a program that takes as input an array of arbitrary length, and then prints out the final values of each monotonic sequence in that array. So for example, if the input were 4 3 7 2 1 4 6 3 5 10, then the output should be something like:
Starts with 4
Decreases to 3
Increases to 7
Decreases to 1
Increases to 6
Decreases to 3
Increases to 10
The end
Part of the exercise is that you should make use of the GOTO command.
So here's my updated answer:
This is not a homework service, we won't solve the issue for you. Then again, you didn't ask for that, so that's okay.
Your issue is not the read*, ar command. You can test this out easily by just adding a print*, ar right below it, it will print.
Your issue is that there is an infinite loop inside your code (actually, there are several), some because you use DO WHILE loops where the condition never changes in the iteration, some because you jump out of one loop to the beginning of another, which resets the initial conditions.
Here are some hints for your exercise:
Create a single variable for the index of the array that you're currently looking at.
Create two loops, one for increasing this index as long as the next value in the array is larger, and one as long as the next value is smaller. Check that you don't increase the index beyond the range of the array.
Do not jump from inside of any loop
Do not jump into the middle any loop.
At the end of either loop, think about what you learned about the array, and were to jump to from there.
Make sure that you know that the algorithm will eventually stop.
And finally, there's no harm in using lots of print* statements during debugging to make you understand what the program is actually doing.

Read array from .txt data

I would like to read an array from a .txt file in Fortran. I tried it with the following code:
PROGRAM test_performance
IMPLICIT NONE
DOUBLE PRECISION, DIMENSION(:), ALLOCATABLE :: ARRAYONE
OPEN(UNIT=20,FILE='testfile.txt',STATUS='OLD', ACTION='READ')
READ (20,*) ARRAYONE
print *, 'here I am!'
CLOSE(UNIT=20)
write(*,*)ARRAYONE
OPEN(UNIT=30,FILE='TEXTFILE.txt', STATUS='REPLACE', ACTION='WRITE')
WRITE(30,*)ARRAYONE
END PROGRAM test_performance
There is no error when I compile it. The point is that the array ARRAYONE as well as the file TEXTFILE.txt are empty.
The file testfile.txt Looks like this:
1 2 3 4 5 6 7 8 9 10 11
I have got a book in front of me according to which this should actually work. What puzzles me is the fact that if I put just one number in the input file, i.e., 1, and I want to write it on an integer, there is no problem and everything works fine :o!
In the vainglorious pursuit of rep, and with the noble intention that this question get an answer
You can't automatically allocate an array in a read statement, the rules forbid it (or, if you prefer, do not make allowance for it). You could either:
allocate the array to some size that you expect to be large enough, populate it with a guard value unlikely to be found in your inputs, and then read the data you have into the first n elements; or
read the data, figure out how many elements there are, allocate the array to that size, pass the data to the array; you could do this in two passes over the input file (one to determine the contents, the second to read it) or you could get clever and read the data into, say, a large string and parse it to find out how many numbers it contains (so simple it's scarcely worthy of the name 'parsing').
There are other ways, I'm sure you can think of some.

Fortran: Array of arbitrary dimension?

If I want to create an allocatable multidimensional array, I can say:
program test
real, dimension(:,:), allocatable :: x
integer :: i,j
allocate(x(5, 5))
do i = 1,size(x,1)
do j = 1,size(x,2)
x(i,j) = i*j
end do
end do
write(*,*) x
end program test
However, what if I don't know how many dimension x will be. Is there a way to accommodate that?
Newer compilers allow the use of assumed-rank objects for interoperability.
I think that is what you are looking for. But this is for call to functions or subroutines. The function or subroutine declares the dummy argument as assumed-rank and the actual rank is passed with the actual argument at runtime.
Example from IBM website:
REAL :: a0
REAL :: a1(10)
REAL :: a2(10, 20)
REAL, POINTER :: a3(:,:,:)
CALL sub1(a0)
CALL sub1(a1)
CALL sub1(a2)
CALL sub1(a3)
CONTAINS
SUBROUTINE sub1(a)
REAL :: a(..)
PRINT *, RANK(a)
END
END
follow this or that for more details
It looks to me like you're trying to carry out stencil computations across an array of rank-1, -2 or -3 -- this isn't quite the same as needing arrays of arbitrary rank. And assumed-rank arrays are really only applicable when passing an array argument to a routine, there's no mechanism even in the forthcoming standard for declaring an array to have a rank determined at run-time.
If you're impatient to get on with your code and your compiler doesn't yet implement TS 29113:2012 perhaps the following approach will appeal to you.
real, dimension(:,:,:), allocatable :: voltage_field
if (nd == 1) allocate(voltage_field(nx,1,1))
if (nd == 2) allocate(voltage_field(nx,ny,1))
if (nd == 3) allocate(voltage_field(nx,ny,nz))
Your current approach faces the problem of not knowing, in advance of knowing the number of dimensions in the field, how many nearest-neighbours to consider in the stencil, so you might find yourself writing 3 versions of each stencil update. If you simply abuse a rank-3 array of size nx*1*1 to represent a 1D problem (mutatis mutandis a 2D problem) you always have 3 sets of nearest-neighbours in each stencil calculation. It's just that in the flattened dimensions the nearest neighbour is, well, either a ghost cell containing a boundary value, or the cell itself if your space wraps round.
Writing your code to work always in 3 dimensions but to make no assumptions about the extent of at least two of them will, I think, be easier than writing rank-sensitive code. But I haven't given the matter a lot of thought and I haven't really thought too much about its impact on your f-d scheme.

Resources