How to remove random rows from a matrix in Fortran90 - arrays

OK so here is the problem. In my assignment I should create a (3,1000) matrix and after I created it I should delete RANDOMLY 271 rows of the matrix. At the end I should obtain a (3,729) Matrix with all the initial values except the one I deleted corresponding to the random numbers.
To do so I wrote this script where
Mc=1000
N=729
h=1
do a=1, (Mc-N)
call random_number(rand_num)
rand_num=int(rand_num*Mc)-1
!print*, rand_num
do b=1, Mc
if (b /= rand_num) then
NMatrix(:,h) = Matrix(:,b)
h=h+1
else
h=h
endif
enddo
enddo
But when I run it it reports me this error: Program receiver signal SIGABRT : Process abort signal.
What should I do? Please it's really important
I know there is some problem with the do loops and the memory of the arrays, but I cannot get to the point. Can you please ask me?

Here an example ouput of what you are asking for (I think).
rows=3, cols=1000
1.000 2.000 3.000 4.000 5.000 6.000 7.000 8.000 9.000 10.00 11.00 12.00 ...
1001. 1002. 1003. 1004. 1005. 1006. 1007. 1008. 1009. 1010. 1011. 1012. ...
2001. 2002. 2003. 2004. 2005. 2006. 2007. 2008. 2009. 2010. 2011. 2012. ...
rows=3, cols=729
1.000 3.000 4.000 9.000 10.00 11.00 12.00 13.00 14.00 16.00 17.00 19.00 ...
1001. 1003. 1004. 1009. 1010. 1011. 1012. 1013. 1014. 1016. 1017. 1019. ...
2001. 2003. 2004. 2009. 2010. 2011. 2012. 2013. 2014. 2016. 2017. 2019. ...
Note that by convention, the 1st index is the rows, and the 2nd index is the columns. So you are asking to remove 271 columns from the matrix.
I decided to use an array of index values indx=[1,2,3,4 .. n], which I shuffle randomly, then slice off the last 271 values (keep n entries) and then sort back to increasing order.
Finally, the result is essentially NMatrix(:,:) = Matrix(:, indx) or in my case I call them a and b in my function.
function RemoveRandomColumns(a,n_col) result(b)
real, intent(in) :: a(:,:)
integer, intent(in) :: n_col
real, allocatable :: b(:,:)
integer :: i,j,n,m,t
integer, allocatable :: indx(:)
real :: u !used in shuffle part
m = size(a, 1)
n = size(a, 2)
! must remove m-n_col columns from a
allocate(indx(n))
indx = [ (i,i=1,n) ]
! indx = [1,2,3,4,5,6,7,8,..,n]
! suffle the index
call RANDOM_SEED()
do i=1, n
call RANDOM_NUMBER(u)
j = 1 + floor(u*(n-1))
t = indx(i)
indx(i) = indx(j)
indx(j) = t
end do
! indx = [18,10,3,16,21,...]
! take only n_col items
indx = indx(1:n_col)
! indx = [18,10,3,...]
! sort the index
do i=1, n_col
do j=1, i-1
if(indx(i)<indx(j)) then
t = indx(i)
indx(i) = indx(j)
indx(j) = t
end if
end do
end do
! indx = [2,3,4,6,7,9,..,n]
! now slice the array to get the resukt
allocate(b(m,n_col))
do j=1, m
b(j,:) = a(j,indx)
end do
end function
and the sample code to test the above is
program FortranProgram1
use, intrinsic :: iso_fortran_env
implicit none
integer, parameter :: Mc = 1000, n = 729
! Variables
real :: matrix(3, Mc)
real :: reduced(3, n)
integer :: i,j
do j=1, 3
do i=1, Mc
matrix(j,i) = real(Mc*(j-1)+i)
end do
end do
print '("rows=",g0,", cols=",g0)', size(matrix,1), size(matrix,2)
print '(*(g0.4," "))', matrix(1,1:12), "..."
print '(*(g0.4," "))', matrix(2,1:12), "..."
print '(*(g0.4," "))', matrix(3,1:12), "..."
print *, ""
reduced = RemoveRandomColumns(matrix, n)
print '("rows=",g0,", cols=",g0)', size(reduced,1), size(reduced,2)
print '(*(g0.4," "))', reduced(1,1:12), "..."
print '(*(g0.4," "))', reduced(2,1:12), "..."
print '(*(g0.4," "))', reduced(3,1:12), "..."
contains
function RemoveRandomColumns(a,n_col) result(b)
...
end function
end program

Related

