Trying to use netlib code (QUADPACK). What is xerror? - fortran

I'm trying to figure out how to use quadpack.
In a single folder, I located the contents of "qag.f plus dependencies" and the code blow as qag_test.f:
(maybe this code itself is not very important. This is in fact just a snippet from the quadpack document)
REAL A,ABSERR,B,EPSABS,EPSREL,F,RESULT,WORK
INTEGER IER,IWORK,KEY,LAST,LENW,LIMIT,NEVAL
DIMENSION IWORK(100),WORK(400)
EXTERNAL F
A = 0.0E0
B = 1.0E0
EPSABS = 0.0E0
EPSREL = 1.0E-3
KEY = 6
LIMIT = 100
LENW = LIMIT*4
CALL QAG(F,A,B,EPSABS,EPSREL,KEY,RESULT,ABSERR,NEVAL,
* IER,LIMIT,LENW,LAST,IWORK,WORK)
C INCLUDE WRITE STATEMENTS
STOP
END
C
REAL FUNCTION F(X)
REAL X
F = 2.0E0/(2.0E0+SIN(31.41592653589793E0*X))
RETURN
END
Using gfortran *.f (installed as MinGW 64bit), I got:
C:\Users\username\AppData\Local\Temp\ccIQwFEt.o:qag.f:(.text+0x1e0): undefined re
ference to `xerror_'
C:\Users\username\AppData\Local\Temp\cc6XR3D0.o:qage.f:(.text+0x83): undefined re
ference to `r1mach_'
(and a lot more of the same r1mach_ error)
It seems r1mach is a part of BLAS (and I don't know why it's not packaged in here but obtained as "auxiliary"), but what is xerror?
How do I properly compile this snippet in my environment, Win7 64bit (hopefully without Cygwin)?
Your help is very much appreciated.

xerror is an error reporting routine. Looking at the way it is called, it appears to use Hollerith constants (the ones where "foo" is written as 3hfoo).
if(ier.ne.0) call xerror(26habnormal return from qag ,
* 26,ier,lvl)
xerror in turn calls xerrwv, passing along the arguments (plus a few more).
This was definitely written before Fortran 77 became widespread.
Your best bet would be to use a compiler which still supports Hollerith constants, pull in all the dependencies (xeerwv has a few more, I don't know why you didn't get them from netlib) and run it through the compiler of your choice. Most compilers, including gfortran, support Hollerith; just ignore the warnings :-)
You will possibly need to modify one routine, that is xerprt. With gfortran, you could write this one as
subroutine xerprt(c,n)
character(len=1), dimension(n) :: c
write (*,'(500A)') c
end subroutine xerprt
and put this one into a separate file so that the compiler doesn't catch the rank violation (I know, I know...)

Related

Changing long variables to int type in large program

I am facing compatibility issues with integer types while migrating a large code base to x64 systems.
Fortran routines which expect INTEGER*4 are passed integers defined as long on the C/C++ side. Here is some sample code :
Fortran interface :
SUBROUTINE FOO(N)
INTEGER*4 N
!! DO SOME WORK
END
C/C++ code :
long n = 1;
FOO(&n);
Of course, this does not work when compiled for x64, and the integer needs to be defined as an int. Those types of calls are made countless times, and replacing them by hand will take forever.
Is there a more efficient way to make those changes ?
First try a find-and-replace like Steve suggests in the comments, this should work:
sed -i 's/integer\*4/integer\*8/gI' *.f90
where -i gives replacement in the file, I at the end gives case-insensitive search, and the * symbols are escaped with \*. You might want to change *.f90 to the extension you have or to *.f*.

Wrong results from Fortran function called from Julia (0.6.2) on Windows

