Moment of inertia in fortran [duplicate] - fortran

This question already has answers here:
Modern Fortran equivalent of an action statement shared by nested DO and GO TO
(1 answer)
Function has no implicit type
(4 answers)
Closed 1 year ago.
I am trying to calculate the moment of inertia in fortran. The formula I am using is following: The code I am using:
program moment
implicit none
real :: cR,h,rho0,a,b,c,d,resultV,pi,resultMI,aMass,exactresMI,exactresV,r,res,z,rho
integer :: m,n
! rho0 = density, cR=capital R( radius),h= height )
rho0=10000
cR=0.05
h=0.1
a=0.d0
b=h
c=0.d0
d=cR
m=1000
n=1000
call cheb2(a,b,m,c,d,n,funV,res)
pi=4*datan(1.d0)
resultV=res*2*pi
exactresV= pi/3*cR**2*h
write(*,*)
write(*,*) "Numerical volume result =", resultV
write(*,*) "Exact volume result = ",exactresV
call cheb2(a,b,m,c,d,n,funV,res)
resultMI=res*2*pi
aMass=exactresV*rho0
exactresMI=3/10.*aMass*cR**2
write(*,*)
write(*,*) "Numerical Moment of Inertia result =", resultMI
write(*,*) "Exact Moment of Inertia result = ",exactresMI
end program
function funV(z,r)
if (r.gt.z*cR/h) then
rho=0.d0
else
rho=1.d0
end if
funV=rho*r
return
end
function funMI(z,r)
if (r.gt.z*cR/h) then
rho=rho0
else
rho=1.d0
endif
funMI=rho*r**3
return
end
include "CHEB.FOR"
Our instructor does not use "implicit none" , so I am really new to this operator. Out instructor gave us CHEB.FOR code for calculating 2 dimensional integrals. I am writing it here:
subroutine ch4xy(al,bl,cl,dl,f,ri)
implicit double precision (a-h,o-z)
common/ttxy/ t1,t2
dimension xx(4),yy(4)
c1=(al+bl)/2.d0
c2=(dl+cl)/2.d0
d1=(-al+bl)/2.d0
d2=(dl-cl)/2.d0
xx(1)=c1+d1*t1
xx(2)=c1+d1*t2
yy(1)=c2+d2*t1
yy(2)=c2+d2*t2
xx(3)=c1-d1*t1
xx(4)=c1-d1*t2
yy(3)=c2-d2*t1
yy(4)=c2-d2*t2
ss=0
do 3 i=1,4
do 3 j=1,4
ss=ss+f(xx(i),yy(j))
3 continue
ri=ss*d1*d2/4.d0
return
end
subroutine cheb2(a,b,m,c,d,n,f,r)
implicit double precision (a-h,o-z)
external f
common/ttxy/ t1,t2
t1=0.187592
t2=0.794654
hx=(b-a)/m
hy=(d-c)/n
rr=0
do 5 i=1,m
do 5 j=1,n
aa=a+(i-1)*hx
bb=aa+hx
cc=c+(j-1)*hy
dd=cc+hy
call ch4xy(aa,bb,cc,dd,f,ri)
rr=rr+ri
5 continue
r=rr
return
end
When I compile the file, a couple of errors and a warning appear:
CHEB.FOR:19:17:
19 | do 3 j=1,4
| 1
Warning: Fortran 2018 deleted feature: Shared DO termination label 3 at (1)
CHEB.FOR:36:11:
36 | do 5 j=1,n
| 1
Warning: Fortran 2018 deleted feature: Shared DO termination label 5 at (1)
momentOFinertia.f95:17:27:
17 | call cheb2(a,b,m,c,d,n,funV,res)
| 1
Error: Symbol 'funv' at (1) has no IMPLICIT type
First, I dont understand why funV is unclassifiable statement, it classifies as a function. Second, our instructor used some old operations which is apparently not valid in new fortran. I dont know what could replace "shared do".