Nested Do and Do while Fortran loops

I'm writing this small program that stores grades in an array and then averages them. The program is supposed to accept up to 10 grades and stop and only accept grades that are > 0 and < 100. Here is my code:
program Average
implicit none
character(len = 50) f_name, l_name
integer i, j, amtOfGrades
real grade, arraySum, avg
Real, Dimension(10)::a
do i = 1, 10
if(.not. (j .LE. 100 .AND. j .GE. 0)) then
write(*,*)'Enter grade: '
read(*,*)a(i)
j = a(i)
arraySum = sum(a)
avg = arraySum/10
else
avg = arraySum/(i-1)
end if
end do
The problem I'm having is with the nested loop section. I cannot get the two conditions I need to work together, which are only up to 10 grades (what the DO is for) AND only accepting grades that in the range of 0-100 (what the DO WHILE is for).
You need to issue an exit statement to quit the loop before the max of 10 grades is entered:
program Console1
use, intrinsic :: iso_fortran_env
implicit none
! Variables
integer, parameter :: maxcount = 10
real :: a(maxcount), ave
integer :: i, count
count = 0
do i = 1, maxcount
write(*,*) 'Enter grade: '
read(*,*) a(i)
if( a(i)<=0.0 .or. a(i)>=100.0) then
exit
end if
count = count + 1
end do
ave = sum(a)/count
write(*,*) 'The average is: ', ave
end program Console1
If you look in help you will see
The EXIT statement causes execution of a DO loop or a named construct to be terminated.
How to do this will depend on what you want to do if an input grade is not 0 <= grade <= 100. Does such an input count towards the limit of 10 grades?
If a bad input does count towards the limit, then you will only need to read from the user 10 times, but you might end up with less than 10 grades total. So you will need to keep track of how many grades have been entered.
Code for this might look like:
program average
implicit none
integer :: i, amtOfGrades
real :: grade, arraySum, avg
real, dimension(10) :: a
amtOfGrades = 0
do i=1,10
write(*,*) 'Enter grade: '
read(*,*) grade
if (0<=grade .and. grade<=100) then
amtOfGrades = amtOfGrades + 1
array(amtOfGrades) = grade
endif
end do
arraySum = sum(a(:amtOfGrades))
avg = arraySum/amtOfGrades
end program
If instead a bad input does not count towards the limit then you will always end up with 10 grades, but you might have to read from the user an infinite number of times.
Code for this might look like:
program average
implicit none
integer :: i
real :: grade, arraySum, avg
real, dimension(10) :: a
do i=1,10
do
write(*,*) 'Enter grade: '
read(*,*) grade
if (0<=grade .and. grade<=100) then
array(i) = grade
exit
endif
enddo
end do
arraySum = sum(a)
avg = arraySum/10
end program

How to do SUM on array from outside file?

