Little help with using Fortran and multiple source files needed.

Discussion in 'Mac Programming' started by Spanky Deluxe, Jul 25, 2008.

  1. Spanky Deluxe macrumors 601

    Spanky Deluxe

    Joined:
    Mar 17, 2005
    Location:
    London, UK
    #1
    Hi everyone again,

    I've coded some test programs that I now want to merge into one program. I'm reading up on how to use the SUBROUTINE definitions and how to pass variables between subroutines, however there's one thing in particular that I don't know how to deal with.

    Where do I put the include statements? All my subroutines need to use an include .h file. I've read that when compiling, you need to put the subroutine files first with your main handler program last.

    I'm using iFort to compile and my command to compile is as follows, is this correct:

    ifort test_subroutine.f90 test_main.f90 -o test.e

    Any help would be really appreciated!! :)
     
  2. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #2
    What I'd say is most analogous to #include is the use keyword. You can "include" modules with:
    use modulename

    Otherwise the convention I've seen for actual includes is using a file called .i.f/F/F90/F95. Then you can actually use the keyword include. This isn't too common, but you can declare types of functions if needed in a file like this, or just use it as a sort of "inline" method that you can stick into your code.

    I'm using G95, but I'll show you my example to see if it helps:
    testSub.F95:
    Code:
    program testSub
      implicit none
      call subA()
    end program
    
    testSubA.F95
    Code:
    subroutine subA()
      implicit none
      write(7,'("In sub!")')
    end subroutine
    
    Build object file for testSubA:
    Code:
    g95 -c testSubA.F95
    
    Build and link executable for testSub:
    Code:
    g95 testSubA.o -o testSub testSub.F95
    
    I'm sure ifort is a bit different in its syntax, but that's the general idea for most compilers. You need to build all of your objects first, then build/link your executable. Using a makefile can greatly simplify this process.

    -Lee
     
  3. Spanky Deluxe thread starter macrumors 601

    Spanky Deluxe

    Joined:
    Mar 17, 2005
    Location:
    London, UK
    #3
    Thanks for that, I'll start using makefiles soon but I want to understand how to do it manually first.

    Can you suggest how to use the use command? I.e. where do I put it.

    My code is basically of the format:

    test_main.f90:
    Code:
    program testSub
      include mpif.h
      implicit none
      call subA()
    end program
    and then test_subroutine.f90:

    Code:
    subroutine subA()
      include mpif.h
      implicit none
      write(7,'("In sub!")')
    end subroutine
    I don't know where to put the include line for the mpif.h file. :confused:
     
  4. ChrisA macrumors G4

    Joined:
    Jan 5, 2006
    Location:
    Redondo Beach, California
    #4
    The compilers will have a search path, that is a list of directories it will look it. Normally this path includes the current working directory, the same place that holds your other source code. The gcc compiler excepts a -I switch where you can add directories to the search path.

    BTW "include files" must be some recent addition to FORTRAN. You will not see it used in most FORTRAN programs you come across
     
  5. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #5
    What is in your .h file that you need access to in both programs? Are you trying to use a common block?

    Chances are your .h file contains C, so this may not be the right solution.

    -Lee
     
  6. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #6
    You had asked about "use", so I wrote something else up:

    testSub.F95:
    Code:
    program testSub
      use module_test
      implicit none
      type(testType) :: myTest
      myTest%key=5
      myTest%next=2
      myTest%value=int(33432,4)
      call print_testType(myTest)
    end program
    
    module_test.F95:
    Code:
    module testType_mod
      type testType
        sequence
        integer(4) :: key
        integer(2) :: next
        integer(4) :: value
      end type
    end module
    
    module module_test
      use testType_mod
      implicit none
      contains
        subroutine print_testType(toPrint)
          implicit none
          type(testType), intent(in) :: toPrint
          write(6,'("Key: ",i12," next: ",i5," value: ",i12)') &
             & toPrint%key,toPrint%next,toPrint%value
        end subroutine
    end module
    
    build module:
    Code:
    g95 -c module_test.F95
    
    build/link executable:
    Code:
    g95 module_test.o -o testSub testSub.F95
    
    By "use"ing the module_test module, this also "use"s the testType_mod module. Then whenever you "use module_test" you can use the testType type, and you can call the function print_testType.

    -Lee
     
  7. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #7
    include has been in the language since at least F77, use was introduced with Fortran 90.

    -Lee
     
  8. Spanky Deluxe thread starter macrumors 601

    Spanky Deluxe

    Joined:
    Mar 17, 2005
    Location:
    London, UK
    #8
    I've got no idea what's in there but its necessary to use MPI. Thanks for the code snippets - it makes a bit more sense now!! :)
     
  9. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #9
    Did a search and found this, it is indeed Fortran in that file. If it's in the same directory as the rest of your source, you should be able to just:
    Code:
    include 'mpif.h'
    -Lee
     
  10. Spanky Deluxe thread starter macrumors 601

    Spanky Deluxe

    Joined:
    Mar 17, 2005
    Location:
    London, UK
    #10
    Ok, but do you know which file should I put it in? The main program file, the subroutine file or both?
     
  11. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #11
    I have never used MPI, so I will go with the reserved answer of "Anywhere you are going to make calls to MPI functions or subroutines".

    -Lee
     
  12. Spanky Deluxe thread starter macrumors 601

    Spanky Deluxe

    Joined:
    Mar 17, 2005
    Location:
    London, UK
  13. crackpip macrumors regular

    Joined:
    Jul 23, 2002
    #13
    I use iFort but not on my Mac, let me give you a few pointers.

    Employ MODULES. This allows you to more closely approximate object oriented programming, and can significantly improve organization. For example, I abstracted all of my MPI routines into a single module. I did the samething for output using HDF5. It's also very easy to overload procedures and operations in modules.

    I love using the preprocessor (-fpp option) for conditional compilation and organization. It's great for debugging. Until submodules are implemented with Fortran 2003, I use a #include directive, which is basically the same as the standard include. for dividing my larger modules into subfiles.

    Compilation will go something like this:

    For the compilation I do:
    mpif90 -fpp <preprocesor definitions> -c module.f90
    mpif90 -fpp <preprocesor definitions> -c subroutine.f90
    mpif90 -fpp <preprocesor definitions> -c main.f90

    Then the linking is
    mpif90 -o executable dependencies(.o files) libraries

    By the way, which MPI implementation are you using? Your MPI implementation should have a Fortran 90 module. So instead of 'include "mpif.h"', you can 'use mpi' in any module or procedure that has MPI calls in it.

    crackpip
     
  14. Spanky Deluxe thread starter macrumors 601

    Spanky Deluxe

    Joined:
    Mar 17, 2005
    Location:
    London, UK
    #14
    I'm using MPICH2. So can you use the preprocessor to get it to include the mpif.h file? I'm still a real amateur with mpi and Fortran and am learning my way around gradually. When I replace my include line with "use mpi" I get the error "This USE statement is not positioned correctly within the scoping unit." when compiling. I'm a step closer now with compiling by leaving the include line in both the main program and the subrouting but it still feels messy.

    Some of this stuff has such a steep learning curve!! Its taken me months to get to where I am now and the depressing this is, I could recreate all of it from scratch now in a mere matter of hours.
     
  15. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #15
    the use line needs to be between program, function, subroutines lines and implicit none.

    The .mod must be compiled when you compile anything that uses it.

    -Lee
     
  16. crackpip macrumors regular

    Joined:
    Jul 23, 2002
    #16
    Yeah, I know how it goes. I had to learn a lot of this stuff on the fly too. The USE statement needs to be the first statement after the PROGRAM statement before the implicit none. When you compile you should use the premade aliases, for example mpif90, this will add in the proper libraries. As an organizational technique, I put at most one program unit in a file. So one module, one major subroutine not associated with a module, or the main program. Sometimes if a module is too large, I'll divide it into subfiles, put them into a subfolder and use the #include directive.

    If you're using allocatable arrays, I found that I ran into problems with the MPI packing routines when only exchanging part of an array. I actually get better communication performance if I use the PACK and UNPACK intrinsic functions to pack the subarray into a 1-D array which is sent to the intended process, and unpacked.

    The .mod files will be generated when you call 'mpif90 -c module.f90'

    crackpip
     

Share This Page