I found a small helper subroutine from a larger legacy codebase that computes some statistics for a vector and have compiled it alone and am trying to call it from Julia (0.6.2) for practice.
To begin, I have found some forum posts and discourse threads, but I wanted to double check since the language is developing quickly and some may be using outdated syntax like this one. Additionally, I am using Windows and many of the forum posts I came across reference .so files, which to my understanding is for UNIX systems, not Windows?
The Fortran code I am referencing (called meansd.f) in its entirety is:
SUBROUTINE MEANSD (A,N,ABAR,VAR,STD)
IMPLICIT NONE
C COMPUTE THE MEAN AND STANDARD DEVIATION OF A REAL VECTOR.
C PARAMETERS:
C A: REAL VECTOR TO COMPUTE MEAN AND STANDARD DEVIATION OVER.
C N: LENGTH OF A.
C ABAR: COMPUTED MEAN OF A.
C VAR: VARIANCE OF A.
C STD: COMPUTED STANDARD DEVIATION OF A.
C
REAL A(N)
INTEGER I,N
DOUBLE PRECISION APX, ABAR, VAR, STD, SUM, SUMSQ, DN, Z
C
DN=N
APX=0D0
DO 30 I=1,N
APX=APX+A(I)
30 CONTINUE
APX=APX/DN
SUM=0D0
SUMSQ=0D0
DO 40 I=1,N
Z=A(I)-APX
SUM=SUM+Z
SUMSQ=SUMSQ+Z*Z
40 CONTINUE
ABAR=SUM/DN
VAR=(SUMSQ-(SUM*ABAR))/(DN-1)
STD=DSQRT(VAR)
ABAR=ABAR+APX
RETURN
END
I have compiled this using gcc
gcc (x86_64-posix-seh-rev1, Built by MinGW-W64 project) 7.2.0
largely following this question, which completes with no errors:
gfortran -c meansd.f
gfortran -shared -fPIC meansd.o -o meansd.dll
when I test with Libdl, everything seems to return fine and I get returned a pointer
path=joinpath(pwd(),"meansd.dll")
dl=Libdl.dlopen(path)
and then I try to build my ccall function as:
a_ref=Ref{Array{Float64,1}}([5.0,5.0,5.0,5.0,5.0])
i_ref=Ref{Int64}(1)
n_ref=Ref{Int64}(length([5.0,5.0,5.0,5.0,5.0]))
apx_ref=Ref{Float64}(0)
abar_ref=Ref{Float64}(0)
var_ref=Ref{Float64}(0)
std_ref=Ref{Float64}(0)
sum_ref=Ref{Float64}(0)
sumsq_ref=Ref{Float64}(0)
dn_ref=Ref{Float64}(0)
z_ref=Ref{Float64}(0)
ccall((:meansd_,"meansd.dll"),Void,(
Ref{Array{Float64,1}},#A
Ref{Int64}, #I
Ref{Int64}, #N
Ref{Float64}, #APX #I think I have to pass these too?
Ref{Float64}, #ABAR
Ref{Float64}, #VAR
Ref{Float64}, #STD
Ref{Float64}, #SUM
Ref{Float64}, #SUMSQ
Ref{Float64}, #DN
Ref{Float64}, #Z
),a_ref,i_ref,n_ref,apx_ref,
abar_ref,var_ref,std_ref,sum_ref,sumsq_ref,dn_ref,z_ref)
This completes which is as far as I have gotten, but abar_ref is returned as NaN. I then made a Float/Int 32 version as well, which completes but abar_ref is returned as 0.0. I thought I should be using 64 bit, since I compiled with 64 bit gfortran.
I think I am messing up on how to pass the array, but I have tried as many different approached I could think of with no success.
I am also confused as to when to use Julia types vs the ccall types (Float32 vs Cint?). I have seen examples of both scattered among the web, but if I am reading correctly, there are underlying convert statements built in behind the scenes at this point which handle that?
Edit: expanded notes
Following Pierre's comments, I went back and re-read through the documentation and managed to get a working version:
I first removed instantiating any variables other than those named in the function call:
SUBROUTINE MEANSD (A,N,ABAR,VAR,STD).
Next, I re-read through the documentation section on calling FORTRAN, in particular this warning section.
Warning
For string arguments (char*) the Julia type should be Cstring (if NUL-
terminated data is expected) or either Ptr{Cchar} or Ptr{UInt8}
otherwise (these two pointer types have the same effect), as described
above, not String. Similarly, for array arguments (T[] or T*), the
Julia type should again be Ptr{T}, not Vector{T}.
The resulting code is:
#declare variables
a=Float32[1.0,2.0,3.0,4.0,5.0] #changed values from OP to have non-zero var/sd for demo
n=length(a) #works as Int32(length(a)) as well?
abar_ref=Ref{Float64}(0)
var_ref=Ref{Float64}(0)
std_ref=Ref{Float64}(0)
#call function
ccall((:meansd_,"meansd.dll"),Void,(
Ptr{Float32},#A
Ref{Int32}, #N
Ref{Float64}, #ABAR
Ref{Float64}, #VAR
Ref{Float64}, #STD
),a,n,abar_ref,var_ref,std_ref)
#check results
abar_ref[] #returns 3.00
var_ref[] #returns 2.50
std_ref[] #returns 1.58

fortran77 to fortran90 differences in output