I'm newbie college student for programming studies,
so recently i have task to calculate matrix from outside files for Gauss Jordan Numeric Method, in the txt file i provide has 10 (x) and (y) data, and declare with do functions to calculate the 10 data from the txt file each for x^2, x^3, x^4, xy, x^2y
my question is : how to SUM (calculate total) each x^2, x^3 ... that was calculated by program ? i try do sum file in below and still got errors (the first argument of sum must not a scalar.)
the Fortran apps i use was Plato cc from Silverfrost.
I apologize if my english bad and my pogram looks funny.
i have 10 data in my txt looks like these :
(x) (y)
12 10
5 6
28 8
9 11
20 17
6 24
32 9
2 7
1 30
26 22
in program below i open these files and want each x and y i provide read and calculate to get x^2, x^3, x^4, xy, x^2y
Program Gauss_Jordan
Real x(10),y(10),xj,yj,xj2,xj3,xj4,xjyj,xj2yj
Open (10, file='Data.txt')
Do j = 1,10
Read(10,*) x(j), y(j)
xj2 = x(j)**2
xj3 = x(j)**3
xj4 = x(j)**4
xjyj = x(j)*y(j)
xj2yj = (x(j)**2)*y(j)
Do k = 1,10
T(xj2) = SUM( xj2, dim=1)
T(xj3) = SUM (xj3, dim=1)
T(xj4) = SUM (xj4, dim=1)
T(xjyj) = SUM (xjyj, dim=1)
T(xj2yj) = SUM (xj2yj, dim=1)
End Do
End Do
Close(10)
End
for T(xj2) I want to get one result scalar result from SUM the all xj^2 that program has been calculated.
Like in excel was expected :
(A) is 1st xj^2 value that has been calculated
.
.
.
until (J) is 10th xj^2 value that has been calculated
sxj^2 = SUM(Xj^2)
SUM (A-J)
The 'sum' intrinsic needs an array argument, which we can compute from the input arrays without using a loop, so your program could be:
Program Gauss_Jordan
Real x(10), y(10), x2(10), x3(10), x4(10), xy(10), x2y(10)
Open(10, file='Data.txt')
Do j = 1, 10
Read (10, *) x(j), y(j)
End Do
Close(10)
x2 = x**2
x3 = x**3
x4 = x**4
xy = x*y
x2y = (x**2)*y
sx2 = SUM(x2)
sx3 = SUM(x3)
sx4 = SUM(x4)
sxy = SUM(xy)
sx2y = SUM(x2y)
End
From what I see I think you are misunderstanding what the SUM intrinsic does. Since your example isn't storing xj2, xj3 etc. in arrays, SUM isn't going to be useful to you. Instead you could declare totals as scalars (as you described you wanted) and simply add the individual xj2 variables in a loop as in the example below.
Also, you should get in the habit of using the implicit none declaration. It will save you from unexpected errors due to spelling mistakes.
Program Gauss_Jordan
implicit none
Real x(10),y(10),xj,yj,xj2,xj3,xj4,xjyj,xj2yj
real :: Txj2,Txj3,Txj4,Txjyj,Txj2yj
integer :: j
Txj2 = 0
Txj3 = 0
Txj4 = 0
Txjyj= 0
Txj2yj= 0
Open (10, file='Data.txt')
Do j = 1,10
Read(10,*) x(j), y(j)
xj2 = x(j)**2
xj3 = x(j)**3
xj4 = x(j)**4
xjyj = x(j)*y(j)
xj2yj = (x(j)**2)*y(j)
Txj2 = Txj2 + xj2
Txj3 = Txj3 + xj3
Txj4 = Txj4 + xj4
Txjyj = Txjyj + xjyj
Txj2yj = Txj2yj + xj2yj
End Do
print *, 'Txj2 = ', Txj2
Close(10)
End
When I ran this I got the output below which is what I believe you intended:
3175

Fortran 90 Reading in Characters and Integers from a data file

Ok, so In my program I'm supposed to take in the name of the data file from the user than open it and read the contents. But when I open and read it all that characters just end up being ****** and all the integers end up being 0. IDK if it's how I'm reading in the file or the format?
The file will contain something like this: (where the number of cities is the first number)
4
SanDiego
0
350
900
1100
Phoenix
350
0
560
604
Denver
900
560
0
389
Dallas
1100
604
389
0
So far my code is this where first I take in the first number than on every firstnumber * I + I pass is supposed to go into the character array city. Now the rest of the numbers I am storing into a integer array, but really want it into a integer matrix called d_table but I couldn't think of a way to do that immediately on the read.
PROGRAM p4
IMPLICIT NONE
INTEGER :: number, status, I, J, K, permutation = 0, distance = 0, distance = 999999
CHARACTER(50) :: filename ! Filenames longer than 50 are truncated
CHARACTER(20), DIMENSION(10) :: city
INTEGER, DIMENSION(100) :: temp
INTEGER, DIMENSION(10,10) :: d_table
INTEGER, DIMENSION(10) :: path, best_path
WRITE (*, '(1x,A)', ADVANCE="NO") "Enter filename: "
READ *, filename
! Open the file we created and read the contents
OPEN(UNIT=15, FILE=filename, STATUS="OLD", ACTION="READ",&
IOSTAT=status)
IF(status /= 0) THEN
PRINT *, "ERROR, could not open file for reading."
STOP
END IF
READ (UNIT=15, FMT = 100, IOSTAT=status) number
J = 0
K = 0
DO I = 0, number*number
IF(I == J*number+J) THEN
READ (UNIT=15, FMT = 200, IOSTAT=status) city(J)
J = J + 1
ELSE
READ (UNIT=15, FMT = 100, IOSTAT=status) temp(K)
K = K + 1
END IF
END DO
K = 0
DO I = 0, number
DO J = 0, number
d_table(I,J) = temp(K)
K = K + 1
END DO
END DO
100 FORMAT(I6)
200 FORMAT (A)
END PROGRAM p4
This line
DO I = 0, number*number
looks wonky to me; the loop will be executed 17 times. Surely you want to read number groups of 5 lines, each group being one city name followed by four integers ? That would be a good case for a little loop nest, something like
do ix = 1, number
read(15,*) city(ix)
do jx = 1, 4
read(15,*) d_table(ix,jx)
end do
end do
Given such a simple input file format there's no need to bother with format statements, list-directed input will work just fine.
I can't see the point of all the index arithmetic the code is doing, perhaps I've missed something.

