Does not display anything after data entry - fortran

Does not display anything after data entry
program g
implicit none
real::q,n,s,z,q2,y,free_board,r,b,e,A,h,t
write(*,100)"pls insert discharge Q ="
read(*,*)q
write(*,100)"please insert Manning coefficient n ="
read(*,*)n
write(*,*)"please insert slope of the hydraulic channel ="
read(*,*)s
write(*,*)"please inset Z ="
read(*,*)z
write(*,*)"how much of b/y do you want?"
write(*,*)"if it not important right 2.5"
read(*,*)e
if(e<2.or.e>5)then
stop
end if
y=0
do
b=y*e
A=b+2*y*((1+Z**2)**(0.5))
R=((b+z*y)*y)/(b+(2*y*(1+z**2)**(0.5)))
h=(1/n)*(r**(2/3))*A*(s)**0.5
if( abs(h-q)<0.01) then
exit
end if
y=0.001+y
end do
free_board=0.2*y
h=free_board+y
t=b+2*y*z
write(*,100)"free board="
write(*,*) free_board
write(*,100)"y="
write(*,*)y
write(*,100)"b="
write(*,*)b
write(*,100)"T="
write(*,100)t
100 format(A)
end program g
this not work and not show anything after enter data

For sure the line write(*,100)t will give you a wrong output, since "t" it is a real, not a string. Please change it to write(*,*).
With all inputs equal to 1.0 and by putting e=2.5, I see these output (at screen):
free board = 3.7200041E-02
y = 0.1860002
b = 0.4650005
T = 0.8370009
If you don't see outputs, maybe you are choosing wrong "e" values (less than 2 or more than 5).

Related

How to subtract values from one row from values of another row using Fortran

I am fairly new to fortran and am using it for some molecular dynamics work
I have a text file that contains xyz coordinates of multiple atoms. Edit: The data is repetitive
12
xyz
OH2 2.056771 0.152501 -3.407425
H1 2.086389 -0.658114 -2.899234
H2 1.325328 0.643692 -3.033321
OH2 -1.620865 1.026821 -4.353753
H1 -1.045534 1.344086 -5.049863
H2 -1.107708 1.130454 -3.552402
OH2 -2.064113 1.377066 -1.093998
H1 -1.228430 1.344786 -1.559641
H2 -2.692285 1.681116 -1.749120
OH2 1.451636 1.645941 -0.456822
H1 0.841741 1.630468 -1.194400
H2 1.251076 0.850951 0.037141
Where OH2 and H1/H2 are atoms.
I would like to be able subtract the xyz coor of the H2(hydrogen) following the preceding OH2(oxygen) for every OH2 that is recognized.
So far my code looks as follows:
program placepoint
implicit none
real(kind(0.0d0)) :: xCoor(1:12), yCoor(1:12), zCoor(1:12)
real(kind(0.0d0)) :: v1_x, v1_y, v1_z, dOH, nx, ny, nz
real(kind(0.0d0)) :: ip_x, ip_y, ip_z, norm
integer :: j, n
character*20 :: dumch(1:12)
open(unit = 10, file = 'hoh.xyz')
open(unit = 13, file = 'ipcoor.txt')
do j= 1, 12
read(10,*) dumch(j) , xCoor(j), yCoor(j), zCoor(j)
!Calculate vector 1 along OXR-HX bond that can be used to place a point ip (R1)
if (dumch(j) .eq. "OH2") then
v1_x = xCoor(j+2) - xCoor(j)
v1_y = yCoor(j+2) - yCoor(j)
v1_z = zCoor(j+2) - zCoor(j)
dOH = sqrt((v1_x)**2 + (v1_y)**2 + (v1_z)**2)
! Normalize vector
nx = v1_x/dOH
ny = v1_y/dOH
nz = v1_z/dOH
!Place ip at 0.7Å along the OH bond (this is not exactly at the correct HX-OXR-OR angle but these are for dummy atoms and shake should take care of this during dyn runs)
ip_x = xCoor(1) + 0.7*nx
ip_y = yCoor(1) + 0.7*ny
ip_z = zCoor(1) + 0.7*nz
end if
end do
write(13,*) 'ip' , ip_x, ip_y, ip_z, dOH
end program place point
I realize I am being to naive using the j+2 as a identifier to find the value of H2 immediately following the OH2, but unfortunately I have not found any other better way. I also get the fortran error "End of file" after proper compilation. So I am expecting that I am perhaps making multiple mistakes here. Any help with this will be so appreciated!

fortran averaging columns frame by frame in specific format

