How to write matrix row by row with implied do loop? [duplicate] - fortran

This question already has answers here:
Formatted reads and implied do
(2 answers)
Fortran output on two lines instead of one
(2 answers)
Closed 2 years ago.
My IDE is CodeBlocks with MinGW 9.2.0.
I need a help with writing matrix row by row in textual file.
This is my simple code:
program matrix
integer :: i, j
integer, dimension(2,2) :: a_mat
forall( i = 1 : 2, j = 1, 2 )
a_mat(i,j) = i + j
end forall
open( unit = 15, file = 'matrix_utput.txt', action = 'write' )
write(15,'(*(i2.2,1x))') ( ( a_mat(i,j), j = 1, 2 ), i = 1, 2 )
close( unit = 15 )
end program matrix
In my .txt file i got this:
02 03 03 04
How to change format to get this:
02 03
03 04

The normal way is to loop in a do loop line by line as shown at Write matrix with Fortran
But one can also do it in an implied loop using format reversion.
write(15,'(2(i2.2,1x))') ( ( a_mat(i,j), j = 1, 2 ), i = 1, 2 )
Basically, the number in front of the parenthesis must be the row length (number of columns). If you put the * there, it will consume the whole array. This way, it will open a new record each time the format found all its items.

Related

Declaration of 1D array with nonlinear functionality between boundaries

This is my code:
Program Arrays_0
Implicit none
Integer :: i , Read_number , Vig_Position , Vipg_Position , n_iter
Integer , parameter :: Br_gra = 12
Integer , parameter , dimension ( Br_gra ) :: Vig = [ ( i , i = 1 , Br_gra) ]
Integer , parameter , dimension ( Br_gra ) :: Vipg = [ 0 , 1 , 1 , 1 , 2 , 2 , 3 , 4 , 4 , 7 , 7 , 7 ]
Integer :: Result_of_calculation
Write(*,*)"Enter the number (From 1 to Br_gra):"
Read(*,*) Read_number
Vig_Position = Vig(Read_number)
Vipg_Position = Vipg(Vig_Position)
!K_str( Vig_Position_temp ) = Vig_Position_temp + 2.3
n_iter = 0
Result_of_calculation = Vig_Position
Do while( Vipg_Position .ne. Vipg(1) )
n_iter = n_iter + 1
Vig_Position = Vipg_Position
! K_str( Vig_Position_temp ) = Vig_Position_temp + 2.3
Result_of_calculation = Result_of_calculation + Vig_Position
Vipg_Position = Vipg(Vig_Position)
End Do
Write(*,'(a,1x,i0)')"The number of iteration is:",n_iter
Write(*,'(a,1x,i0)')"The result of calculation is:",Result_of_calculation
End Program Arrays_0
There is no problem with code if I want to make calculation for a n_iter and Result_of_calculation but I have a problem with declaration of K_str in way that can follow correctly specific use of this two variables (my intention for using this variables in calculation was showed in comments).
So question is how to declare, for example, in case that Read_number is 12?
In that case I have: K_str(12), K_str(7), K_str(3) and K_str(1).
What I can do is this:
Real, dimension (Br_gra):: K_str
But in this case a must import one more loop for all elements from Vig (12 calculation). I want to prevent that number of calculation and in this case, I want to that my code make just a 4 calculation.
How to do that?
So you want to get an array, which e.g. starts at index 1, ends at index 12, but does not contain all the indexes in between, just some of them?
That is not possible with Fortran arrays. Actually, it is not possible with arrays in any other language I know.
One can use the dictionary data structure for something like that, which is intrinsic in some languages, but not Fortran. There are external libraries for similar data-structures in Fortran. See http://fortranwiki.org/fortran/show/Hash+tables
You could also use a linked list with all usual drawbacks and advantages (no direct indexing etc.).
Unless your need is for some very large ranges of indexes, much much larger than your example, use a regular array that contains all indexes.
You can also use one array which will contain the data (indexed 1 to 4) and another array of the same size, which will contain the global position (1,3,7 and 12). Or a derived type with these two components. But it will not be the same usage as you propose.

