A Simple Way to Combine Fortran and Stata in Your workflow
Lin Shao, 2016
Introduction
Our tasks are best done by utilizing the comparative advantage of different tools. As an example, we might want to use Stata for data processing and Fortran for optimization. Yet sometimes, the Stata task and the Fortran task have to be done sequentially. And we do not want to sit still and wait for the Stata task to end and manually begin the Fortran task.
Consider for example the following set of tasks:
- Data processing, generate some data moments (Stata)
- Optimization using the data moments (Fortran)
- More manipulation of data using the optimization results from the previous step (Stata)
Step 2 can not start until step 1 is finished; and step 3 can not start until step 2 is finished. If we do this manually, we would have to run Stata code for step 1, wait for it to end; and start the Fortran code, wait for it to end; and start another Stata code again.
In this notes, I introduce a very simple way to deal with this problem, so that we can free ourselves from the computer.
The basic ideas is that, we ask Stata to send a “go ahead” message to Fortran when step 1 is finished; and ask Fortran to send a “go ahead” message to Stata when step 2 is finished.
More specifically, we maintain two “signal” files (simple text files would do). The first file deals with the sequentiality between step 1 and 2: Stata writes signal into this file and Fortran reads signal from the file. Once Stata finishes step 1, it opens this file and writes a signal into it. At the same time, we tell Fortran to wait while repeatedly read the same file until it receives a signal to move on. The wait process can be implemented by a simple “do while” loop.
Similarly, the second file deals with sequentiality between step 2 and 3. The only difference is now Fortran writes and Stata reads. Stata is asked to wait until the signal says to move ahead. The wait process can be implemented using a simple “while” loop.
Below are examples of Fortran and Stata code. Run the Fortran code first, because it initializes the signal files.
Fortran file
PROGRAM MAIN
INTEGER :: iwait
! sig_ok = 0 means wait; sig_ok = 1 means go ahead
REAL :: sig_ok
!***Initializing the signal files
sig_ok = 0
OPEN(UNIT = 1, FILE='sig_ok_1.txt')
WRITE(1,*) sig_ok
CLOSE(UNIT=1)
OPEN(UNIT = 2, FILE='sig_ok_2.txt')
WRITE(2,*) sig_ok
CLOSE(UNIT=2)
!******Wait for the signal from STATA to proceed
iwait = 0
sig_ok = 0
DO WHILE(sig_ok .EQ. 0)
! Ask Fortran to read the signal file once every 5 seconds
CALL SLEEP(5)
OPEN(UNIT = 1, FILE='sig_ok_1.txt')
READ(1,*) sig_ok
CLOSE(UNIT=1)
iwait=iwait+1
PRINT *, "iwait", iwait
ENDDO
!******Optimization
PRINT *, "Step two finished"
!******Send a signal to STATA to proceed
sig_ok = 1
OPEN(UNIT = 2, FILE='sig_ok_2.txt')
WRITE(2,*) sig_ok
CLOSE(UNIT=2)
END PROGRAM MAIN
Stata file
******Step one
display "Step one finished"
******Send the signal to Fortran
clear
set obs 1
generate var1 = 1 in 1
export delimited var1 using "sig_ok_1.txt", delimiter(tab) novarnames replace
******Wait for the signal from Fortran
local sig_ok = 0
while `sig_ok' == 0{
import delimited "sig_ok_2.txt", clear
local sig_ok = v1[1]
display `sig_ok'
}
******Step three
display "Step three finished"