The main problem (fixed by your edit)is that your code misses an end or end program at the end. Alternatively, you could put an end program after your functions and contains between the subroutine and the main program body. That would make the functions to be internal subprograms and would fix your other problem - no implicit type for the functions.
This - putting the functions inside the program as internal subprograms, allows the program to "see" them and then the program can correctly pass them to other procedures. Alternatively, you could make an interface block for them or declare their type and let them be external. See Why do I have to specify implicitly for a double precision return value of a function in Fortran? for more.
You also have a type mismatch. The code you got from your instructor uses double precision but your code uses the default real. You have to synchronize that. Update your code to double precision, either using double precision or using real kinds.
The compiler also warns you that your program is using deleted features. These features were deleted in modern revisions of the Fortran standards. However, the compiler remain largely backwards compatible and will compile the code including those features anyway, unless you request strictly a certain standard revision.
In this case two do-loops use one common continue statement
do 5 ...
do 5 ...
5 continue
This is not allowed and can be fixed by inserting another continue with another label or, better, by using end do.

Related

Using varibles in subroutines without passing them in Fortran [duplicate]

This question already has answers here:
Host Association vs Use Association in Fortran
(1 answer)
What are the ways to pass a set of variable values through the subroutine to a function without common block?
(3 answers)
Closed 1 year ago.
I start to work on an older Fortran code that uses heavily the following "feature":
subroutine sample
integer*4 :: a, b
a = 1
b = 1
call increment(b)
print *, a, b ! Prints "2 2"
contains
subroutine increment(c)
implicit none
integer*4, intent(inout) :: c
c = c + 1
a = a + 1
end subroutine increment
end subroutine sample
On multiple occasions in the code, a variable from a subroutine is used in (sub)subroutine without passing it through arguments. Before someone points it out, I don't think this is a good coding paradigm, but it is a code I should work on, and I have to deal with it.
My problem is I cannot find in the Fortran language reference if this is actually legal. I never used this "feature" I thought it is not legal but this code works for 20 years compiled with GCC, intel Fortran, pgi, nvhpc without a problem. Very recently I tried to compile it with one-API, but on multiple occasions, the variables in (sub)subroutine contained rubbish data (but not all the time).
My question is if this is actually a legal thing to do? Is it only a part of other compilers dialects? Or is it an oneapi's bug?

Fortran Type mismatch in argument n at 1 passed REAL(8) to integer (4)

I'm having a problem with a fortran 77 project (Yes i know it's archaic, but my prof requres us to program in fixed form fortran)
So I'm having a problem with a subroutine, which should read an N dimension Vector, which should be a column. the code for this looks like: (its still an early draft for my homework, just trying to figure out how to call a subroutine the rest of the code will be done if i can compile this problem)
Program gauss
implicit double precision (A-H,O-Z)
!he directly asked for implicit typing
call Vread(V(N))
end program
Subroutine Vread(V,N)
Implicit double precision (A-H,O-Z)
dimension V(N)
read(*,*) (V(I),I=1,N)
return
end
So my problem is: If I try to compile it with gfortran gauss.exe -o gauss.f the compiler returns with error:
Type mismatch argument 'n' at(1); passed REAL(8) to Integer(4)
In your main program you write
call Vread(V(N)) ! this passes a rank-1 vector with N elements
but your subroutine is declared
Subroutine Vread(V,N) ! this requires 2 arguments
Change the call to
call Vread(V,N)
and let your professor know that the 21st Century arrived a while age. Note too that it is possible to write 21C Fortran in fixed-form. It doesn't make much sense, but might enable you to toe the line while developing in a more modern version of the language.
!he directly asked for implicit typing
I trust that you are in a jurisdiction where you do not pay directly for your education. If you are paying fees then demand more, you're being cheated.

Why are resulsts of silverfrost and gfortran different?

