Thread: mixed program c/fortran

  1. #1
    Registered User
    Join Date
    Aug 2008
    Location
    London and Lyon
    Posts
    26

    mixed program c/fortran

    Hi all, I am a beginner in programming in C, C++ as well as fortran.

    I am trying to call a fortran subroutine from a c program. I found documentation on how to do that when the arguments of the subroutine are classical, such as integer...but how do you pass a fortran subroutine that has itself a function or another subroutine as an argument to a c program ?

    Here is the c code

    Code:
     
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include "f77.h"
    
    
    extern "C"{
    void LMQN_(int *IERROR, int *N, double X[], double *F, double G[], double W[], int *LW, double *SFUN_, int *MSGLVL
    , int *MAXIT, int *MAXFUN, double *ETA, int *STEPMX, double *ACCRCY, double *XTOL);
    }
    
    
    int
    main(void)
    {
    int IERROR,i;
    int N=200,LW=4000,MSGLVL,MAXIT,MAXFUN,STEPMX=10;
    double F=-1000.0,SFUN_;
    double G[300],W[4000],X[300],tipo[300];
    double ETA=0.25,ACCRCY=1.0e-15,XTOL;
    FILE *inputFPtr;
    
    XTOL=sqrt(ACCRCY);
    MAXIT=N/2;
    MAXFUN=150*N;
    
    
      if((inputFPtr=fopen("conf1_deform.dat","r"))==NULL){
        printf("can't read conf1_deform.dat.dat\n");
        exit(1);
      }
    
    
      for(i=0;i<100;i++) {
        fscanf(inputFPtr,"%lf%lf%lf",&tipo[i],&X[i],&X[i+100]);
      }
    
    
    LMQN_(&IERROR, &N, X, &F, G, W, &LW, SFUN_, &MSGLVL, &MAXIT, &MAXFUN, &ETA, &STEPMX, &ACCRCY, &XTOL);
                  
    }
    Thanks all

    Mike

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    You'd have to read the instructions which come with your compiler on how to create mixed-language programs.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Aug 2008
    Location
    London and Lyon
    Posts
    26
    Hi all again, thanks for the answer but has anyone a bit more information to give me on this topic ??

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Do you mean to say that you want to pass a function pointer to a C function into a fortran function? Or are you passing a fortran function to a C function, or something else?

    [I have no idea as to the answer to the question, I'm just attempting to clarify what it is that you want answered, as that would help someone who actually knows the answer].

    And I'd also like to make the note that combining languages is always dependant on the compilers involved, so it would be good if you told us what compiler suite(s) you are using.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Aug 2008
    Location
    London and Lyon
    Posts
    26
    Hi,

    I will try and clarify.

    What I want to do is to include an optimization code from netlib called TN/TNBC in a c code.

    The fortran code is working well, the main code is the following.



    Code:
    an C***********************************************************************
    C CUSTOMIZED, NO BOUNDS
    C***********************************************************************
    C MAIN PROGRAM TO MINIMIZE A FUNCTION (REPRESENTED BY THE ROUTINE SFUN)
    C OF N VARIABLES X - CUSTOMIZED VERSION
    C
          DOUBLE PRECISION  X(300), F, G(300), W(4000)
          DOUBLE PRECISION  ETA, ACCRCY, XTOL, STEPMX, DSQRT
          EXTERNAL          SFUN
    	DOUBLE PRECISION dummy
    	integer i
    C
    C SET UP FUNCTION AND VARIABLE INFORMATION
    C N  - NUMBER OF VARIABLES
    C X  - INITIAL ESTIMATE OF THE SOLUTION
    C F  - ROUGH ESTIMATE OF FUNCTION VALUE AT SOLUTION
    C LW - DECLARED LENGTH OF THE ARRAY W
    C
    
    
            open(33,file="conf1_deform.dat",status='unknown')
            do i=1,100
            read(33,*) dummy,X(i),X(i+100)
            enddo
            close(33)
    
    
          N  = 200
    !      DO 10 I = 1,N
    !         X(I) = I / FLOAT(N+1)
    !10    CONTINUE
          F  = 1.D0
          LW = 4000
    C
    C SET UP CUSTOMIZING PARAMETERS
    C ETA    - SEVERITY OF THE LINESEARCH
    C MAXFUN - MAXIMUM ALLOWABLE NUMBER OF FUNCTION EVALUATIONS
    C XTOL   - DESIRED ACCURACY FOR THE SOLUTION X*
    C STEPMX - MAXIMUM ALLOWABLE STEP IN THE LINESEARCH
    C ACCRCY - ACCURACY OF COMPUTED FUNCTION VALUES
    C MSGLVL - DETERMINES QUANTITY OF PRINTED OUTPUT
    C          0 = NONE, 1 = ONE LINE PER MAJOR ITERATION.
    C MAXIT  - MAXIMUM NUMBER OF INNER ITERATIONS PER STEP
    C
          MAXIT  = N/2
          MAXFUN = 150*N
          ETA    = .25D0
          STEPMX = 1.D1
          ACCRCY = 1.D-15
          XTOL   = DSQRT(ACCRCY)
          MSGLVL = 1
    C
    C MINIMIZE THE FUNCTION
    C
          CALL LMQN (IERROR, N, X, F, G, W, LW, SFUN,
         *     MSGLVL, MAXIT, MAXFUN, ETA, STEPMX, ACCRCY, XTOL)
    C
    C PRINT THE RESULTS
    C
          IF (IERROR .NE. 0) WRITE(*,800) IERROR
          IF (MSGLVL .GE. 1) WRITE(*,810)
          IF (MSGLVL .GE. 1) WRITE(*,820) (I,X(I),I=1,N)
          STOP
    800   FORMAT(//,' ERROR CODE =', I3,/)
    810   FORMAT(10X, 'CURRENT SOLUTION IS ',/14X, 'I', 11X, 'X(I)')
    820   FORMAT(10X, I5, 2X, 1PD22.15)
          END
    C
    C
    
          SUBROUTINE SFUN (N, X, F, G)
          DOUBLE PRECISION  X(N), G(N), F, T
    	integer i,j
       	DOUBLE PRECISION  Vp,v,cutoff,pot_cutoff,dx,dy,r2
            DOUBLE PRECISION  sigma_xy,Fx,Fy,r(100)
    
    
    	open(33,file="conf1_deform.dat",status='unknown')
    	do i=1,100
    	read(33,*) r(i)
    	enddo
    	close(33)
    
    	v=0.d0
    	F = 0.D0
    	do i=1,100
    	G(i) = 0.d0
    	G(i+100) = 0.d0
    	enddo
    
    	do i=1,100
    	 do j=1,100
    	 if (i.ne.j) then
    	 sigma_xy=(r(i)+r(j))/2.d0
    	 cutoff=2.d0**(7.d0/6.d0)*sigma_xy
    	 pot_cutoff=4*((sigma_xy*sigma_xy/(cutoff*cutoff))**6.d0-
         $        (sigma_xy*sigma_xy/(cutoff*cutoff))**3.d0)
    	 dx=X(i)-X(j)
    	 dy=X(i+100)-X(j+100)
    	 if (dx.ge.10.3975/2.d0) dx=dx-10.3975
    	 if (dx.le.-10.3975/2.d0) dx=dx+10.3975
    	 if (dy.ge.10.3975/2.d0) dy=dy-10.3975
             if (dy.le.-10.3975/2.d0) dy=dy+10.3975
    
    	 r2=dx*dx+dy*dy
    
    	 if (r2.le.cutoff*cutoff) then
    	 Vp=4*((sigma_xy*sigma_xy/r2)**6-(sigma_xy*sigma_xy/r2)**3)-pot_cutoff
    !	 print *, i, j, Vp
    	 F=F+Vp/2.0
    
    	 Fx=48.d0*sigma_xy**12.d0*dx/r2**7.d0-
         $    24.d0*sigma_xy**6.d0*dx/r2**4.d0
    	 Fy=48.d0*sigma_xy**12.d0*dy/r2**7.d0-
         $    24.d0*sigma_xy**6.d0*dy/r2**4.d0
    	 G(i) =  G(i) - Fx
    	 G(i+100) = G(i+100) - Fy	  
    	 endif
    	 
    	 endif
     	 enddo
    	enddo	
    
    
    
    C
    C ROUTINE TO EVALUATE FUNCTION (F) AND GRADIENT (G) OF THE OBJECTIVE
    C FUNCTION AT THE POINT X
    C
    
    !      F = 0.D0
    !      DO 10 I = 1,N
    !         T    = 2*X(I) - I
    !         F    = F + T*T
    !         G(I) = 2.D0 * T
    !10    CONTINUE
     
    !     RETURN
    
          END
    The previous code I posted a c code is aimed at doing the same thing. This is just a test later I will call the subroutine LMQN from another c code that I am using. My difficulty is that I DON'T KNOW HOW TO CALL A SUBROUTINE FROM C (LMQN) THAT HAS AS ARGUMENT ANOTHER SUBROUTINE (SFUN).

    Thank you for your help.
    If there are references on this, please let me know.

    To compile my c codes I use gcc or g++.

    Mike

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Ok, and are you using g77 to compile your fortran?

    Have you tried declaring SFUN() in your C code:
    Code:
    extern "C" void  SFUN _(int *N, double *X, double *F, double *G);
    [I'm not 100% sure that's the right format, but something along those lines].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    Aug 2008
    Location
    London and Lyon
    Posts
    26
    Hi I really appreciate your help.

    I use this syntax

    Code:
    extern "C"{
    void SFUN_(int *N, double X[], double *F, double G[]);
    }
    I compile in this way

    g++ -c minim.c
    ifort -c tn.f blas.f sfun.f
    g++ minim.o tn.o blas.o sfun.o

    and I get this error message (I cut it as it goes on and on)

    /usr/bin/ld: AVERTISSEMENT: architecture i386 du fichier d'entrée « tn.o » est incompatible avec la sortie i386:x86-64
    /usr/bin/ld: AVERTISSEMENT: architecture i386 du fichier d'entrée « blas.o » est incompatible avec la sortie i386:x86-64
    /usr/bin/ld: AVERTISSEMENT: architecture i386 du fichier d'entrée « sfun.o » est incompatible avec la sortie i386:x86-64
    minim.o(.text+0x1d6): In function `main':
    : undefined reference to `LMQN_'
    tn.o(.text+0x136): In function `tn_':
    : undefined reference to `for_write_seq_fmt'
    tn.o(.text+0x16d): In function `tn_':
    : undefined reference to `for_write_seq_fmt'
    tn.o(.text+0x1a1): In function `tn_':
    : undefined reference to `for_write_seq_fmt'
    tn.o(.text+0x1d7): In function `tn_':
    : undefined reference to `for_write_seq_fmt'
    tn.o(.text+0x204): In function `tn_':
    : undefined reference to `for_write_seq_fmt_xmit'


    My problem is how to pass the subroutine SFUN_ as an argument inside the other subroutine LMQN_.

    For the moment I passing like that

    Code:
    extern "C"{
    void LMQN_(int *IERROR, int *N, double X[], double *F, double G[], double W[], int *LW, void *SFUN_, int *MSGLVL, int *MAXIT, int *MAXFUN, double *ETA, int *STEPMX, double *ACCRCY, double *XTOL);
    }
    and
    Code:
    LMQN_(&IERROR, &N, X, &F, G, W, &LW, &SFUN_, &MSGLVL, &MAXIT, &MAXFUN, &ETA, &STEPMX, &ACCRCY, &XTOL);
    Thanks for the suggestion any other ideas ???

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    First of all, "architecture i386 du fichier d'entrée « tn.o » est incompatible avec la sortie i386:x86-64" says that your file contains x86_32 functions, so you should pass -m32 to g++ to match the functions to your C++ code.

    This would be a more correct version of passing SFUN_ to your function.
    Code:
    void LMQN_(int *IERROR, int *N, double X[], double *F, double G[], double W[], int *LW, void (*SFUN_)(int *N, double X[], double *F, double G[]), int *MSGLVL, int *MAXIT, int *MAXFUN, double *ETA, int *STEPMX, double *ACCRCY, double *XTOL);

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Aug 2008
    Location
    London and Lyon
    Posts
    26
    This makes more sence.

    Here is what I get now.

    g++ -c minim.c -m32

    minim.c: In function `int main()':
    minim.c:45: erreur: ne peut convertir « double » à « void (*)(int*, double*, double*, double*) » pour l'argument « 8 » vers « void LMQN_(int*, int*, double*, double*, double*, double*, int*, void (*)(int*, double*, double*, double*), int*, int*, int*, double*, int*, double*, double*) »

    (sorry for all this french)

    You didn't mention how I should pass the subroutine SFUN_ as an argument when I call LMQN_ in the c code. For the moment I am doing

    Code:
    LMQN_(&IERROR, &N, X, &F, G, W, &LW, SFUN_, &MSGLVL, &MAXIT, &MAXFUN, &ETA, &STEPMX, &ACCRCY, &XTOL);
    I also tried &SFUN_ and it gives the above error.
    What is the proper syntax ?

    By the way do you know any usefull reference on these topics?

    Thanks a lot.

    Mike

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Trying to read the french and translating to English, I get the impression that it says that it can't translate a double to void (*)(...) for argument 8 - which seems strange to me.

    No, I don't know of any references for this.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Registered User
    Join Date
    Aug 2008
    Location
    London and Lyon
    Posts
    26

    Unhappy

    ANY SPECIALIST ON HOW TO MIX THE LANGUAGES FORTRAN AND C see threads above???

    Thanks I am stuck there for 5 days and I suspect it is trivial.

    Thanks everyone and Mats especially.

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by mimi1981 View Post
    ANY SPECIALIST ON HOW TO MIX THE LANGUAGES FORTRAN AND C see threads above???

    Thanks I am stuck there for 5 days and I suspect it is trivial.

    Thanks everyone and Mats especially.
    Just to clarify, the current problem is a pure C (or C++) problem, not a Fortran mix with C++ problem - or at least, the compiler error should be solved with fixing the C++ code, it may not be completely correct in other ways, and that may cause problems in the interface, but at the moment, it's a pure C++ problem.

    Can you post the whole C++ code as it stands now?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Aug 2008
    Location
    London and Lyon
    Posts
    26
    Here is the code (with my question in red).

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include "f77.h"     [COLOR="I don't know what this does ?"][/COLOR]
    
    
    extern "C"{
    void SFUN_(int *N, double X[], double *F, double G[]);
    }
    
    
    //extern "C" void  SFUN_(int *N, double *X, double *F, double *G);
    
    extern "C"{
    void LMQN_(int *IERROR, int *N, double X[], double *F, double G[], double W[], int *LW, void (*SFUN_)(int *N, doub
    le X[], double *F, double G[]), int *MSGLVL, int *MAXIT, int *MAXFUN, double *ETA, int *STEPMX, double *ACCRCY, do
    uble *XTOL);
    }
    
    
    int
    main(void)
    {
    int IERROR,i;
    int N=200,LW=4000,MSGLVL,MAXIT,MAXFUN,STEPMX=10;
    double F=-1000.0,SFUN_;
    double G[300],W[4000],X[300],tipo[300];
    double ETA=0.25,ACCRCY=1.0e-15,XTOL;
    FILE *inputFPtr;
    
    XTOL=sqrt(ACCRCY);
    MAXIT=N/2;
    MAXFUN=150*N;
    
    
      if((inputFPtr=fopen("conf1_deform.dat","r"))==NULL){
        printf("can't read conf1_deform.dat.dat\n");
        exit(1);
      }
    
    
      for(i=0;i<100;i++) {
        fscanf(inputFPtr,"%lf%lf%lf",&tipo[i],&X[i],&X[i+100]); [COLOR="How could I pass tipo[i] to the function SFUN without changing its signature ie the number of its arguments ???"][/COLOR]
      }
    
    
    LMQN_(&IERROR, &N, X, &F, G, W, &LW, &SFUN_, &MSGLVL, &MAXIT, &MAXFUN, &ETA, &STEPMX, &ACCRCY, &XTOL); [COLOR="WHAT SHOULD I TYPE THERE &SFUN_, SFUN...?????"][/COLOR]
    
    
    
    }
    The function sfun.f is the following

    Code:
          SUBROUTINE SFUN (N, X, F, G)
          DOUBLE PRECISION  X(N), G(N), F, T
            integer i,j
            DOUBLE PRECISION  Vp,v,cutoff,pot_cutoff,dx,dy,r2
            DOUBLE PRECISION  sigma_xy,Fx,Fy,r(100)
    
    
            open(33,file="conf1_deform.dat",status='unknown')
            do i=1,100
            read(33,*) r(i)
            enddo
            close(33)
    
            v=0.d0
            F = 0.D0
            do i=1,100
            G(i) = 0.d0
            G(i+100) = 0.d0
            enddo
    
            do i=1,100
             do j=1,100
             if (i.ne.j) then
             sigma_xy=(r(i)+r(j))/2.d0
             cutoff=2.d0**(7.d0/6.d0)*sigma_xy
             pot_cutoff=4*((sigma_xy*sigma_xy/(cutoff*cutoff))**6.d0-
         $        (sigma_xy*sigma_xy/(cutoff*cutoff))**3.d0)
             dx=X(i)-X(j)
             dy=X(i+100)-X(j+100)
             if (dx.ge.10.3975/2.d0) dx=dx-10.3975
             if (dx.le.-10.3975/2.d0) dx=dx+10.3975
             if (dy.ge.10.3975/2.d0) dy=dy-10.3975
             if (dy.le.-10.3975/2.d0) dy=dy+10.3975
    
             r2=dx*dx+dy*dy
    
             if (r2.le.cutoff*cutoff) then
             Vp=4*((sigma_xy*sigma_xy/r2)**6-(sigma_xy*sigma_xy/r2)**3)-pot_cutoff
    !        print *, i, j, Vp
             F=F+Vp/2.0
    
             Fx=48.d0*sigma_xy**12.d0*dx/r2**7.d0-
         $    24.d0*sigma_xy**6.d0*dx/r2**4.d0
             Fy=48.d0*sigma_xy**12.d0*dy/r2**7.d0-
         $    24.d0*sigma_xy**6.d0*dy/r2**4.d0
             G(i) =  G(i) - Fx
             G(i+100) = G(i+100) - Fy
             endif
    
             endif
             enddo
            enddo
    
    
          END
    and F77.h is (I found that on the internet maybe it does not make sense to put it as an include ?????

    Code:
    #ifndef Lib_F77_h
    #define Lib_F77_h
    
    #ifdef WIN32
    #define Lib_stdcall __stdcall
    #else
    #define Lib_stdcall
    #endif
    
    #endif
    THANKS A LOT

  14. #14
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    It was probably in your original code, but changing this line:
    Code:
    double F=-1000.0,SFUN_;
    into
    Code:
    double F=-1000.0;
    makes the code compile with g++ on my machine. It doesn't link because I don't have the libraries. And there may of course be other problems.

    As to how you pass "tipo[i]", I think you would not do that, since sfun() reads that from the datafile in itself.

    If you want to read the file only once, you would have to change the FORTRAN code around to take another argument double tipo[] in both LMQN and SFUN, and pass tipo from LMQN to SFUN.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #15
    Registered User
    Join Date
    Aug 2008
    Location
    London and Lyon
    Posts
    26
    So that is one stupid mistake sorted. Thanks and sorry about that.

    One question you haven't answered is how to pass SFUN as an argument to the function LMPQ when I call it through

    Code:
    LMQN_(&IERROR, &N, X, &F, G, W, &LW, &SFUN_, &MSGLVL, &MAXIT, &MAXFUN, &ETA, &STEPMX, &ACCRCY, &XTOL);
    Is this the right syntax ?? or is it something else SFUN_,SFUN ....??

    If this is correct, I think we are back to the initial questions about the way to link C++ and fortran functions.

    I do

    g++ -c minim.c -m32
    ifort -c tn.f
    ifort -c blas.f
    ifort -c sfun.f
    g++ minim.o blas.o sfun.o tn.o -m32

    and I get the horrible
    /usr/bin/ld: AVERTISSEMENT: architecture i386 du fichier d'entrée « minim.o » est incompatible avec la sortie i386:x86-64
    /usr/bin/ld: AVERTISSEMENT: architecture i386 du fichier d'entrée « tn.o » est incompatible avec la sortie i386:x86-64
    /usr/bin/ld: AVERTISSEMENT: architecture i386 du fichier d'entrée « sfun.o » est incompatible avec la sortie i386:x86-64
    minim.o(.text+0x169): In function `main':
    : undefined reference to `SFUN_'
    minim.o(.text+0x1a7): In function `main':
    : undefined reference to `LMQN_'
    tn.o(.text+0x136): In function `tn_':
    : undefined reference to `for_write_seq_fmt'
    tn.o(.text+0x16d): In function `tn_':
    : undefined reference to `for_write_seq_fmt'
    tn.o(.text+0x1a1): In function `tn_':
    : undefined reference to `for_write_seq_fmt'
    tn.o(.text+0x1d7): In function `tn_':
    : undefined reference to `for_write_seq_fmt'
    tn.o(.text+0x204): In function `tn_':
    : undefined reference to `for_write_seq_fmt_xmit'
    tn.o(.text+0x226): In function `tn_':
    : undefined reference to `for_write_seq_fmt_xmit'
    tn.o(.text+0x241): In function `tn_':
    : undefined reference to `for_write_seq_fmt_xmit'
    tn.o(.text+0x2bd): In function `lmqn_.':

    and on and on....

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Issue with program that's calling a function and has a loop
    By tigerfansince84 in forum C++ Programming
    Replies: 9
    Last Post: 11-12-2008, 01:38 PM
  2. Need help with a program, theres something in it for you
    By engstudent363 in forum C Programming
    Replies: 1
    Last Post: 02-29-2008, 01:41 PM
  3. Replies: 4
    Last Post: 02-21-2008, 10:39 AM
  4. My program, anyhelp
    By @licomb in forum C Programming
    Replies: 14
    Last Post: 08-14-2001, 10:04 PM