简体   繁体   中英

Using Fortran 77 subprogram as stand-alone, calling from C++

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 (eg 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 (eg 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!!!

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM