0

I have a problem with a Fortran project and figured out maybe you could help me.

I'm using codeblocks as IDE and there you can make projects, so I created a project with two files in it: a main program and a fuction (I don't know what else to use, I could use something different from a fuction maybe).

So I have my function that reads values from a .txt and saves them as real numbers and everything is working good. What I want to do is, from the file main, call this function and save in main the data I collected with my function so that the main remains cleaner.

How would I do that? I can post the whole script if you want, but I don't think it would add that much more.

EDIT: As you asked, here it is (uncut):

program main

    ! Variables
    real :: d1, r1, r2, a, teta, freq, Dt, mu, g0, r_t, height, r, omega, H, lx, ly, lz, m_c0, &
        Jx, Jy, Jz, gmax, I_s, K, Jx0, Jy0, Jz0, Vmin, tsp_0, Fmax, Isp, c1, n, F, DV, tfin, cont, Tmax
    real :: data_input

    ! Call the funcion
    data_input=data_module(d1, r1, r2, a, teta, freq, Dt, mu, g0, r_t, height, r, omega, H, lx, ly, lz, m_c0, &
          Jx, Jy, Jz, gmax, I_s, K, Jx0, Jy0, Jz0, Vmin, tsp_0, Fmax, Isp, c1, n, F, DV, tfin, cont, Tmax)

    ! Error 
    if (data_input/=1) then
        print*, 'ERROR: data_module did not work'
    end if

   !Just to show it
    print*,'After'
    print*, d1, r1, r2, a, teta, freq, Dt, mu, g0, r_t, height, r, omega, H, lx, ly, lz, m_c0, &
        Jx, Jy, Jz, gmax, I_s, K, Jx0, Jy0, Jz0, Vmin, tsp_0, Fmax, Isp, c1, n, F, DV, tfin, cont, Tmax
end program main

real function data_module ()

  ! Variables
  implicit none
  integer :: flag_read=0, w_int, d_int
  real:: coefficient, d1, r1, r2, a, teta, freq, Dt, mu, g0, r_t, height, r, omega, H, lx, ly, lz, m_c0, &
          Jx, Jy, Jz, gmax, I_s, K, Jx0, Jy0, Jz0, Vmin, tsp_0, Fmax, Isp, c1, n, F, DV, tfin, cont, Tmax
  character (LEN=35) :: starting_string, name*15, coefficient_string*20, w_string, d_string, number_format
  character :: w*2, d

  ! Open file
  open (11, file = 'Data.txt', status = 'old', access = 'sequential', form = 'formatted')

  ! Read a new line for every iteration
  sentence_reader: do while (flag_read==0)
    read (11, fmt='(A)', iostat = flag_read) starting_string

    ! Error
    if (flag_read>0)then
        print*, 'ERROR: could not read data'
        stop
    end if

    ! Skip useless lines
    if (starting_string(1:1)=='%' .OR. starting_string(1:1)==' ') then
        cycle
    end if

    ! Exit when you're done
    if (flag_read<0)then
        exit sentence_reader
    end if

    ! Just stuff to prepare it
    name=trim(starting_string(1:index(starting_string, '=')-1))
    coefficient_string=trim(adjustl(starting_string(index(starting_string, '=')+1:index(starting_string,';')-1)))
    if (scan(coefficient_string,'E')/=0) then
        w_string=coefficient_string
        w_int=len_trim(w_string)
        write(w, '(BN,I2)') w_int
        d_string=coefficient_string(index(coefficient_string, '.')+1:index(coefficient_string, 'E')-1)
        d_int=len_trim(d_string)
        write(d, '(BN,I1)') d_int

        !All togheter
        number_format='(BN,F' // trim(w) // '.' // d // ')'
    else
        w_string=coefficient_string
        w_int=len_trim(w_string)
        write(w, '(BN,I1)') w_int
        d_string=coefficient_string(index(coefficient_string, '.')+1:len_trim(coefficient_string))
        d_int=len_trim(d_string)
        write(d, '(BN,I1)') d_int
        number_format='(BN,F' // trim(w) // '.' // d // ')'

    end if

    ! Read the number
    read(coefficient_string,number_format) coefficient


    ! Save where it's needed (is there an easier way to do it?)
    select case (name)
        case ('d1')
            d1=coefficient
        case ('r1')
            r1=coefficient
        case ('r2')
            r2=coefficient
        case ('a')
            exit
        case ('teta')
            exit
        case ('freq')
            freq=coefficient
        case ('Dt')
            exit
        case ('mu')
            mu=coefficient
        case ('g0')
            g0=coefficient
        case ('r_t')
            r_t=coefficient
        case ('height')
            height=coefficient
        case ('lx')
            lx=coefficient
        case ('ly')
            ly=coefficient
        case ('lz')
            lz=coefficient
        case ('m_c0')
            m_c0=coefficient
        case ('Jx')
            Jx=coefficient
        case ('Jy')
            Jy=coefficient
        case ('Jz')
            Jz=coefficient
        case ('gmax')
            gmax=coefficient
        case ('I_s')
            I_s=coefficient
        case ('K')
            K=coefficient
        case ('Vmin')
            Vmin=coefficient
        case ('tsp_0')
            tsp_0=coefficient
        case ('Fmax')
            Fmax=coefficient
        case ('Isp')
            Isp=coefficient
        case ('n')
            n=coefficient
        case ('tfin')
            tfin=coefficient
        case ('cont')
            cont=coefficient
        case ('Tmax')
            Tmax=coefficient
        case default
            print*, 'Variable ', name, ' is not recognized'
    end select


  end do sentence_reader


  ! Other stuff I need
  teta=atan((r1 - r2)/d1)
  a=sqrt(d1**2 + (r1 - r2)**2)
  Dt=1/freq
  r=r_t + height
  omega=(mu/(r**3))**0.5
  H=(r*mu)**0.5
  Jx0=Jx - I_s
  Jy0=Jy - I_s
  Jz0=Jz - I_s
  c1=Isp*g0
  F=n*Fmax
  DV=(F/m_c0)*tsp_0

  ! Shows that the function is correctly executed
  data_module=1
  print*,'Before'
  print*, d1, r1, r2, a, teta, freq, Dt, mu, g0, r_t, height, r, omega, H, lx, ly, lz, m_c0, &
        Jx, Jy, Jz, gmax, I_s, K, Jx0, Jy0, Jz0, Vmin, tsp_0, Fmax, Isp, c1, n, F, DV, tfin, cont, Tmax