I would like to average first column and last column shown here(that is my output). My code does several things such as compare specific atoms with the name "CA" for each frame (I have 1000 frames), exclude the nearest neighbours and depending on the cutoff value, and count those contacts and print them separately according to my wish (input file looks like this). I would like to print a file where it gives me the output something like following as an example:
1 0
2 12
3 12
....
100 16
Need guidance to achieve that by helping me form a loop or a condition.
open(unit=11,file="0-1000.gro", status="old", action="read")
do f=1,frames,10
25 format (F10.5,F10.5,F10.5)
do h=1,natoms_frames
read(11,format11)nom(h),resname(h),atmtype(h),num(h),x(h),y(h),z(h)
end do
read(11,25)lasta(f),lastb(f),lastc(f)
count=0
do h=1, natoms_frames
if (atmtype(h).eq.' CA') then
count=count+1
CAx(count)=x(h)
CAy(count)=y(h)
CAz(count)=z(h)
end if
end do
do h=1, count
avg_cal=0
cal=0
do hh=h+3, count
if (h.ne.hh) then
! finding distance formula from the gro file
distance = sqrt((CAx(hh)-CAx(h))**2 + (CAy(hh)-CAy(h))**2 + (CAz(hh)-CAz(h))**2)
if (distance.le.cutoff) then
cal = cal+1
set = set+1
final_set=final_set+1
avg_cal=avg_cal+1
end if
end if
end do
write(*,*)h,cal,final_set
end do
end do ! end of frames
close(11)
end program num_contacts
Writing in a file (in ASCII) is the same as printing on screen, except that you need to specify the file's unit.
So first, open your file:
open(unit = 10, file = "filename.dat", access = "sequential", form = "formatted", status = "new", iostat = ierr)
where 'unit' is a unique integer that will be associated to your file (as an ID). Note that the 'form' is 'formatted' as you want to output something readable by a human. Then you can start your loop:
do h = 1, natoms_frames
! BUNCH OF STUFF TO CALCULATE REQUIRED VARIABLES
write(10, *) h, cal, final_set
end do
Finally, close your file:
close(10)

Questions about Tuples

So I was able to run part of a program doing below (using tuples)
def reverse_string():
string_in = str(input("Enter a string:"))
length = -int(len(string_in))
y = 0
print("The reverse of your string is:")
while y != length:
print(string_in[y-1], end="")
y = y - 1
reverse_string()
The output is:
Enter a string:I Love Python
The reverse of your string is:
nohtyP evoL I
I am still thinking how for the program to reverse the position of the words instead of per letter.
The desired output will be "Phython Love I"
Is there anyway that I will input a string and then convert it to a tuple similar below:
So If I enter I love Phyton, a certain code will do as variable = ("I" ,"Love", "Python") and put additional codes from there...
Newbie Programmer,
Mac

Call a subroutine for a list of points instead of a single point