When I run my code with Silverfrost fortran, the result is -2.987531633638E-02. But with gfortran (under cygwin and ubuntu linux) it is -2.9875316336381942E-002. My code is here:
program seebeck
real*8::ss
integer::ix,i
complex,parameter::i1=(0.0,1.0)
call quad3d(0.,190.,ss)
write(*,*) "result:",ss
stop
end program seebeck
SUBROUTINE quad3d(x1,x2,ss)
REAL:: x1,x2
external f1
real*8::ss,f1
call qgausep(f1,x1,x2,ss)
return
END
SUBROUTINE qgausep(f2,a,b,ss)
external f2
REAL:: a,b
real*8::ss,f2
INTEGER j
REAL*8 dx,xm,xr,w(5),x(5)
SAVE w,x
DATA w/.2955242247,.2692667193,.2190863625,.1494513491,.0666713443/
DATA x/.1488743389,.4333953941,.6794095682,.8650633666,.9739065285/
xm=0.5*(b+a)
xr=0.5*(b-a)
ss=0
do 11 j=1,5
dx=xr*x(j)
ss=ss+w(j)*(f2(xm+dx)+f2(xm-dx))
11 continue
ss=xr*ss
return
END
function f1(t)
real*8::t,f1
f1=cos(t)/(1+exp(t))**2
end function
There is a huge difference between the two results. I cannot explain the cause of this difference as a floating point inaccuracy.
Note: My code is a draft version and has no physical meaning.
This has something to do with how different compilers handling your data assignment at line 26/27 of your code. You defined both w and x as double-precision arrays, but only initialize them with lower precision values. This will introduce some floating point inaccuracy. In fact if I pass your code through the NAG compiler (which is known to be very strict), it gives a warning:
Warning: test.f90, line 26: Low-precision data-value assigned to high-precision data-object
To confirm, you can print out the values in array w and x to see if they are different when using different compilers.

Have a function in fortran return a reference that can be placed on the left-hand-side of an assignment

As stated in the title, I want to directly modify data that I access through a pointer retrieved from a function. Having a reference returned by a function appearing on the l.h.s. of an assignment(=) is no issue in C++ but the following minimal example in fortran errors out:
module test_mod
implicit none
integer, target :: a=1, b=2, c=3 ! some member variables
contains
function get(i)
integer, pointer :: get
integer, intent(in) :: i
select case (i)
case (1)
get => a
case (2)
get => b
case (3)
get => c
end select
end function get
end module test_mod
program test
use test_mod
implicit none
integer, pointer :: i_p
!> prints out 1 2 3
print*, get(1), get(2), get(3)
!> this is what I want but I get the error
!> Error: 'get' at (1) is not a variable
get(2) = 5
!> this works but is not what I want
i_p => get(2)
i_p = 5
end program test
Is there any way to accomplish this behaviour; maybe I'm missing some attributes? I would like to bypass writing any setter routines such as
set(i,value)
since it should mimic the appearance of an array.
In my application, the member variables a,b,c are actually arrays of different size
a = [a1, a2, a3]
b = [b1, b2]
c = [c1]
and I want the getter get(i,j) to mimic a matrix of pointers
j = 1 2 3
i = 1: [[a1, a2, a3],
i = 2: [b1, b2, XX],
i = 3: [c1, XX, XX]]
wehre XX would be referencing to null().
Update:
I am using gfortran (version 5.2.0) and the deployment machines would have only versions starting from 4.6.x and upwards. Therefore, the suggested fortran 2008 standard features are unfortunately not available to me. Is it possible to mimic the behaviour described above without having a compiler supporting it out of the box?
Update 2:
So I ended up implementing a structure as follows
type Vec_t
integer, allocatable, dimension(:) :: vec
end type Vec_t
type(Vec_t), allocatable, dimension(:), target :: data
which I initialise like this (my triangular matrix application I mention at the end)
allocate(data(max))
do i=1,max
allocate(data(i)%vec(i))
end do
and I access & write to it through
print*, data(2)%vec(1)
data(2)%vec(1) = 5
which is not precisely what I was after but good enough for my application.
Let's look at what you want to do:
get(2)=5
and the error message
Error: 'get' at (1) is not a variable
That looks pretty comprehensive: you can't do what you want. Or, perhaps...
get(2) is indeed, under the rules of Fortran 2003, not a variable. In Fortran 2003 a variable is given by the rules R601 and R603, which is a list of designators.
The left-hand side of an assignment must be a variable.
But look at Fortran 2008 and its definition of a variable. Now a variable is either one of those same designators (or ones related to coarrays or complex parts), but it could also (C602 to R602) be a function reference which
shall have a data pointer result.
This is summarized in the introduction of Fortran 2008, detailing the extensions over Fortran 2003, as
A pointer function reference can denote a variable in any variable definition context.
get(2) is a reference to a function that has a data pointer result. get(2) then may appear on the left-hand side of an assignment statement under the rules of Fortran 2008.
Alas, this interpretation of Fortran is not widely supported by current compilers: at the time of answering just the Cray compiler.
This means that this answer is really saying that you have two options: switch compiler or wait until this feature is more widespread. As both of these are likely impractical, you probably want another answer which gives something slightly more portable as a workaround.
I prefer my link to that given by innoSPG, as although this latter is based on the former, the description of the appropriate field "Pointer functions - pointer function ref is a variable" is slightly more clear. This is, though, a more accessible document and a viable alternative.