Fortran: How to conduct a job repeatedly using multiple files

Project description:
I have the coordinates of McDonalds in cities and the coordinates of city centers. They are divided to text files by city. For example,
=== atlanta_mc.txt === === houston_mc.txt === ... (for 200 cities)
[latitude] [longitude] [latitude] [longitude] <-- The headers are not written in the files.
33.5431140 -84.5766910 29.8044570 -95.3990780
34.0489350 -84.0928960 30.0051170 -95.2834550
33.7853660 -84.1018980 29.7371140 -95.5352550
34.0903210 -84.2040180 29.7280160 -95.4188230
34.1606520 -84.1781010 29.7851700 -95.3609770
.... ....
My goal is to calculate the distance between the city center and each McDonald for each city. The city center data file has [cityname],[latitude],[longitude] fiels. It looks like:
== city_centers.txt ==
[city name] [latitude] [longitude] <-- The headers are not written in the file.
atlanta 33.79526 -84.326528
la 34.057453 -118.413842
ny 40.759347 -73.980202
houston 29.733215 -95.430824
....
(for 200 cities in the US.)
Fortran code:
For one city (say, Atlanta), I can do the job as follows:
program mcdonalds
implicit none
interface
function distkm(deglat1,deglon1,deglat2,deglon2)
real :: distkm
real, intent(in) :: deglat1,deglon1,deglat2,deglon2
end function distkm
end interface
integer, parameter :: maxnr = 200
integer :: nr, i, j, ios
character(len=1) :: junkfornr
real, dimension(:), allocatable :: lat, lon
! Obtain the total number of observations
nr=0
open(10, file='atlanta_mc.txt', status='old')
do i=1,maxnr
read(10,*,iostat=ios) junkfornr
if (ios/=0) exit
if (i == maxnr) then
stop
endif
nr = nr + 1
end do
allocate(lat(nr))
allocate(lon(nr))
rewind(10)
do i=1,nr
read(10,*) lat(i), lon(i)
end do
open(20,file='RESULT_atlanta_mc.txt')
do i=1,nr
write(20,100) "atlanta",lat(i),lon(i),distkm(lat(i),lon(i),33.79526,-84.326528)
100 format(A,3F12.6)
end do
end program mcdonalds
function distkm(deglat1,deglon1,deglat2,deglon2)
implicit none
real, intent(in) :: deglat1,deglon1,deglat2,deglon2
real :: pi,dlat,dlon,lat1,lat2,a,distkm
pi = 4*atan(1.0)
dlat = (deglat2-deglat1)*pi/180
dlon = (deglon2-deglon1)*pi/180
lat1 = deglat1*pi/180
lat2 = deglat2*pi/180
a = (sin(dlat/2))**2 + cos(lat1)*cos(lat2)*(sin(dlon/2))**2
distkm = 6372.8*2*atan2(sqrt(a),sqrt(1-a))
end function distkm
Problem:
I have to do this for the all cities. So, I have to change (1) the McDonalds data file, (2) the city center coordinate; and (3) the result file for each city accordingly. How do I have to write a program to iterate this process for the whole 200 cities? I use Intel Fortran (ifort) to compile it.
EDIT (This code worked -- Friday, April 11, 2014):
! calculate distances from the city center to each McDonald
! Try this for all the cities
program mcdonalds
implicit none
interface
function distkm(deglat1,deglon1,deglat2,deglon2)
real :: distkm
real, intent(in) :: deglat1,deglon1,deglat2,deglon2
end function distkm
end interface
integer, parameter :: maxnr = 200
integer :: nr, i, j, ios
character(len=1) :: junkfornr
character(len=25) :: fn
real, dimension(:), allocatable :: lat, lon
real, dimension(5) :: clat, clon
character(len=15), dimension(5) :: filename
character(len=6), dimension(5) :: code
character(len=7), dimension(5) :: cityname
! I have a text file that contains the list of data file names, city names and the (lat/lon)s of city centers.
! The name of that file: datafilelistcitycenter.txt
! === The content of the file looks like: ===
! atlanta_mc.txt 11111 atlanta 33.79526 -84.326528
! houston_mc.txt 22222 houston 29.733215 -95.430824
! la_mc.txt 33333 la 34.057453 -118.413842
! ny_mc.txt 44444 ny 40.759347 -73.980202
! philly_mc.txt 55555 philly 29.733215 -95.430824
! Let's assume we know the number of the cities.
! In this case, it is 5.
open(10, file='datafilelistcitycenter.txt', status='old')
rewind(10)
do i=1,5
read(10,*) filename(i), cityname(i), clat(i), clon(i)
end do
close(10)
! Obtain the total number of observations for each city
do j=1,5
open(j, file=filename(j), status='old')
nr=0
do i=1,maxnr
read(j,*,iostat=ios) junkfornr
if (ios/=0) exit
if (i == maxnr) then
write(*,*) "Error: Maximum number of records exceeded..."
write(*,*) "Exiting the program..."
stop
endif
nr = nr + 1
end do
allocate(lat(nr),lon(nr))
rewind(j)
do i=1,nr
read(j,*) lat(i), lon(i)
end do
close(j)
write(fn, '("RESULT_",A15)') filename(j)
open(j,file=fn)
do i=1,nr
write(j,100) code(j),cityname(j),lat(i),lon(i),distkm(lat(i),lon(i),clat(j),clon(j))
100 format(A6,A7,3F12.6)
end do
close(j)
deallocate(lat,lon)
end do
end program mcdonalds
function distkm(deglat1,deglon1,deglat2,deglon2)
implicit none
real, intent(in) :: deglat1,deglon1,deglat2,deglon2
real :: pi,dlat,dlon,lat1,lat2,a,distkm
pi = 4*atan(1.0)
dlat = (deglat2-deglat1)*pi/180
dlon = (deglon2-deglon1)*pi/180
lat1 = deglat1*pi/180
lat2 = deglat2*pi/180
a = (sin(dlat/2))**2 + cos(lat1)*cos(lat2)*(sin(dlon/2))**2
distkm = 6372.8*2*atan2(sqrt(a),sqrt(1-a))
end function distkm
No luck. I end up with very weird messages: severe <66>: output statement overflows record, unit -5, file Internal Fomatted Write.
EDIT: I think I got it right. Thanks.
Instead of opening one specific city file such as atlanta_mc.tx, create a file that a list of the filenames of the city. Open that file, add a new loop to your program and read a name of a city file, open and process it as you do now, then close the file. Next iteration of new loop will process the next city file, etc. This is assuming that the cities are in separate files. If they are in one big file, then create arrays to hold information for all of the cities, read all the information into the array, then have a new loop to iterate over the cities.
Also, if you place your function distkm into a module you won't have to bother with having an interface for it. Using modules and easier and less error prone. An example: distkm