I have downloaded the following fortran program dragon.f at http://www.iamg.org/documents/oldftp/VOL32/v32-10-11.zip
I need to do a minor modification to the program which requires the program to be translated to fortran90 (see below to confirm if this is truly needed).
I have managed to do this (translation only) by three different methods:
replacing comment line indicators (c for !) and line continuation
indicators (* in column 6 for & at the end of last line)
using convert.f90 (see https ://wwwasdoc.web.cern.ch/wwwasdoc/WWW/f90/convert.f90)
using f2f.pl (see https :// bitbucket.org/lemonlab/f2f/downloads)
Both 1) and 3) worked (i.e. managed to compile program) while 2) didn't work straight away.
However, after testing the program I found that the results are different.
With the fortran77 program, I get the "expected" results for the example provided with the program (the program comes with an example data "grdata.txt", and its example output "flm.txt" and "check.txt"). However, after running the translated (fortran90) program the results I get are different.
I suspect there are some issues with the way some variables are declared.
Can you give me recommendations in how to properly translate this program so I get the exact same results?
The reason I need to do it in fortran90 is because I need to input the parameters via a text file instead of modifying the program. This shouldnt be an issue for most of the parameters involved, except for the declaration of the last one, in which the size is determined from parameters that the program does not know a priori (see below):
implicit double precision(a-h,o-z)
parameter(lmax=90,imax=45,jmax=30)
parameter(dcta=4.0d0,dfai=4.0d0)
parameter(thetaa=0.d0,thetab=180.d0,phaia=0.d0,phaib=120.d0)
dimension f(0:imax,0:jmax),coe(imax,jmax,4),coew(4),fw(4)
So for example, I will read lmax, imax, jmax, dcta, dfai, thetaa, thetab, phaia, and phaib and the program needs to declare f and coe but as far as I read after googling this issue, they cannot be declared with an unknown size in fortran77.
Edit: This was my attempt to do this modification:
character fname1*100
call getarg(1,fname1)
open(10,file=fname1)
read(10,*)lmax,imax,jmax,dcta,dfai,thetaa,thetab,phaia,phaib
close(10)
So the program will read these constants from a file (e.g. params.txt), where the name of the file is supplied as an argument when invoking the program. The problem when I do this is that I do not know how to modify the line
dimension f(0:imax,0:jmax)...
in order to declare this array when the values imax and jmax are not known when compiling the program (they depend on the size of the data that the user will use).
As has been pointed out in the comments above, parameters cannot be read from file since they are set at compile time. Read them in as integer, declare the arrays as allocatable, and then allocate.
integer imax,jmax
real(8), allocatable :: f(:,:),coe(:,:,:)
read(10,*) imax,jmax
allocate(f(0:imax,0:jmax),coe(imax,jmax,4))
I found out that the differences in the results were attributed to using different compilers.
PS I ended up adding a lot more code than I intended at the beginning to allow reading data from netcdf files. This program in particular is really helpful for spherical harmonic expansion. [tag:spherical harmonics]

Fortran 95: inline evaluation of if-conditions

Here a small snippet of code that returns epsilon() for a real value:
program epstest
real :: eps=1.0, d
do
d=1.0+eps
if (d==1.0) then
eps=eps*2
exit
else
eps=eps/2
end if
end do
write(*,*) eps, epsilon(d)
pause
end program
Now, when I replace the if condition by
if (1.0+eps==1.0) then
the program should have the same in return but it unfortunately does not! I tested it with the latest (snapshot) release of g95 on Linux and Windows.
Can someone explain that issue to me?
Floating point arithmetic has many subtle issues. One form of source code can generate different machine instructions than another seemingly almost identical source code. For example, "d" might get stored to a memory location, while "1.0 + eps" might be evaluated solely with registers ... this can cause different precision.
More generally, why not use the intrinsic functions provided for Fortran 95 that disclose the characteristics of a particular precision of reals?

Fatal error F1002 compiler is out of heap space in pass 2 in MS Fortran Powerstation