Does fortran function pass by const reference?

I'm learning how to use functions in fortran and I came across several cases which made me believe that fortran function pass the argument by const reference. When I say "pass by const reference", I'm saying it in C++ sense. I searched online and didn't find related documents. The code which makes me believe fortran functions pass arguments by const reference is as follows.
program try
implicit none
real sq
real a,b
write(*,*) sq(2)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
sq=x**2
return
end
The output for this is
0.0000000E+00
4.000000
This result supports the idea that fortran functions pass arguments by reference, since sq(2) doesn't work. After this code, I put a new line x=x+1 inside the definition of sq. The code looks like
program try
implicit none
real sq
real a,b
write(*,*) sq(2)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
x=x+1
sq=x**2
return
end
This code does compile, but when I run it, it gives the following error
forrtl: severe (180): SIGBUS, bus error occurred
Image PC Routine Line Source
a.out 00000001000014DB Unknown Unknown Unknown
a.out 000000010000144C Unknown Unknown Unknown
Stack trace terminated abnormally.
I guess I got this error because I can't modify the argument inside the function definition, which makes me believe that the argument is passed by const reference. The compiler I'm using is ifort 12.0.0. I'm running it on Mac OS X 10.6.8. Can anyone tell me whether my guess is true?
Update: According to the comment of #Jean, after modifying sq(2) to sq(2.0). The first example will work, the second one still gives the same error. The modified version of the first example is
program try
implicit none
real sq
real a,b
write(*,*) sq(2.0)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
sq=x**2
return
end
The output is
4.000000
4.000000
I don't know why this simple modification will work. Hopefully someone can clarify for me.
As pointed out in the comments, you should use explicit interfaces. Then the compiler is able to check argument types. There are different possibilities to do that. For larger programs use modules, for smaller ones, you can include your procedure in the main program by using the contains keyword.
Here is a slightly modified version of your code:
program try
implicit none
real a,b
write(*,*) sq(2.0)
a=2
write(*,*) sq(a)
contains
real function sq(x)
real, value :: x
x=x+1
sq=x**2
return
end
end program
What's new?
the function is included in the main program with the contains keyword. When doing so, you don't have to declare sq like you did before in your third line. Also, the compiler can now check the argument type. Try to write 2 instead of 2.0 and see what happens.
You are right about the references. In Fortran arguments are passed by reference. If your argument is not a variable but just a number, then you can not change it within the procedure because it is constant. If you want variables to be passed by value, use the value keyword.