Fortran 90 Reading in Characters and Integers from a data file - arrays

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.

Related

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

Split a array in VBA and output to multiple columns in Excel

I have a long array that exceeds the maximum number of rows of a single column (1048576), and I wish to output this array into multiple columns, for example, if my array length is 3145728, and so I intend to create 3 separate arrays, each with length 1048576, so 1 to 1048576 would be output to column A, 1048577 to 2097152 to column B, and 2097153 to 3145728 to column C. My code attempted is as follows:
Sub test()
'for simplicity, just created a simply long array
Dim arrIn(1 To 3145728, 1 To 1) As Long
For i = 1 To 3145728
arrIn(i, 1) = i
Next i
'created 3 separate arrays, each with length of 1048576
Dim arrOut1(1 To 1048576, 1 To 1) As Long, arrOut2(1 To 1048576, 1 To 1) As Long, arrOut3(1 To 1048576, 1 To 1) As Long
Dim p As Long, p2 As Long, p3 As Long
'because counter p is going to be from 1 to 3145728, for the second and third arrays, the counter need to restart from 1 and upto 1048576
p2 = 1
p3 = 1
For p = 1 To 3145728
Select Case p
Case Is <= 1048576
arrOut1(p, 1) = arrIn(p, 1)
Case Is <= 2097152
arrOut2(p2, 1) = arrIn(p, 1)
p2 = p2 + 1
Case Is <= 3145728
arrOut3(p3, 1) = arrIn(p, 1)
p3 = p3 + 1
End Select
Next p
Range("A1:A1048576") = arrOut1
Range("B1048577: B2097152") = arrOut2
Range("C2097153:C3145728") = arrOut3
End Sub
The first column (arrOut1) was output to column A, however, when it comes to the second column (arrOut2), VBA returns Run-time error '1004': Menthod 'Range' of object '_Global' failed.
I checked the locals windows results, p2 and p3 were 1048577, and arrOut2(1,1) = 1048577, arrOut2(1,1) = 1048578, and so on, seems the arrays all get populated, however I'm not sure what is prohibiting them from being spitted out to the columns. Thank you for your advice.
Ok so, just realized that Range(“B1048577:B...) was nonsense... so it is solved. Thank you!

How to read and parse a line from file?

There is a file consisted of lines in the following format:
John, D E 100
Bob, F I 200
Oli, G H 1500
...
in general:
string, char char integer
The file needs to be read and stored in two arrays of which the first should store the string and characters1 and the second should store the integer.
How could this be done?
An initial attempt is made here.
1. Concatenated into single string as they are with the comma and the white spaces.
If the items in the input file are delimited by whitespaces or commas, we can read them using list-directed input (fmt=*), as suggested in the comments in the linked question, such that
read (funit, [fmt =] *, iostat = ios) surname, first_name, second_name, consumption
where the part "fmt =" is optional. The following is a slightly modified version of the original code in the linked page (please see comments in the code for more details):
module MyModule
implicit none !<-- this propagates to all routines in this module
contains
subroutine ReadFileIntoArrays (filename, name_arr, kWh_arr, ndata)
character(*), intent(in) :: filename !<-- an assumed-length string
character(*), intent(out) :: name_arr(:) !<-- an array of assumed-length strings
integer, intent(out) :: kWh_arr(:), ndata
character :: first_name, second_name !<-- a single char
character(50) :: surname !<-- a string of 50 chars
integer :: consumption, funit, ios, idx
funit = 10 ! use >= 10 (or open( newunit=funit, ... ) for recent compilers)
open (funit, file = filename, status = 'old')
idx = 0
do
read (funit, fmt = *, iostat = ios) & !<-- "&" means line continuation
surname, first_name, second_name, consumption
! "fmt = *" (list-directed input) tells the compiler
! to use whitespaces/commas as delimiters.
if (ios > 0) then
print *, "Wrong input format!" ; exit
else if (ios < 0) then
print *, "finished reading data." ; exit
else
idx = idx + 1
if (idx > size( name_arr )) stop "size of name_arr(:) too small"
! trim() chops trailing spaces in a string
name_arr( idx ) = trim(surname)//','//first_name//'.'//second_name//'.'
kWh_arr( idx ) = consumption
end if
end do
ndata = idx
close (funit)
end subroutine
end module
program MyMain
use MyModule
implicit none
integer :: consumption( 10 ), ndata, idx
character(50) :: names( 10 ) !<-- an array of size 10 (each element = 50-char string)
character(200) :: filename !<-- a string of 200 chars
filename = "clients.txt"
names = ""
consumption = 0
call ReadFileIntoArrays (filename, names, consumption, ndata)
print "(2a20)", "name", "consumption"
do idx = 1, ndata
print "(a20,i20)", trim( names( idx ) ), consumption( idx )
enddo
end program
Then, with the input in the question, the output becomes
finished reading data.
name consumption
John,D.E. 100
Bob,F.I. 200
Oli,G.H. 1500