I have a FORTRAN 77 program code. I am using Fortran Power Station 4.0 on Windows. It is a very long Finite element method code.
The code is the following :
1 Main Program starts with
PARAMETER (HLENGTH=600.0,VLENGTH=600.0,NHELE=6,NVELE=6,NTYPE=1)
PARAMETER (DENSITY=2.78E-6,POISON=0.34,THICK=1.0,EMODULE=6.87E4)
PARAMETER (NTOTALNODE=(NHELE+1)*(NVELE+1))
PARAMETER (NHNODE=NHELE+1,NVNODE=NVELE+1)
PARAMETER (MK=(NTOTALNODE-2*NHNODE-2*(NVNODE-2))*5)
PARAMETER (DELTAH=(HLENGTH+0.0)/(NHELE+0.0))
PARAMETER (DELTAV=(VLENGTH+0.0)/(NVELE+0.0))
DIMENSION NODEMATRIX(NTOTALELE,4)
REAL*8 STIFFMATRIX(20,20),MASSMATRIX(20,20)
REAL*8 STIFFMATRIXS(20,20),MASSMATRIXS(20,20)
DIMENSION NODEROWT(4),NODEROWT2(20)
DIMENSION NM(NVNODE,NHNODE)
REAL*8 GSM(NTOTALNODE*5,NTOTALNODE*5),NCARRIER(MK),
&GMM(NTOTALNODE*5,NTOTALNODE*5),AA(MK,MK),BB(MK,MK)
CALL STIFFMAT(STIFFMATRIX,DELTAV,DELTAH,THICK,EMODULE)
CALL MASSMAT(MASSMATRIX,DELTAV,DELTAH,THICK,DENSITY)
CALL STIFFMATS(STIFFMATRIXS,DELTAV,DELTAH)
CALL MASSMATS(MASSMATRIXS,DELTAV,DELTAH,DENSITY)
.
.
.
. etc
2 - The Subroutins are starts as following:
SUBROUTINE STIFFMAT(STIFFMATRIX,DELTAV,DELTAH,THICK,EMODULE)
REAL*8 STIFFMATRIX(20,20),B(6,20),BT(20,6),D(6,6)
REAL*8 CC(5),ZETAM(5),ETAM(5),CA,CB,ZETA,ETA,SUM,SUM2,SUM3
.
.
.etc
SUBROUTINE MASSMAT(MASSMATRIX,DELTAV,DELTAH,THICK,DENSITY)
REAL*8 MASSMATRIX(20,20),B(5,20),BT(20,5),D(5,5)
REAL*8 CC(5),ZETAM(5),ETAM(5),CA,CB,ZETA,ETA,SUM,SUM2,SUM3
.
.
.etc
SUBROUTINE MASSMATS(MASSMATRIXS,DELTAV,DELTAH,DENSITY)
REAL*8 MASSMATRIXS(20,20),B(5,20),BT(20,5),D(5,5),IS,JS,AS
REAL*8 CC(5),ZETAM(5),CA,ZETA,ETA,SUM,SUM2,SUM3
.
.
.etc
SUBROUTINE STIFFMATS(STIFFMATRIXS,DELTAV,DELTAH)
REAL*8 STIFFMATRIXS(20,20),B(3,20),BT(20,3),D(3,3)
REAL*8 CC(5),ZETAM(5),CA,ZETA,ETA,SUM,SUM2,SUM3
.
.
.etc
When I press the compile command it shows me the following message :
fatal error F1002: compiler is out of heap space in pass 2
I Googled the problem, and found the following solutions
But I did not understand the solution!
I do not know how to change the Zi option, where I can find it?
I think my code is good and clear. Does any one have any suggestions to solve this problem?
If the project workspace is placed in nested folders resulting in large path, then powerstation compiler shows this error. The solution for this, is to reduce the path of the project workspace by placing it closer to c drive , for example in my documents folder.
There is only so much help that can be given over the internet. And only so much that can be done with an outdated product (MS Fortran Power Station) for which you lack the documentation. I have several suggestions. Get a modern compiler. With your computer experience, and since you are using MS Windows, you would probably do best with a commercial product such as Intel Visual Fortran Compiler for Windows.
There may be an educational discount. There is probably a trial download (timed demo). If you still have difficulties (installing, compiling your program, etc.), offer some money to a undergraduate who is good with computers to help you for a couple of hours. I also suggest learning Fortran 95. You can gradually switch from FORTRAN 77 to Fortran 95 since the languages are compatible. Fortran 95 is a more capable language. It also has features that better allow compilers to find programmer mistakes, speeding the development process.
From the link you provided:
There are three different ways to resolve these problems:
Reorder the structure. Putting small
items first often eliminates both
errors. -or-
Use one-character-long member names.
-or-
Recompile without -Zi.
If you're compiling with the -Zi parameter, take the parameter off.
If that doesn't work, reorder the structure. That means putting the smaller individual INTEGER, FLOAT, etc. elements towards the front of the program, followed by the Array declarations.
If that doesn't work, your program is too large for Fortran power station.
I have a similar problem when I make the "Project Workspace" name too long. Use short "Project Workspace" name.