PETSC DMDA vec values are assigned to wrang place

I recently started learning PETSc and encountered a problem while trying to accomplish some simple task. What is wrong with this code:
static char help[] = "Test 2d DMDAs Vecs.\n\n";
#include <petscdm.h>
#include <petscdmda.h>
#include <petscsys.h>
PetscReal process_value(int rank, int i) {
return i*PetscPowScalar(10,rank*2);
}
int main(int argc,char **argv) {
PetscErrorCode ierr;
PetscMPIInt rank;
PetscInt M = -5,N = -3;
DM da;
Vec local,global;
ierr = PetscInitialize(&argc,&argv,(char*)0,help);CHKERRQ(ierr);
ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);
ierr = DMDACreate2d(PETSC_COMM_WORLD , DM_BOUNDARY_NONE , DM_BOUNDARY_NONE
, DMDA_STENCIL_BOX , M , N , PETSC_DECIDE, PETSC_DECIDE
, 1 , 1 , NULL , NULL , &da); CHKERRQ(ierr);
ierr = DMCreateGlobalVector(da,&global);CHKERRQ(ierr);
ierr = DMCreateLocalVector(da,&local);CHKERRQ(ierr);
{
PetscInt v,i, j, xm, ym, xs, ys;
PetscScalar **array;
ierr = DMDAGetCorners(da, &xs, &ys, 0, &xm, &ym, 0); CHKERRQ(ierr);
PetscSynchronizedPrintf(PETSC_COMM_WORLD,"%d:xs=%d\txm=%d\tys=%d\tym=%d\n",rank,xs,xm,ys,ym);
PetscSynchronizedFlush(PETSC_COMM_WORLD,PETSC_STDOUT);
ierr = DMDAVecGetArray(da, global, &array); CHKERRQ(ierr);
v=0;
for (j = ys; j < ys + ym; j++) {
for (i = xs; i < xs + xm; i++) {
array[j][i] = process_value(rank,v+=1);
}
}
ierr = DMDAVecRestoreArray(da, global, &array); CHKERRQ(ierr);
}
ierr = VecView(global,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
ierr = VecDestroy(&local);CHKERRQ(ierr);
ierr = VecDestroy(&global);CHKERRQ(ierr);
ierr = DMDestroy(&da);CHKERRQ(ierr);
ierr = PetscFinalize();
return 0;
}
It fills small array with quantities labeled by process rank.
After successful compilation and linking it gives the following result:
> mpiexec -n 2 ./problem
0:xs=0 xm=3 ys=0 ym=3
1:xs=3 xm=2 ys=0 ym=3
Vec Object: 2 MPI processes
type: mpi
Vec Object:Vec_0x84000004_0 2 MPI processes
type: mpi
Process [0]
1.
2.
3.
100.
200.
4.
5.
6.
300.
Process [1]
400.
7.
8.
9.
500.
600.
>
VecView shows that processes have written to places that belong to other process. Where is an error? DMDAVecGetArray/DMDAVecRestoreArray give wrong array or VecView is not suitable to view Vec obtained from DM object ?
DMDAVecGetArray() and DMDAVecRestoreArray() work perfectly fine. Indeed, you are dealing with a feature of VecView() described in the mailing list of petsc a few years ago.
As is, VecView() prints the vector from the DMDA using the natural ordering.
proc0 proc1
1 2 | 3 4
5 6 | 7 8
___________
9 10 | 11 12
13 14 | 15 16
proc2 proc3
The difference between the natural ordering and Petsc's ordering is underlined in the documentation of Petsc, in section 2.5 about structured grids. Here is what Petsc's ordering looks like:
proc0 proc1
1 2 | 5 6
3 4 | 7 8
___________
9 10 | 13 14
11 12 | 15 16
proc2 proc3
As signaled in the thread VecView doesn't work properly with DA global vectors, it is still possible to print the vector using Petsc's ordering by using:
PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_NATIVE);
VecView(global,PETSC_VIEWER_STDOUT_WORLD);
PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);
Let's take a closer look to the source of Petsc to see how it works. The VecView() operation for DMDA vector is overloaded as the DMCreateGlobalVector_DA() function is called (see dadist.c): the new method is VecView_MPI_DA() in gr2.c. Unsurprisingly, it calls a function DMDACreateNaturalVector() and later prints the natural vector using the native VecView(). If the format PETSC_VIEWER_NATIVE is used, the vector interface calls the operation *vec->ops->viewnative, which likely points to the native VecView() function VecView_MPI_ASCII() in pdvec.c. This explains the strange ( but very practical! ) behavior of VecView for DMDA vectors.
If you wish to keep the natural ordering, you can revome the meaningless Process[0]...Process[3] that get printed by using:
PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_COMMON);

