I was trying to code this problem in fortran. The output file contains the result in two columns. I am having hard time to modify my code (below) to get a gnuplot-ready output file containing nt columns and nx lines. Can anybody help me? Thanks!
PROGRAM odlc
IMPLICIT NONE
INTEGER::i,it,nx,nt,k,ierr
DOUBLE PRECISION::dx,dt,c
DOUBLE PRECISION,DIMENSION(2000)::u,un
ierr=0
nx=20
nt=50
dt=0.01
c=1.0
dx=2./(nx-1.)
!initial condition
DO i = 1,nx
IF(i*dx>=0.5 .and. i*dx<=1) THEN
u(i) = 2
ELSE
u(i)=1
ENDIF
ENDDO
!Finite Difference
OPEN(UNIT=200,FILE='tab2.txt',STATUS='REPLACE',ACTION='WRITE',IOSTAT=ierr)
DO it=1,nt
DO k=1,nx
un(k)=u(k)
ENDDO
DO i=2,nx-1
u(i)=un(i)-c*dt/dx*(un(i)-un(i-1))
ENDDO
DO i=1,nx
WRITE(200,'(I7,F10.2)')i,u(i)
ENDDO
ENDDO
CLOSE(UNIT=200)
END
I'm not 100% sure that it is exactly what you want but here you go:
Declare
CHARACTER(len=32)::fmt
and initialize it like this
WRITE(fmt,*)'(',nx,'F10.2)'
This just creates a format string which writes a single line of nx reals.
Then replace
DO i=1,nx
WRITE(200,'(I7,F10.2)')i,u(i)
ENDDO
by
WRITE(200,fmt) (/ (u(i), i=1,nx) /)
Now in your tab2.txt file, you will get nt lines and nx columns.
After your update, here is the (slightly shortened) code that will do what you want:
PROGRAM odlc
IMPLICIT NONE
INTEGER::i,it
INTEGER,PARAMETER::nx=20,nt=50
DOUBLE PRECISION,PARAMETER::dx=2./(nx-1.),dt=0.01,c=1.0
DOUBLE PRECISION,DIMENSION(nt,nx)::u
CHARACTER(len=32)::fmt
WRITE(fmt,*)'(I3,',nt,'F5.2)'
!initial condition
DO i = 1,nx
IF(i*dx>=0.5 .and. i*dx<=1) THEN
u(1,i) = 2
ELSE
u(1,i)=1
ENDIF
ENDDO
!Finite Difference
DO it=2,nt
DO i=2,nx-1
u(it,i)=u(it-1,i)-c*dt/dx*(u(it-1,i)-u(it-1,i-1))
ENDDO
ENDDO
!Write to file
OPEN(UNIT=200,FILE='tab2.txt',STATUS='REPLACE',ACTION='WRITE')
DO i=1,nx
WRITE(200,fmt)REAL(i*(2./(nx-1.))),u(:,i)
ENDDO
CLOSE(UNIT=200)
END PROGRAM odlc
Related
I am fighting with trying to get numbers 1 and 2 only on each second and third line in the second column.
I have a file tisk2 with
O
H
H
O
H
H
And I need to get to file tisk this:
O
H1
H2
O
H1
H2
I mean I want no number no text after O. I tried to write this code:
program cislo
implicit none
integer :: i, sum, j, k
character :: t*10, m*10
open(10,file="tisk2",status='old')
open(12,file="tisk",status='old')
do k=0,5
read(10,*) m
enddo
do j=1,3
do i = 0,0
t=" "
print*, t
exit
enddo
sum=0
do i=1,2
write(12,fmt='(a2,i2)') m, i
enddo
enddo
end program cislo
I can print only i and I get nothing, second line 1 and third line 2. Then alone print m. But when I want to put both to one file, it skips O and writes to file only H1, H2 and then again. Does anyone has an idea how to get what I need? Thank you for help.
all. I'm writing a relatively simple program that iterates through a list of data and returns the peak values for a school project.
Here's the code so far:
program Fortran_Project_1
implicit none
integer::cnt,cnt1, i
integer:: peaks=5
real, dimension(360):: time,impulse
real, allocatable :: impulselist(:)
integer, dimension(360)::interval
character(len=150)::clean,header
clean='C:\Users\User\Desktop\Fortran_Project_1\ir_clean.txt'
print *, clean
open (unit=1,file=clean)
do cnt1=1,4
read (1,*) header
end do
do cnt=1,443
read(1,*) interval(cnt),time(cnt),impulse(cnt)
end do
print *, 'Choose amount of peaks to find'
read *, peaks
deallocate (impulselist)
allocate (impulselist(peaks))
do i = 1, cnt
if (impulse(i)>impulse(i+1) .and. impulse(i)>impulse(i-1)) then
peaks = peaks - 1
impulselist(peaks) = impulse(i)
end if
if (peaks < 1) then
exit
end if
end do
close (1)
print *, impulselist
end program Fortran_Project_1
Anyways, when running this and inputting the amount of peaks the user wants to find, the console is totally blank. It prints the clean variable and the query but that's all. What should I do?
Thank you
EDIT: Console output:
C:\Users\User\Desktop\Fortran_Project_1\ir_clean.txt
Choose amount of peaks to find
[Input]
It is strange that you say that nothing happens. You should get an error message.
Array impulselist is not allocated and you are calling deallocate(impulselist). That is not allowed and should be diagnosed by the compiler and it should complain when the code is running.
I figured it out. There was an issue with list dimensions. Here's the updated code that works perfectly.
program Fortran_Project_1
implicit none
integer::cnt,cnt1,i,count1,peaks
real, dimension(1000):: time,impulse
real, allocatable :: impulselist(:),timelist(:)
integer, dimension(1000)::interval
character(len=150)::clean,header
clean='C:\Users\Buraaq Alrawi\Desktop\Fortran_Project_1\ir_clean.txt'
print *, clean
print *, 'Choose amount of peaks to find'
read *, peaks
allocate (impulselist(peaks))
allocate(timelist(peaks))
open (unit=1,file=clean,action='read')
do cnt1=1,4
read (1,*) header
end do
do cnt=1,501
read(1,*) interval(cnt),time(cnt),impulse(cnt)
end do
count1=1
do i = 1, cnt
if (impulse(i)>impulse(i+1) .and. impulse(i)>impulse(i-1)) then
impulselist(count1) = impulse(i)
timelist(count1) = time(i)
count1 = count1 + 1
end if
if (count1 > peaks) then
exit
end if
end do
close (1)
100 format(A28,X,1000F10.2)
200 format(A28,X,1000F10.4)
300 format(A23,F10.2,F10.4)
write (*,100) 'The peak times are(seconds):', timelist
write (*,200) 'The peak impulse values are:', impulselist
write (*,300) 'The settled values are:',time(501),impulse(501)
end program Fortran_Project_1
Thanks everybody
I want to use structure in matlab but in first iteration it's run correctly and in other iteration give that message .
1x2 struct array with fields:
my code is :
for i=1:lenfd
currow=rees(i,:)
maxcn=max(currow)
if maxcn~=0
maxin=find(currow==maxcn)
ress(i).x =maxin
end
end
thank you.
That message is not a warning or error. That's just MATLAB printing the output of an operation. And it does that by default, unless you suppress it by appending a semicolon to the command:
for ii = 1:lenfd
currow = rees(ii,:); % <=== NOTE: semicolons at the end
maxcn = max(currow);
if maxcn ~= 0
ress(ii).x = find(currow==maxcn);
end
end
Note that max() may have 2 outputs, the second output being the first index into the array where the maximum occurred. If you know beforehand that any maximum will occur only once, you can skip the call to find() and use the second output of max().
In an IML proc I have several martices and several vectors with the names of columns:
proc IML;
mydata1 = {1 2 3, 2 3 4};
mydata2 = {1 2, 2 3};
names1 = {'red' 'green' 'blue'};
names2 = {'black' 'white'};
To assign column names to columns in matrices one can copypaste the mattrib statement enough times:
/* mattrib mydata1 colname=names1;*/
/* mattrib mydata2 colname=names2;*/
However, in my case the number of matrices is defined at execution, thus a do loop is needed. The following code
varNumb=2;
do idx=1 to varNumb;
call symputx ('mydataX', cat('mydata',idx));
call symputx ('namesX', cat('names',idx));
mattrib (symget('mydataX')) colname=(symget('namesX'));
end;
print (mydata1[,'red']) (mydata2[,'white']);
quit;
however produces the "Expecting a name" error on the first symget.
Similar question Loop over names in SAS-IML? offers the macro workaround with symget, what produces an error here.
What is the correct way of using mattrib with symget? Is there other way of making a variable from a string than macro?
Any help would be appreciated.
Thanks,
Alex
EDIT1
The problem is in the symget function. The &-sign resolves the name of the matrix contained in the macro variable, the symget only returns the name of the macro.
proc IML;
mydata1 = {1 2 3};
call symputx ('mydataX', 'mydata1');
mydataNew = (symget('mydataX'));
print (&mydataX);
print (symget("mydataX"));
print mydataNew;
quit;
results in
mydata1 :
1 2 3
mydata1
mydataNew :
mydata1
Any ideas?
EDIT2
Function value solves the symget problem in EDIT1
mydataNew = value(symget('mydataX'));
print (&mydataX);
print (value(symget("mydataX")));
print mydataNew;
The mattrib issue but persists.
SOLVED
Thanks Rick, you have opened my eyes to CALL EXECUTE() statement.
When you use CALL SYMPUTX, you should not use quotes for the second argument. Your statement
call symputx ('mydataX', 'mydata1');
assigns the string 'mydata1' to the macro variable.
In general, trying to use macro variables in SAS/IML loops often results in complicated code. See the article Macros and loops in the SAS/IML language for an indication of the issues caused by trying to combine a macro preprocessor with an interactive language. Because the MATTRIB statement expects a literal value for the matrix name, I recomend that you use CALL EXECUTE rather than macro substitution to execute the MATTRIB statement.
You are also having problems because a macro variable is always a scalar string, whereas the column name is a vector of strings. Use the ROWCAT function to concatenate the vector of names into a single string.
The following statements accomplish your objective without using macro variables:
/* Use CALL EXECUTE to set matrix attributes dynamically.
Requires that matrixName and varNames be defined at main scope */
start SetMattrib;
cmd = "mattrib " + matrixName + " colname={" + varNames + "};";
*print cmd; /* for debugging */
call execute(cmd);
finish;
varNumb=2;
do idx=1 to varNumb;
matrixName = cat('mydata',idx);
varNames = rowcat( value(cat('names',idx)) + " " );
run SetMattrib;
end;
I have to read the simple text file I write on the end of this post (it is just a sctructured grid). In fortran it is so easy to do this, you just have to do:
read(fileunit,*)
read(fileunit,*) mc,nc
do j = 1, nc
read (fileunit, *) dummy, dummy, (xcor(j,i), i=1,mc)
enddo
is there an equivalent function in matlab that reads element by element and keeps reading after the newline like in fortran? I could not find it, all the function as fscanf, textscan etc read line by line and then i have to parse each line. Here is the file. thanks for any help A.
Gridfile version 8.675.44
8 3
eta= 1 0.00000000000000000E+00 1.50000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
eta= 2 0.00000000000000000E+00 1.50000000000000000E+02
3.00000000000000000E+02 4.50000000000000000E+02
7.50000000000000000E+02 9.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
eta= 3 0.00000000000000000E+00 1.50000000000000000E+02
3.00000000000000000E+02 4.50000000000000000E+02
7.50000000000000000E+02 9.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
There are many ways to do this, but perhaps you will like the way fscanf works, as in this example. After the file is opened by something like fin = fopen('gridfile.txt') and the header swallowed, you can use fscanf(f, 'x= %d'), and then fscanf(f, '%f'), which will read the entire block. fscanf does not stop at the end of a line if not instructed to do so. Taken together, a solution could look like
fin = fopen('gridfile.txt');
fgetl(fin);
% read data counts
cnt = fscanf(fin, '%d %d', 2);
mc = cnt(1);
nc = cnt(2);
xcor = zeros(nc, mc);
% read blocks of data
for j = 1 : nc
fscanf(fin, '%s %s', 2);
xcor(j, :) = fscanf(fin, '%f', mc)';
end
fclose(fin);
fscanf keeps matching the format specifier as long as possible, and returns only when no further consecutive matches can be found. The above examples uses this in two places. First, to extract the dimensionality cnt, in your example (8, 3), and second, to read eight consecutive floating point values per record.