2
votes

So I've been avoiding Fortran like the plague, but finally my time has come... I need to take part of someone else's Fortran code (let's call it program A) and do two things with it:

(1) Merge it with a third person's Fortran code (let's call it program B) so that B can call A

(2) Merge it with my C++ code (program C) so that C can call A

B and C are optimization algorithms, and A is a collection of benchmark functions... But before all that awesomeness can happen, I must first compile the portion of A that I need. All the subroutines of A that I need are contained in one file. I've been getting it into shape based on information I got online (e.g. adding "IMPLICIT NONE" to the code and making it suitable for gfortran). But I've got two stubborn bugs and a warning (I'll leave the warning for another post).

Here's how I am currently compiling it (via a Makefile):

all:
    gfortran progA.FOR
    g++ -c progC.cpp
    g++ -o Program.out progA.o progC.o
    rm *.o

But the first line fails to complete with the following errors,

FIRST ERROR:

SUBROUTINE TP1(MODE)
1
Error: Unclassifiable statement at (1)

RELEVANT CODE (starting from the top of the file):

      IMPLICIT NONE  
      INTEGER    NMAX,MMAX,LMAX,MNNMAX,LWA,LIWA,LACTIV,N,NILI,NINL,
     /           NELI,NENL,NEX, MODE              
      PARAMETER (NMAX   = 101, 
     /           MMAX   = 50, 
     /           LMAX   = 50, 
     /           MNNMAX = NMAX + NMAX + MMAX + 2,
     /           LWA    = 2*NMAX*NMAX + 33*NMAX + 10*MMAX + 200,
     /           LIWA   = MMAX + NMAX + 150,
     /           LACTIV = 2*MMAX + 15)  
      LOGICAL    INDEX1,INDEX2

      SUBROUTINE TP1(MODE)      
      COMMON/L1/N,NILI,NINL,NELI,NENL   
      COMMON/L2/X(2)   
      COMMON/L4/GF(2)   
      COMMON/L6/FX      
      COMMON/L9/INDEX1  
      COMMON/L10/INDEX2 
      COMMON/L11/LXL    
      COMMON/L12/LXU    
      COMMON/L13/XL(2)  
      COMMON/L20/LEX,NEX,FEX,XEX(2)     
      REAL*8 X,G,GF,GG,FX,XL,XU,FEX,XEX 
      LOGICAL LXL(2),LXU(2),LEX 
      GOTO (1,2,3,4,4),MODE     
1     N=2       
      NILI=0    
      NINL=0    
      NELI=0    
      NENL=0    
      X(1)=-2.D0
      X(2)=1.D0 
      LXL(1)=.FALSE.    
      LXL(2)=.TRUE.     
      LXU(1)=.FALSE.    
      LXU(2)=.FALSE.    
      XL(2)=-1.5D0      
      LEX=.TRUE.
      NEX=1     
      XEX(1)=1.D0       
      XEX(2)=1.D0       
      FEX=0.D0  
      RETURN    
2     FX=100.D0*(X(2)-X(1)**2)**2+(1.D0-X(1))**2
      RETURN    
3     GF(2)=200.D0*(X(2)-X(1)**2)       
      GF(1)=-2.D0*(X(1)*(GF(2)-1.D0)+1.D0)      
4     RETURN    
      END       

I do not understand why this error appears since there are over 300 other subroutines declared exactly the same way (e.g. SUBROUTINE TP2(MODE), ..., SUBROUTINE TP300(MODE) ).

SECOND ERROR:

HX=TP273A(X)
1
Error: Return type mismatch of function 'tp273a' at (1) (REAL(4)/REAL(8))

RELEVANT CODE:

      SUBROUTINE TP273(MODE) 
      COMMON/L1/N,NILI,NIML,NELI,NENL 
      COMMON/L2/X 
      COMMON/L4/GF 
      COMMON/L6/FX 
      COMMON/L11/LXL 
      COMMON/L12/LXU 
      COMMON/L20/LEX,NEX,FEX,XEX 
      LOGICAL LEX,LXL(6),LXU(6) 
      REAL*8 X(6),FX,GF(6),FEX,XEX(6),HX,DFLOAT
      GOTO (1,2,3,4,4)MODE 
 1    N=6 
      NILI=0 
      NINL=0 
      NELI=0 
      NENL=0 
      DO 6 I=1,6 
      X(I)=0.D+0 
      XEX(I)=0.1D+1 
      LXL(I)=.FALSE. 
6     LXU(I)=.FALSE. 
      LEX=.TRUE. 
      NEX=1 
      FEX=0.D+0 
      RETURN 
 2    HX=TP273A(X) 
      FX=0.1D+2*HX*(0.1D+1+HX) 
      RETURN 
 3    HX=TP273A(X) 
      DO 7 I=1,6 
 7    GF(I)=0.2D+2*(0.16D+2-DFLOAT(I))*(X(I)-0.1D+1) 
     1       *(0.1D+1+0.2D+1*HX) 
 4    RETURN 
      END       

      REAL*8 FUNCTION TP273A (X) 
      REAL*8 X(6),DFLOAT
      TP273A=0 
      DO 10 I=1,6 
10    TP273A=TP273A+(0.16D+2-DFLOAT(I))*(X(I)-0.1D+1)**2 
      RETURN
      END

After reading Physics Forums I tried renaming the variable "TP273A" to "TP273Avar" so that it would not have the same name as the function. This did not resolve the error. Also, I replaced the "1" with "F" just below "7 GF(I) = ..." and recompiled. Nothing changed. I'm pretty sure the changes I just mentioned are necessary anyway, but there must be something else going on.

I have also read Data type mismatch in fortran and Function return type mismatch, so I naively tried adding "module mycode" to the top and "end module mycode" to the bottom of the file to no avail.

After this is all said and done, my goal is to call these subroutines from C++ using a code similar to:

#include <kitchensink>

extern"C"
{
void TP1_(int *mode);
}

int main()
{
    TP1_(2);
    return 0;
}

Once the Fortran Code compiles, I want to modify the subroutines so that C++ can pass std::vector X to TP#_(2,*X,*Y) and get back the computed value for Y. My std::vector X will replace COMMON/L2 X in each of the subroutines, and Y will be the value of FX computed in the subroutines. I used Mixing Fortran and C as guidance for the above C++ code.

As for the B calls A part, I hope that it will be as simple as compiling A along with B, and adding "CALL TP1(MODE)" lines wherever I need them.

Any and all guidance will be greatly appreciated!!!

1
Not answering your question directly, but: Fortran is not plague, it's just a language, and an easy one compared to C++. If you need to modify Fortran code, I would strongly advise you to learn a bit of it first: here is a good introduction to Fortran 77, and here is the Fortran 77 standard (Fortran 77 is not the latest version available, but you seem to be using it here). - user1220978
You're right. It's just that 90% of my experiences with Fortran involved what I consider to be poorly written code, so every time someone says "here's some Fortran code for you to use" I shudder. - Eric Inclan
I would disagree with @arbautjc, though my job involves a lot of Fortran. Fortran 95/2003 are fine (sometimes easier than C), but I avoid Fortran 77 like the plague! I've seen well-written Fortran 77 routines, but they are rare. - Sean Patrick Santos

1 Answers

6
votes

You cannot have statements just in a file outside of a compilation unit. These can be subroutines, functions, modules or programs. In your case you have some statements( first of them being implicit none) and only after them there is the beginning of the subroutine TP1.

Either organize the procedures in a module and leave the common part before the contains section (more work with the C++ interoperability will follow if you are a Fortran newbie) or you must include the implicit none and others in every subroutine separately. Are you sure you even need this if the code worked before?