I have a certain piece of code in fortran. The code takes 'pq' as an input from the user and is a single point. Instead of doing this I want to read a set of points 'pq' from a file points.txt and run it for those number of points instead of just one single user input. Is it possible? The code is as follows:
program prop
use module
implicit none
character(len=80) :: ErrorMsg
character(2) :: xy
real(8) :: Conc(20) = 0.d0
character(len=20) :: fn, fl
real(8) :: Mmolar, Tcritical, Pcritical, Tmininimum, Tmaximum, x, y
call Init_module()
write(*,*) 'Insert the gas name:'
read(*,*) fn
write(*,*) 'Insert the gas library:'
read(*,*) fl
write(*,*) 'Insert the copule pq:'
read(*,*) pq
write(*,*) 'Insert the value of ', pq(1:1)
read(*,*) x
write(*,*) 'Insert the value of ', pq(2:2)
read(*,*) y
write(*,*) 'Pres = ', Pres( pq, x, y, ErrorMsg)
write(*,*) 'Temp = ', Temperature( pq, x, y, ErrorMsg)
call ReleaseObjects()
end program prop
Instead of reading pq as a single point x,y from the user in the above code, I want to read a set of points from file.txt, for example 50 points and then run subroutines Pres and Temperature.
Each line of the file contains one point x,y and x and y in each line are separated by a few space characters.
The first few lines of file.txt are:
Ts
500
0.04781564 159.81587875
0.20396084 165.46398084
0.08159885 166.81382894
0.03879184 164.17497877
0.12585959 165.37000305
0.09895530 165.95997769
0.10389518 170.74235496
It must be noted that the length and the sign of the floating numbers can vary. The file.txt is originally written through python with the formatting for x, y being '%-12.8f %-12.8f\n'%. I have the following code to try and read the file but am not able to read from the 3rd line onwards:
real, allocatable :: x(:),y(:)
integer :: np
open(12,file=trim('file.txt'),status='old', &
access='sequential', form='formatted', action='read' )
read(12,*)pq
write(*,*)'pq:', pq
read(12,*)np
write(*,*)'number of points:',np
allocate (x(np))
allocate (y(np))
do i=1,np
read(12,*)x(i),y(i)
write(*,*)x(i),y(i)
enddo
Instead of using the READ statement with the asterisk (*) as the first argument asking for an user input, use a file identifier. You need to OPEN your file containing the set of points, assuming it is ASCII :
OPEN(UNIT=10,FILE=file.txt,ACTION='read',STATUS='old')
I think the arguments of this command are quite explanatory.
Then assuming your file contains multiple lines with x and y values, you can read each line of your file by doing :
READ(10,*) x,y
If you have multiple points to read, just use a DO if you know the number of points to read, a DO WHILE otherwise. To take your example with 50 points, something like this should work :
OPEN(UNIT=10,FILE=file.txt,ACTION='read',STATUS='old') ! Open file
DO i=1,50
READ(10,*) x,y
write(*,*) 'Pres = ', Pres( pq, x, y, ErrorMsg)
write(*,*) 'Temp = ', Temperature( pq, x, y, ErrorMsg)
END DO
CLOSE(10) ! Close file
EDIT
Your suggestion is almost correct. You forgot to declare pq as a character(len=2). You should not have been able to pass line 1 because of that.
As I said, there is a space separator that is naturally treated by a asterisk as a format. Anyway, if you want to exactly match the format, use the same with which you wrote your data. Reading your format Python, I assume you wrote two floats with a space separator, and indeed if you count the number of character of your digits :
0.04781564 159.81587875
^^^^^^^^^^^^|^^^^^^^^^^^^
1 12|1 12
|
space
which gives the following format in Fortran :
read(12,'(f12.8,1X,f12.8)') x(i),y(i)
X means a space separator in Fortran formats.
Then you can write you data onscreen with the same format to check :
write(*,'(f12.8,1X,f12.8)') x(i),y(i)
It gives :
pq:Ts
number of points: 500
0.04781564 159.81587219
0.20396084 165.46397400
0.08159885 166.81382751
0.03879184 164.17497253
0.12585959 165.37001038
0.09895530 165.95997620
0.10389518 170.74235535
You may have noticed that you lost precision on the last digits. It is because you have declared a simple real (4 bytes). Switch your real to 8 bytes with real(kind=8) or real*8 according to your compiler (be aware, not the right way to do it, not portable but sufficient in your case)
Do not forget to close your file when you are done dealing with it :
close(12)

Program to create spatial grid, average values that fall within grid, write to table