Convert Cell to an Array

i have a cell array with dimensions 1x16384 consists of 16384 numbers.
I tried using cell2mat(), but i get one element with all those numbers in it.
How do i convert it to an array with 1x16384 dimension.
Assuming B= cell2mat(A);
A looks like;
Columns 16382 through 16384
'15.849' '16.337' '14.872'
where as B looks like;
B =
-8.921-8.433-2.5745.23911.58714.02811.5876.7041.821-1.109-2.085-1.5970.3562.
console ;
class(A), class(A{1}), size(A), size(A{1})
ans =
cell
ans =
char
ans =
1 16384
ans =
1 6
For mcve,
Csv input file
DELIMITER = ' ';
HEADERLINES = 3;
% Import the file
newData1 = importdata('C:\Python34\co2a0000364.csv', DELIMITER, HEADERLINES);
% Create new variables in the base workspace from those fields.
vars = fieldnames(newData1);
for i = 1:length(vars)
assignin('base', vars{i}, newData1.(vars{i}));
end
new = textdata(6:16452,4);
A = new;
for z = 1:63
A(i*257)=[];
end
B = A'
A= B;
A= cell2mat(B)
B= A
You way of importing data is quite clumsy. I invite you to read the textscan function documentation, which allows much more flexibility in importing mixed data type (text and numeric data).
I propose you another way of importing, which uses textscan:
%% // Import only the 4th column of data
fid = fopen('co2a0000364.csv') ;
M = textscan( fid , '%*s%*s%*s%f' , 'Delimiter',' ' , 'HeaderLines',4) ;
fclose(fid) ;
M = cell2mat(M) ;
%% // reshape to have each channel in its own colum
M = reshape( M , 257 , [] ) ;
%% // Delete the channel number from the data table
M(1,:) = [] ;
This will give you a nice 256*64 matrix, containing the data for each of the 64 channels in one column.
if you really want them all in sequence in one column, just add:
M = M(:) ;
to the end of the code.
Explanation note: the textscan format specifier I use: '%*s%*s%*s%f' tells the function to read 4 elements per line:
- 3x strings : %s
- 1x floating point number: %f
adding the character * in the format specifier (for example %*s) for an element tells the function to ignore the element, so it does not put it into the output.

How do I make this specific code run faster in Matlab?

I have an array with a set of chronological serial numbers and another source array with random serial numbers associated with a numeric value. The code creates a new cell array in MATLAB with the perfectly chronological serial numbers in one column and in the next column it inserts the associated numeric value if the serial numbers match in both original source arrays. If they don't the code simply copies the previous associated value until there is a new match.
j = 1;
A = {random{1:end,1}};
B = cell2mat(A);
value = random{1,2};
data = cell(length(serial), 1);
data(:,1) = serial(:,1);
h = waitbar(0,'Please Wait...');
steps = length(serial);
for k = 1:length(serial)
[row1, col1, vec1] = find(B == serial{k,1});
tf1 = isempty(vec1);
if (tf1 == 0)
prices = random{col1,2};
data(j,2) = num2cell(value);
j = j + 1;
else
data(j,2) = num2cell(value);
j = j + 1;
end
waitbar(k/steps,h,['Please Wait... ' num2str(k/steps*100) ' %'])
end
close(h);
Right now, the run-time for the code is approximately 4 hours. I would like to make this code run faster. Please suggest any methods to do so.
UPDATE
source input (serial)
1
2
3
4
5
6
7
source input (random)
1 100
2 105
4 106
7 107
desired output (data)
SR No Value
1 100
2 105
3 105
4 106
5 106
6 106
7 107
Firstly, run the MATLAB profiler (see 'doc profile') and see where the bulk of the execution time is occuring.
Secondly, don't update the waitbar on every iteration> Particularly if serial contains a large (> 100) number of elements.
Do something like:
if (mod(k, 100)==0) % update on every 100th iteration
waitbar(k/steps,h,['Please Wait... ' num2str(k/steps*100) ' %'])
end
Some points:
Firstly it would help a lot if you gave us some sample input and output data.
Why do you initialize data as one column and then fill it's second in the loop? Rather initialize it as 2 columns upfront: data = cell(length(serial), 2);
Is j ever different from k, they look identical to me and you could just drop both the j = j + 1 lines.
tf1 = isempty(vec1); if (tf1 == 0)... is the same as the single line: if (!isempty(vec1)) or even better if(isempty(vec1)) and then swap the code from your else and your if.
But I think you can probably find a fast vecotrized solution if you provide some (short) sample input and output data.

Resources