I am trying to write a fortran code, but when I am trying to pass data from one variable in subroutine to another, error is coming as:
common /c/kf,eff,q
1
Warning: Padding of 4 bytes required before 'q' in COMMON 'c' at (1); reorder elements or use -fno-align-commons.
The value of q from subroutine input to calculation is not being passed.
If the value of q at subroutine input is 5e-3, the value of q at subroutine calculation is 3.57e-315
Kindly help
See the code
implicit none
call input
call calculation
stop
end
subroutine input
real*8 n
real*8 l1,l2,l3,d,kf,eff,z1,z2,rho,mu,pin,pout,l4
common /a/l1,l2,l3,l4,d
common /c/kf,eff,q
common /e/z1,z2
common /d/rho,mu,pin,pout
common /b/n
print*,"enter the lengths of the pipe at various sections (4)"
read(*,*) l1,l2,l3,l4
print*,"enter the diameter of the pipe"
read(*,*) d
print*,"enter the volumetric flow rate (m3/s)"
read(*,*) q
print*,"enter the number of elbows to be added"
read(*,*) n
print*,"enter firction coefficient for elbow"
read(*,*) kf
print*,"enter the pump efficiency"
read(*,*) eff
print*,"enter the datum height (m)"
read(*,*)z1
print*,"enter the final height (m)"
read(*,*)z2
print*,"enter the density of the fluid (kg/m3)"
read(*,*)rho
print*,"enter the viscosity of the fluid (kg/ms)"
read(*,*)mu
print*,"enter the inlet and exit pressure (KPa)"
read(*,*) pin,pout
print*,q
end
subroutine calculation
real*8 n
real*8 g,pi,v2,v1,vdif,z2,z1,head,v,q,d
real*8 p,pout,pin,rho,re,mu,f,kc,hc,kf,hf
real*8 kex,hex,l,l1,l2,l3,l4,fp,ft,Ws,Wp,m,power
common /a/l1,l2,l3,l4,d
common /c/kf,eff,q
common /e/z1,z2
common /d/rho,mu,pin,pout
common /b/n
parameter (g=9.8,pi=3.14)
print*,q,d
v= (4*q)!/(pi*(d**2))
v1=v
v2=v
vdif=0.5*((v2**2)-(v1**2))
head=g*(z2-z1)
p=(pout-pin)/(rho)
re=(d*v*rho)/(mu)
print*,v,vdif,p,head,re
if (re>2000) then
f=16/re
else
f=0.079*(re**(-0.25))
endif
kc=0.55
hc=kc*(v**2)/2
hf=n*kf*(v**2)/2
kex=1
hex=kex*(v**2)/2
l=l1+l2+l3+l4
fp=(4*f*l*(v**2))/(2*d)
ft=hc+hf+hex+fp
Ws=-head-vdif-ft
Wp=-(Ws/eff)
m=q*rho
power=m*Wp
print*, "the power required by the pump is", power
end
It doesn’t look like you define variable q as real*8 in subroutine input. You don’t specify implicit none in the input subroutine, so it’ll be implicitly declared real*4. That means your common blocks are mapping out two different regions in memory starting from the same initial memory address. Fortran interprets memory in common blocks according to the variable types and their order. That means in one subroutine q is a double and in the other it’s a float. That’s why you’re getting the value change.
Related
I want to fine eigenvalue and eigenvector of matrix that is symmetric positive definite define. However, I can not use function GVCSP in Fortran in Linux. Are there another function in Fortran that is equivalent GVCSP function.
here is my code:
program main
integer , parameter :: n=4
real*8 A(n,n), eigval(n), eigvec(n,n),eigvalmatrix(n,n)
integer i,j
do i=1,n
eigval(i)=0
do j=1,n
eigvec(i,j)=0
eigvalmatrix(i,j)=0
end do
end do
A(1,1)=-1
A(1,2)=0
A(1,3)=4
A(1,4)=2
A(2,1)=0
A(2,2)=2
A(2,3)=3
A(2,4)=-2
A(3,1)=4
A(3,2)=3
A(3,3)=0
A(3,4)=-4
A(4,1)=2
A(4,2)=-2
A(4,3)=-4
A(4,4)=1
call GVCSP(A, eigvalmatrix, eigval,eigvec)
end program
I've written a piece of FORTRAN code that solves first order differential equations, for example the one that is in the function at the momement. However, I want to use it for second order ODES (and eventually 2nd order coupled ODEs), but I'm struggling to adapt it. Here's the code:
program rungekutta
implicit none
integer :: istat
real(8)::a,b,h,y_0,t
write(*,*)"Enter interval a,b, step-size h and y_0"
read(*,*)a,b,h,y_0
open(unit=1, file="rungekutta.dat",status='replace', iostat=istat)
if (istat .ne. 0) stop 'error opening rungekutta.dat'
call RungeKuttaSub(y_0,a,b,h)
close(1)
contains
subroutine RungeKuttaSub(y_0,a,b,h)
implicit none
real(8), intent(inout)::a,h,b, y_0
real(8):: y,t, F_1, F_2, F_3, F_4
t=a
y=y_0
do while(t<=b)
F_1=h*f(y,t)
F_2=h*f(y+(1d0/2d0)*F_1, t+h*(1d0/2d0))
F_3=h*f(y+(1d0/2d0)*F_2, t+h*(1d0/2d0))
F_4=h*f(y+F_3,t+h)
y=y+(F_1+2d0*F_2+2d0*F_3+F_4)/6d0
write(1,*)t, y
t=t+h
end do
end subroutine
function f(y,t)
implicit none
real(8)::f,y,t,pi
pi=acos(-1d0)
f=-y+sin(pi*2d0*t)
end function
end program
So as you can see the differential in the function at the moment is y'(t) = -y(t) + sin(2*pi*t). How can I update this for 2nd order ODEs?
Thanks.
There are several threads with similar titles of mine, but I do not believe they are the same. One was very similar fortran pass allocated array to main procedure, but the answer required Fortran 2008. I am after a Fortran 90/95 solution.
Another very good, and quite similar thread is Dynamic array allocation in fortran90. However in this method while they allocate in the subroutine, they don't ever appear to deallocate, which seems odd. My method looks on the surface at least to be the same, yet when I print the array in the main program, only blank spaces are printed. When I print in the subroutine itself, the array prints to screen the correct values, and the correct number of values.
In the following a MAIN program calls a subroutine. This subroutine reads data into an allocatable array, and passes the array back to the main program. I do this by using small subroutines each designed to look for specific terms in the input file. All of these subroutines are in one module file. So there are three files: Main.f90, input_read.f90 and filename.inp.
It seems then that I do not know how to pass an array that is allocatable in program Main.f90 as well as in the called subroutine where it is actually allocated, sized, and then deallocated before being passed to program Main. This perhaps sounds confusing, so here is the code for all three programs. I apologize for the poor formatting when I pasted it. I tried to separate all the rows.
main.f90:
Program main
use input_read ! the module with the subroutines used for reading filename.inp
implicit none
REAL, Allocatable :: epsilstar(:)
INTEGER :: natoms
call Obtain_LJ_Epsilon(epsilstar, natoms)
print*, 'LJ Epsilon : ', epsilstar
END Program main
Next is the module with a subroutine (I removed all but the necessary one for space), input_read.f90:
module input_read
contains
!===============================================================
!===============================================================
Subroutine Obtain_LJ_Epsilon(epsilstar,natoms)
! Reads epsilon and sigma parameters for Lennard-Jones Force-Field and also
! counts the number of types of atoms in the system
!===============================================================
!===============================================================
INTEGER :: error,line_number,natoms_eps,i
CHARACTER(120) :: string, next_line, next_next_line,dummy_char
CHARACTER(8) :: dummy_na,dummy_eps
INTEGER,intent(out) :: natoms
LOGICAL :: Proceed
real, intent(out), allocatable :: epsilstar(:)
error = 0
line_number = 0
Proceed = .true.
open(10,file='filename.inp',status='old')
!=============================================
! Find key word LJ_Epsilon
!=============================================
DO
line_number = line_number + 1
Read(10,'(A120)',iostat=error) string
IF (error .NE. 0) THEN
print*, "Error, stopping read input due to an error reading line"
exit
END IF
IF (string(1:12) == '$ LJ_epsilon') THEN
line_number = line_number + 1
exit
ELSE IF (string(1:3) == 'END' .or. line_number > 2000) THEN
print*, "Hit end of file before reading '$ LJ_epsilon' "
Proceed = .false.
exit
ENDIF
ENDDO
!========================================================
! Key word found, now determine number of parameters
! needing to be read
!========================================================
natoms_eps = -1
dummy_eps = 'iii'
do while ((dummy_eps(1:1) .ne. '$') .and. (dummy_eps(1:1) .ne. ' '))
natoms_eps = natoms_eps + 1
read(10,*) dummy_eps
enddo !we now know the number of atoms in the system (# of parameters)
close(10)
Allocate(epsilstar(natoms_eps))
epsilstar = 0.0
!============================================================
! Number of parameters found, now read their values
!============================================================
if(Proceed) then
open(11,file='filename.inp',status='old')
do i = 1,line_number-1
read(11,*) ! note it is not recording anything for this do loop
enddo
do i = 1,natoms_eps
read(11,*) dummy_char
read(dummy_char,*) epsilstar(i) ! convert string read in to real, and store in epsilstar
enddo
close(11)
PRINT*, 'LJ_epsilon: ', epsilstar ! printing to make sure it worked
endif
deallocate(epsilstar)
END Subroutine Obtain_LJ_Epsilon
end module input_read
And finally the input file: filename.inp
# Run_Type
NVT
# Run_Name
Test_Name
# Pressure
1.0
# Temperature
298.15
# Number_Species
# LJ_epsilon
117.1
117.1
117.1
# LJ_sigma
3.251
3.251
3.251
END
And again, I can't figure out how to pass the allocated epsilstar array to the main program. I have tried passing an unallocated array to the subroutine from the main.f90, allocating it inside, passing it back, and deallocating it in the main.f90, but that did not work. I have tried it as the code currently is... the code works (i.e. is bug free) but it does not pass epsilstar from the subroutine where it correctly finds it and creates an array.
It turns out that the mistake I made was in deallocating the array in the subroutine before passing it to the main program. By NOT deallocating, the array was sent back fine. Also, I do not deallocate in the main program either.
I am trying to write a FORTRAN subroutine for ABAQUS that would modify the seepage coefficient and thus the flow depending on whether there is contact on the surface. In order to do so I need 2 subroutines URDFIL to retrieve the node data and FLOW to modify the seepage coefficient.
However, when I compile my subroutine I get the following errors:
flow_us.for(81): error #6837: The leftmost part-ref in a data-ref can not be a function reference. [K_ELE_DETAILS]
IF(K_ELE_DETAILS(E_INDX)%IS_CONT(N_INDX).EQ.0)THEN
----------^
flow_us.for(81): error #6158: The structure-name is invalid or is missing. [K_ELE_DETAILS]
IF(K_ELE_DETAILS(E_INDX)%IS_CONT(N_INDX).EQ.0)THEN
Obviously it is repeated for the 3 lines (if's) that contain such structure (81,8, and 89).
Please find the code below and hopefully someone will be able to help
****************************************************************************************
***SUBROUTINE FOR ADAPTIVE FLUID FLOW
****************************************************************************************
****************************************************************************************
**
**
**
*USER SUBROUTINE
SUBROUTINE URDFIL(LSTOP,LOVRWRT, KSTEP, KINC, DTIME, TIME)
INCLUDE 'ABA_PARAM.INC'
C
DIMENSION ARRAY(513),JRRAY(NPRECD,513),TIME(2)
EQUIVALENCE (ARRAY(1),JRRAY(1,1))
C DECLARATIONS
TYPE ELE_DATA
SEQUENCE
DOUBLE PRECISION :: NODE_COORD(9)
DOUBLE PRECISION :: OPP_NODE_COORD(9)
DOUBLE PRECISION :: IPT_COORD(9)
DOUBLE PRECISION :: POR(3)
DOUBLE PRECISION :: OPP_POR(3)
INTEGER :: ELE_NUM
INTEGER :: OPP_ELE_NUM
INTEGER :: NODE_NUM(3)
INTEGER :: OPP_NODE_NUM(3)
INTEGER :: IPT_NUM(3)
INTEGER :: OPP_IS_CONT(3)
END TYPE ELE_DATA
TYPE(ELE_DATA)::K_ELE_DETAILS(500)
COMMON K_ELE_DETAILS
PARAMETER (THRESHOLD_CSTRESS=1.0E-6)
*******************************************************
INTEGER :: NO_OF_NODES
INTEGER :: NO_OF_ELEMENTS
INTEGER :: NO_OF_DIM
COMMON NO_OF_DIM, NO_OF_NODES, NO_OF_ELEMENTS
********************************************************
C INITIALIZE
LSTOP=0
LOVRWRT=1
LOP=0
NO_OF_NODES=10000
NO_OF_ELEMENTS=10000
NO_OF_DIM=2
DO K1=1,999999
CALL DBFILE(0, ARRAY,JRCD)
IF (JCRD.NE.0) GO TO 110
KEY=JRRAY(1,2)
*******************************************************
C THE KEYS USED IN THE FOLLOWING LINES REFER
C TO INFORMATION ON THE SURFACE, NODES, CONTACT ETC
IF (KEY.EQ.1501) THEN
ELSE IF (KEY.EQ.1502)THEN
ELSE IF(KEY.EQ.1911) THEN
ELSE IF(KEY.EQ.108.AND.SURFACE_N_SET.EQ.'N_TOP') THEN
ELSE IF(KEY.EQ.107.AND.SURFACE_N_SET.EQ.'N_TOP') THEN
ELSE IF(KEY.EQ.1503)THEN
ELSE IF(KEY.EQ.1504.AND.K_NODE_SET.EQ.'N_TOP')THEN
ELSE IF(KEY.EQ.1511.AND.K_NODE_SET.EQ.'N_TOP')THEN
C IS THE NODE IN CONTACT?
120 CONTINUE
END IF
END DO
110 CONTINUE
RETURN
END
**********************************************************
**********************************************************
*USER SUBROUTINE
SUBROUTINE FLOW(H, SINK, KSTEP, KINC, TIME, NOEL, NPT, COORDS,
1 JLTYP,SNAME)
INCLUDE 'ABA_PARAM.INC'
C
DIMENSION TIME(2), COORDS(3)
CHARACTER*80 SNAME
MIN_DIST=10E-20
DO K25=1,NO_OF_ELEMENTS
DO K26=1,NO_OF_NODES
C FINDS THE CLOSEST NODE TO THE INTEGRATION POINT NPT
END DO
END DO
C NOT IN CONTACT
IF(K_ELE_DETAILS(E_INDX)%IS_CONT(N_INDX).EQ.0)THEN
IF(K_ELE_DETAILS(E_INDX)%POR(N_INDX).GE.0) THEN
SINK=0
H=0.001
ELSE
SINK=0
H=1
END IF
ELSE IF(K_ELE_DETAILS(E_INDX)%IS_CONT(N_INDX).EQ.1)THEN
C IF THERE IS CONTACT
SINK=0
H=0
END IF
RETURN
END
I think you meant to write
IF(K_ELE_DETAILS(E_INDX)%OPP_IS_CONT(N_INDX).EQ.0) THEN
instead of
IF(K_ELE_DETAILS(E_INDX)%IS_CONT(N_INDX).EQ.0)THEN
Also, if you intent to extend this code with type-bound procedures, you cannot reference a component of a function result of derived data type without an appropriate interface. Such issues are rarely encountered if the type declaration is confined to a module. The module will automatically generate the correct interface for type-bound procedures.
Hermite Interpolation woes
I am trying to find the Newton Dividing Differences for the function and derivative values of a given set of x's. I'm running into serious problems with my code working for tiny examples, but failing on bigger one's. As is clearly visible, my answers are very much larger than they original function values.
Does anybody have any idea what I'm doing wrong?
program inter
implicit none
integer ::n,m
integer ::i
real(kind=8),allocatable ::xVals(:),fxVals(:),newtonDivDiff(:),dxVals(:),zxVals(:),zdxVals(:),zfxVals(:)
real(kind=8) ::Px
real(kind=8) ::x
Open(Unit=8,File="data/xVals")
Open(Unit=9,File="data/fxVals")
Open(Unit=10,File="data/dxVals")
n = 4 ! literal number of data pts
m = n*2+1
!after we get the data points allocate the space
allocate(xVals(0:n))
allocate(fxVals(0:n))
allocate(dxVals(0:n))
allocate(newtonDivDiff(0:n))
!allocate the zvalue arrays
allocate(zxVals(0:m))
allocate(zdxVals(0:m))
allocate(zfxVals(0:m))
!since the size is the same we can read in one loop
do i=0,n
Read(8,*) xVals(i)
Read(9,*) fxVals(i)
Read(10,*) dxVals(i)
end do
! contstruct the z illusion
do i=0,m,2
zxVals(i) = xVals(i/2)
zxVals(i+1) = xVals(i/2)
zdxVals(i) = dxVals(i/2)
zdxVals(i+1) = dxVals(i/2)
zfxVals(i) = fxVals(i/2)
zfxVals(i+1) = fxVals(i/2)
end do
!slightly modified business as usual
call getNewtonDivDiff(zxVals,zdxVals,zfxVals,newtonDivDiff,m)
do i=0,n
call evaluatePolynomial(m,newtonDivDiff,xVals(i),Px,zxVals)
print*, xVals(i) ,Px
end do
close(8)
close(9)
close(10)
stop
deallocate(xVals,fxVals,dxVals,newtonDivDiff,zxVals,zdxVals,zfxVals)
end program inter
subroutine getNewtonDivDiff(xVals,dxVals,fxVals,newtonDivDiff,n)
implicit none
integer ::i,k
integer, intent(in) ::n
real(kind=8), allocatable,dimension(:,:) ::table
real(kind=8),intent(in) ::xVals(0:n),dxVals(0:n),fxVals(0:n)
real(kind=8), intent(inout) ::newtonDivDiff(0:n)
allocate(table(0:n,0:n))
table = 0.0d0
do i=0,n
table(i,0) = fxVals(i)
end do
do k=1,n
do i = k,n
if( k .eq. 1 .and. mod(i,2) .eq. 1) then
table(i,k) = dxVals(i)
else
table(i,k) = (table(i,k-1) - table(i-1,k-1))/(xVals(i) - xVals(i-k))
end if
end do
end do
do i=0,n
newtonDivDiff(i) = table(i,i)
!print*, newtonDivDiff(i)
end do
deallocate(table)
end subroutine getNewtonDivDiff
subroutine evaluatePolynomial(n,newtonDivDiff,x,Px,xVals)
implicit none
integer,intent(in) ::n
real(kind=8),intent(in) ::newtonDivDiff(0:n),xVals(0:n)
real(kind=8),intent(in) ::x
real(kind=8), intent(out) ::Px
integer ::i
Px = newtonDivDiff(n)
do i=n,1,-1
Px = Px * (x- xVals(i-1)) + newtonDivDiff(i-1)
end do
end subroutine evaluatePolynomial
Values
x f(x) f'(x)
1.16, 1.2337, 2.6643
1.32, 1.6879, 2.9989
1.48, 2.1814, 3.1464
1.64, 2.6832, 3.0862
1.8, 3.1553, 2.7697
Output
1.1599999999999999 62.040113431002474
1.3200000000000001 180.40121445431600
1.4800000000000000 212.36319446149312
1.6399999999999999 228.61845650513027
1.8000000000000000 245.11610836104515
You are accessing array newtonDivDiff out of bounds.
You are first allocating it as 0:n (main program's n) then you are passing to subroutine getNewtonDivDiff as 0:n (the subroutine's n) but you pass m (m=n*2+1) to the argument n. That means you tell the subroutine that the array has bounds 0:m which is 0:9, but it has only bounds 0:4.
It is quite difficult to debug the program as it stands, I had to use valgrind. If you move your subroutines to a module and change the dummy arguments to assumed shape arrays (:,:) then the bound checking in gfortran (-fcheck=all) will catch the error.
Other notes:
kind=8 is ugly, 8 can mean different things for different compilers. If you want 64bit variables, you can use kind=real64 (real64 comes from module iso_fortran_env in Fortran 2008) or use selected_real_kind() (Fortran 90 kind parameter)
You do not have to deallocate your local arrays in the subroutines, they are deallocated automatically.
Your deallocate statement in the main program is after the stop statement, it will never be executed. I would just delete the stop, there is no reason to have it.