So I'm trying to come up with a clever way to make this program read a catalog and take anything falling within specific spatial "grid" boxes and average the data in that box together. I'll paste my horrid attempt below and hopefully you'll see what I'm trying to do. I can't get the program to work correctly (it gets stuck in a loop somewhere that I haven't debugged), and before I bang my head against it anymore I want to know if this looks like a logical set of operations for what I'm looking to do, or if there is a better way to accomplish this.
Edit: To clarify, the argument section is for the trimming parameters---"lmin lmax bmin bmax" set the overall frame, and "deg" sets the square-degree increments.
program redgrid
implicit none
! Variable declarations and settings:
integer :: ncrt, c, i, j, k, count, n, iarg, D, db, cn
real :: dsun, pma, pmd, epma, epmd, ra, dec, degbin
real :: V, Per, Amp, FeH, EBV, Dm, Fi, FeHav, EBVav
real :: lmin, lmax, bmin, bmax, l, b, deg, lbin, bbin
real :: bbinmax, bbinmin, lbinmax, lbinmin
character(len=60) :: infile, outfile, word, name
parameter(D=20000)
dimension :: EBV(D), FeH(D), lbinmax(D), bbinmax(D)
dimension :: bbinmin(D), lbinmin(D)
103 format(1x,i6,4x,f6.2,4x,f6.2,4x,f7.2,3x,f6.2,4x,f5.2,4x,f5.2,4x,f5.2,4x,f6.4)
3 continue
iarg=iargc()
if(iarg.lt.7) then
print*, 'Usage: redgrid infile outfile lmin lmax bmin bmax square_deg'
stop
endif
call getarg(1, infile)
call getarg(2, outfile)
call getarg(3, word)
read(word,*) lmin
call getarg(4, word)
read(word,*) lmax
call getarg(5, word)
read(word,*) bmin
call getarg(6, word)
read(word,*) bmax
call getarg(7, word)
read(word,*) deg
open(unit=1,file=infile,status='old',err=3)
open(unit=2,file=outfile,status='unknown')
write(2,*)"| l center | b center | [Fe/H] avg | E(B-V) avg | "
FeHav = 0.0
EBVav = 0.0
lbinmin(1) = lmin
bbinmin(1) = bmin
degbin = (bmax-bmin)/deg
db = NINT(degbin)
do j = 1, db
bbinmax(j) = bbinmin(j) + deg
lbinmax(j) = lbinmin(j)*cos(bbinmax(j))
print*, lbinmin(j), bbinmin(j), db
cn = 1
7 continue
read(1,*,err=7,end=8) ncrt, ra, dec, l, b,&
V, dsun, FeH(cn), EBV(cn)
if(b.ge.bbinmin(j).and.b.lt.bbinmax(j)) then
if(l.ge.lbinmin(j).and.l.lt.lbinmax(j)) then
FeHav = FeHav + FeH(cn)
EBVav = EBVav + EBV(cn)
cn = cn + 1
end if
end if
goto 7
8 continue
FeHav = FeHav/cn
EBVav = EBVav/cn
write(2,*) lbinmax(j), bbinmax(j), FeHav, EBVav
bbinmin(j+1) = bbinmin(j) + deg
lbinmin(j+1) = lbinmin(j) + deg
end do
close(1)
close(2)
end program redgrid
Below is a small section of the table I'm working with. "l" and "b" are the two coordinates I am working with---they are angular, hence the need to make the grid components "b" and "l*cos(b)." For each 0.5 x 0.5 degree section, I need to have averages of E(B-V) and [Fe/H] within that block. When I write the file all I need are four columns: the two coordinates where the box is located, and the two averages for that box.
| Ncrt | ra | dec | l | b | V | dkpc | [Fe/H] | E(B-V) |
7888 216.53 -43.85 -39.56 15.78 15.68 8.90 -1.19 0.1420
7889 217.49 -43.13 -38.61 16.18 16.15 10.67 -1.15 0.1750
7893 219.16 -43.26 -37.50 15.58 15.38 7.79 -1.40 0.1580
Right now, the program gets stuck somewhere in the loop cycle. I've pasted the terminal output that happens when I run it, along with the command line I'm running it with. Please let me know if I can help clarify. This is a pretty complex problem for a Fortran rookie such as myself---perhaps I'm missing some fundamental knowledge that would make it much easier. Anyways, thanks in advance.
./redgrid table2.above redtest.trim -40 0 15 30 0.5
-40.0000000 15.0000000 30 0.00000000 0.00000000
-39.5000000 15.5000000 30 -1.18592596 0.353437036
^it gets stuck after two lines.
I assume that the program does what you want it to do, but you are looking for a few things to tidy the code up.
Well first up, I'd fix up the indentation.
Secondly, I'd not use unit numbers below 10.
INTEGER, PARAMETER :: in_unit = 100
INTEGER, PARAMETER :: out_unit = 101
...
OPEN(unit=in_unit, file=infile, status='OLD")
...
READ(in_unit, *) ...
...
CLOSE(in_unit)
Thirdly, I'd not use GOTOs and labels. You can do that in a loop far easier:
INTEGER :: read_status
DO j = 1, db
...
read_loop : DO
READ(in_unit, *, IOSTAT=read_status) ...
IF (read_status == -1) THEN ! EOF
EXIT read_loop
ELSEIF (read_status /= 0) THEN
CYCLE read_loop
ENDIF
...
END DO read_loop
...
END DO
There are a few dangers in your code, and even in this one above: It can lead to infinite loops. For example, if the opening of infile fails (e.g. the file doesn't exist), it loops back to label 3, but nothing changes, so it will eventually again try to open the same file, and probably have the same error.
Same above: If READ repeatedly fails without advancing, and without the error being an EOF, then the read loop will not terminate.
You have to think about what you want your program to do when something like this happens, and code it in. (For example: Print an error message and STOP if it can't open the file.)
You have a very long FORMAT statement. You can leave it like that, though I'd probably try to shorten it a bit:
103 FORMAT(I7, 2F10.2, F11.2, 4F9.2, F10.4)
This should be the same line, as numbers are usually right-aligned. You can also use strings as a format, so you could also do something like this:
CHARACTER(LEN=*), PARAMETER :: data_out_form = &
'(I7, 2F10.2, F11.2, 4F9.2, F10.4)'
WRITE(*, data_out_form) var1, var2, var3, ...
and again, that's one less label.