end function data_module

PS. I know modules, but with open and all the other stuff I couldn't get them to work. Would love to.

What I want to do is to pass the data d1, r1, ecc that I collected in data_module to main and save them in main, but doing it this way it doesn't save them (if you run it, when you print them "before" everything is fine, when you print them "after" you got all zeros.

5
  • Show your code. It is not very clear to me what you are describing. What is your function returning? Is it a function or a subroutine? Do you know modules?(you should stackoverflow.com/documentation/fortran/1139/…) Commented Mar 27, 2017 at 19:19
  • you need to give the variable as arguments in the function def: real function data_module (d1,r1,r2,...) (If you actually use a module this sort of mistake would give you a pretty clear error message ) Commented Mar 27, 2017 at 20:13
  • agentp, I'm pretty sure I tried that 5 times, and it never worked. Now I tried it again and it magically worked. That's odd, but thank you. Know I feel a little bit an idiot, but hope it could help somebody else looking on internet. I looked for a while and found nothing about it. Commented Mar 27, 2017 at 20:19
  • as a matter of style this should be a subroutine not a function since you never set the function return value (I don't see data_module= .. anywhere) or try to use it. Commented Mar 27, 2017 at 20:19
  • It's actually there, at the bottom. I use it to make sure I read it, but it's probably pointless, so I will probably use a subroutine, thank you Commented Mar 27, 2017 at 20:22

1 Answer 1

1

Okay, there are a few things I notice.

  1. Your function is of type real, but you set it only to 1 (an integer), to, as you put it in the comment "Show that the function is correctly executed". It's not uncommon to make a procedure return a value to show whether it executed correctly or not, but it's usually an error code, with zero meaning that no error occurred and everything went fine. Also, you might want to declare the function as integer instead of real, as integers are better for that kind of thing. (More reliable to compare.)

  2. As to your actual question: If you want to pass more than a single value back to the calling routine, you would want to declare intent(out) dummy variables. See this example:

    integer function test_output(outdata)
        integer, intent(out) :: outdata(10)
        integer :: i
        outdata = (/(i, i=1, 10)/)
        ! All worked well
        test_output = 0
        return
    end function test_output
    
  3. Modules are the way to go. Here is a very limited example on how to incorporate the function above into a module, and using that module in a program:

    module mod_test
        implicit none
        ! Here you can place variables that should be available
        ! to any procedure using this module
    contains
        ! Here you can place all the procedures (functions and
        ! subroutines)
        integer function test_output(outdata)
            integer, intent(out) :: outdata(10)
            integer :: i
            outdata = (/(i, i=1, 10)/)
            ! All worked well
            test_output = 0
            return
        end function test_output
    end module mod_test
    
    program test
        ! The 'USE' statement is the only thing that needs to be 
        ! *ahead* of the 'implicit none'
        use mod_test
        implicit none
        integer :: mydata(10) ! The variable that will contain the data
                              ! from the function
        integer :: status     ! The variable that will contain the error
                              ! code.
        status = test_output(mydata)
    
        if (status == 0) then
             print*, mydata
        end if
    
    end program test
    

    If the module is in a different source file, you need to compile them this way (assuming that you use gfortran):

    $ gfortran -c -o mod_test.o mod_test.f90
    $ gfortran -c -o test.o test.f90
    $ gfortran -o test test.o mod_test.o
    
Sign up to request clarification or add additional context in comments.

2 Comments

A minor additional point - there's no point in returning an error code if it is never going to be set to an error value.
True, but since he used an error code (or something similar to that) in his own example, I wanted to show how that would be included. Also: If you are reasonably certain that at a point in the near future you will add some sort of error checking, having it in helps as you don't have to change quite as much code later on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.