How to read data from multiple files and write into columns of a single file

I'm completely new in Fortran and I need to write some relatively simple codes.
I have some files (various, for example 200 files); each file for the specific node, with some simplification, each file contains:
T(i), X(i)
these are my input and I want to have an output file contain:
T(i) X(i)1 X(i)2 ... X(i)n
the problem is that I can't separate data in different columns of output file, they comes all after each other in 1 column.
My code is :
PROGRAM Output
implicit none
integer ::nn,n,i,j,l
real,dimension(:),allocatable::t,x,y,z
character(len=10)::TD
open(11,file='outputX.txt')
allocate (t(1000),x(1000),y(1000),z(1000))
n=5 ! Number of Files
nn=50 ! Number of Rows in each File
Do i=1,n ! loop for opening different files
write(TD,10)i
write(*,*)TD
open(1,file=TD)
Do l=1,nn ! loop for reading rows in each file
read(1,*)t(j),x(j)
write(11,*)x(j) !!!! This is my PROBLEM, all the data shows in
! one column, I want each file in separately
Enddo
Enddo
10 format('100',i3.3,'')
deallocate(x,y,z,t)
END PROGRAM Output
The output I get is like this :
11
12
13
21
22
23
31
32
33
But in fact I want :
11 21 31
12 22 32
13 23 33
There are several problems with your code
Do i=1,n ! loop for opening different files
write(TD,10)i
write(*,*)TD
open(1,file=TD)
Do l=1,nn ! loop for reading rows in each file
read(1,*)t(j),x(j)
write(11,*)x(j) !!!! This is my PROBLEM, all the data shows in
! one column, I want each file in separately
End do
End do
The index j is completely undefined. You should put j=1 or 0 and j=j+1 somewhere inside the loop.
The other issue is your output. You are reading the files in sequence. It is very hard to print each file into a separate column. A separate row for each file is easy:
write(11,*) x(1:nn)
after the inner loop.
Or with finer control and avoiding a line wrap
write(11,'999(g0,1x)') x(1:nn)
(g0 is a general edit descriptor which uses only the necessary width). This will only work if you fix the j issue I mentioned above!
To put it into separate columns you must
Open all files at the same time, then read from each of them and print the read data in a single write command.
or
Store all the data from all files into separate columns in a 2D array and print the 2D array afterwards.
So what I got is x(1) belongs to 11, x(2) belongs to 12, x(3) belongs to 13 and so on, isn't it? You could try this one:
write(11,100) x(j), x(j+3), x(j+6)
100 format(1X,11F20.4,11F20.4,11F20.4)
The 2D array... for this problem it is backwards
But it should give you some help... (Hopefully)
PROGRAM Output
IMPLICIT NONE
INTEGER, PARAMETER :: nfiles = 5
INTEGER, PARAMETER :: nrows = 50
integer :: iFile, iRow !File and row counter/#
real,dimension(:,:),allocatable :: t,x,y,z !The are now 2D
INTEGER,dimension(nFiles) :: lFile !logical file indexed by file#
LOGICAL,dimension(nFiles) :: Open4Biz !logical for closing
character(len=10)::TD !Unsure about this
open(11,file='outputX.txt')
allocate (t(iRow,iFile),x(iRow,iFile),y(iRow,iFile),z(iRow,iFile))
Open4Biz(:) = .FALSE. !Initialize
!n=5 ! Number of Files ^^Moved up/renamed^^
!nn=50 ! Number of Rows in each File ^^Moved up/renamed^^
Files_Loop1: Do iFile = 1, nFiles !I think that the loop identifier is std f95 (std ifort anyhow)
write(TD,10) iFile !Unsure about this
write(*,*)TD
lFile(iFile) = 10+iFile
open(lFile(iFile),file=TD) !Probably put in some logic if the file is not found
Open4Biz(iFile) = .TRUE.
ENDDO Files_Loop1
Rows_Loop: Do iRow = 1, nn !The loops are backwards from normal
Files_Loop2: Do iFile = 1, nFiles
read(lFile(iFile),*) t(iRow, iFile), x(iRow, iFile)
Enddo Files_Loop2
write(11,*) x(iRow,:)
Enddo Rows_Loop
10 format('100',i3.3,'')
667 CONTINUE !This is label to 'jump to' from a bad open
Files_Loop3: Do iFile = 1, nFiles
IF(Open4Biz(iFile) CLOSE(lFile(iFile))
ENDDO Files_Open_Loop
IF(ALLOCATED(X)) deallocate(x)
IF(ALLOCATED(Y)) deallocate(y)
IF(ALLOCATED(Z)) deallocate(z)
IF(ALLOCATED(T)) deallocate(t)
END PROGRAM Output

Reading a sequence of integer in a line with unknown bound in fortran

I would like to read a sequence of integer in a line with unknown bound in FORTRAN. My question is similar to the following previous post,
Reading a file of lists of integers in Fortran
however I want to read a sequence of unknown numbers of integer in a line and save it in separate arrays. And successive lines of integer should be saved to some other array
My file looks like this
5 7 8 9 10 13 # should be stored f(1)(6) arrays
93 102 92 # c(1)(3)
105 107 110 145 147 112 # f(2)(6)
97 98 # b(1)(2)
12 54 55 # c(2)(3)
15 17 21 23 45 # e(1)(5)
43 47 48 51 62 # d(1)(4)
Thus I have a sequence of integers with maximum length of 6 (to be stored in f array) and minimum length of 2(to be stored in b array). I have hundreds of lines like this, such that I need to classify according to the maximum length and count on them.
Reading a file of lists of integers in Fortran
There are probably many ways to do this, and the following is one such example. Here, the split() makes multiple trials for list-directed input for all values in the line, until non-numeric characters or the end of line is encountered.
subroutine split( line, vals, n )
implicit none
character(*), intent(in) :: line
real*8 :: vals(*), buf( 100 ) !! currently up to 100 items (for test)
integer :: n
n = 1
do
read( line, *, end=100, err=100 ) buf( 1 : n ) !! (See Appendix for why buf is used here)
vals( 1:n ) = buf( 1:n )
n = n + 1
enddo
100 continue
n = n - 1
end
program main
implicit none
character(200) :: line
real*8 :: vals( 100 )
integer :: n
open( 10, file="test.dat", status="old" )
do
read( 10, "(a)", end=500 ) line
call split( line, vals, n )
if ( n == 0 ) then
print *, "comment line"
else
print *, nint( vals( 1 : n ) )
endif
enddo
500 continue
close( 10 )
end
If test.dat contains the whole lines in the Question, plus the following lines
# additional data
1,2,3 , 4 , 5 # comma-separated integers
1.23e2 -4.56e2 , 777 # integer/floating-point mixed case
it gives
comment line
5 7 8 9 10 13
93 102 92
105 107 110 145 147 112
97 98
12 54 55
15 17 21 23 45
43 47 48 51 62
comment line
1 2 3 4 5
123 -456 777
So one can save the result for each line by copying the values in vals(1:n) to a desired array.
[ Appendix (thanks to #francescalus) ]
In the above code, the data are read once into buf(1:n) and then copied to vals(1:n). One might think that it would be more direct to read in the data into vals(1:n) such that
read( line, *, end=100, err=100 ) vals( 1 : n )
However, this direct approach is not recommended because vals(1:n) becomes undefined when the read statement hits the "end" or "err" condition. Although ifort and gfortran seem to retain the data in vals(1:n) even when that condition is met (and so they work even with the direct approach), the same behavior cannot be guaranteed for other compilers. In contrast, the buffer approach avoids this risk by saving the data one step before to vals(1:n), so that undefined data are not used. This is why the buffer approach is used in the above code despite it is one statement longer.
Something like this might satisfy your requirements
INTEGER :: ix, rdstat
INTEGER, DIMENSION(6) :: nums
CHARACTER(len=128) :: aline
...
OPEN(21,file='data.txt')
DO ix = 1,10
READ(21,'(a)',iostat=rdstat) aline
IF (rdstat/=0) catch_errors()
nums = -99 ! a guard
READ(aline,*,iostat=rdstat) nums
IF (rdstat/=0) catch_errors()
! do something with nums
END DO
CLOSE(21)
I haven't thoroughly tested this and I haven't written catch_errors for you -- in practice you may not want to do very much. This first version is probably too brittle, but whether it's suitable or not depends heavily on the uniformity (or otherwise) of the input files.
The strategy is to read each line into a character variable (one long enough for the entire line) and then to use internal, list-directed, reading to read 6 integers from the start of the character variable. This takes advantage of the in-built facility that list-directed input has of finding integers in an input stream with spaces separating values. The approach should work as well with a comma-separated list of integers. The internal read only looks for 6 integers, then catches the error when either no more integers are found, or only material which cannot be interpreted as integers (such as strings like # comment).
Note
I've assumed a maximum line length of 128 characters, you may want to adjust that.
I've specified a fixed upper limit on the number of lines the program will read. You may want to change that, or change to a do/while loop.
The program expects no more than 6 integers in a line, as your question specifies.
At each line read the array nums is filled with -99 at each element; this is a 'guard'. If -99 is likely to occur in your input files you may want to change this.
It's entirely up to you what you do with the numbers in nums once you have them.

Formatting 2D Arrays in a fortran namelist input file

Im writing a namelist input file for a Fortran code. I know that if you have a 1D array, you can populate a range of elements by,
&namelist
array(10) = 0, 1, 2, ......., n
&END
is the equivalent of
&namelist
array(10) = 0
array(11) = 1
array(12) = 2
...
array(10 + n) = n
&END
I need to now write a 2d array. I want to do the shortest equivalent to
&namelist
array2d(1,1) = 1
array2d(1,2) = 2
&END
Can I write that as
&namelist
array2d(1) = 1, 2
&END
or do I need to write this as
&namelist
array2d(1,1) = 1, 2
&END
Wow, thanks for the question -- never heard of namelists before :) This is useful!! :) After a little testing, older gfortran versions have a problem with this. Let's say you have
program nltest
implicit none
integer :: a(3,3)
namelist /mylist/ a
a = 0
open(7, file='nlinput.txt')
read(7, nml = mylist)
write(*,*) a
end program nltest
read a whole array, a=1,2,3,4,5,6,7,8,9 : this works fine and reads a(1,1), a(2,1), ... as expected regardless of the compiler.
read an array slice, e.g. a(2,:)=1,2,3 : this works fine with ifort and gfortran 4.6.1, but with gfortran 4.3 it does not.
So to do what you want you should be able to write array2d(1,:) = 1,2 if the code is compiled with a recent compiler.