write in array format in fortran

I try to write an output file.dat with an nxn matrix format .
I write the code but the output is a column of value f.
Now the problem is: how can i change the output-format of the file to write?
from:
1
2
4
5
...
to: 1,2,3,4 //
5,6,8,.. //
program eccen
implicit none
integer, parameter:: grid=800
integer::i,j,k,n,m
real*8,allocatable::f(:,:)
real*8::xx(grid),yy(grid),mval,Mxval
real*8,allocatable::x(:),y(:)
open(10,file='3d_disk.txt')
n=0
DO
READ(10,*,END=100)
n=n+1
END DO
100 continue
rewind(10)
allocate(x(n),y(n))
do i=1, n
read(10,*) x(i),y(i)
end do
mval=-20.
Mxval=20.
do i=1, grid
xx(i) = mval + ((Mxval - mval)*(i-1))/(grid-1)
yy(i) = mval + ((Mxval - mval)*(i-1))/(grid-1)
end do
open(20,file='3d_map.dat')
allocate(f(n,n))
f=0
do i=1,grid
do j=1,grid
m=0.
do k=1, n
if (x(k) > xx(i) .and. x(k) < xx(i+1) .and. &
& y(k) > yy(j) .and. y(k) < yy(j+1)) then
m=m+1 ! CONTA IL NUMERO DI PARTICELLE
end if
end do
f(i,j)=float(m+1)
I thing that the modification must be here from this:
write(20,*) f(i,j)
end do
write(20,*)
print *,i
end do
end program eccen
to:
do i=1,grid
do j=1,grid
write(20,*) f(i,j)
end do
end do
end do
write(20,*)
print *,i
end do
end program eccen
This statement
write(20,*) f(i,j)
will write the value of f(i,j) then move to the next line, so the file you're getting is exactly what your code is specifying. If you want the file to contain n rows each with n values try
write(20,*) f(i,:)
which ought to make a good stab at writing the whole of row i of the array to a single line in the output file. Of course, this makes your loop over j redundant so you can remove it.

Resources