How to convert a big fortran IV code to matlab ?
Show older comments
Hello everyone,
I am in deep trouble trying to convert a very old fortran IV code written in 1984 to matlab.
I have tried firstly to find a tool in order to go from fortran IV to f90, but I am a complete beginner of fortran language...
The code is 2500 lines and has many many subroutines, I am losing hope and I am thinking of convert it manually... What do you think ?
Here is the study linked to the code : https://ntrs.nasa.gov/citations/19850022698
Thanks for your help
Answers (4)
Jan
on 16 Mar 2022
2 votes
I'd never trust an automatic translation. But if you try it, make it as simple as possible: no intermediate conversion to FORTRAN 90.
Fortunately 2500 lines of FORTRAN is small enough to be conveted manually. This will be abou 1000 or less lines of Matlab code.
But what about using the FORTRAN code directly through a Mex wrapper? Do you have a FORTRAN compiler? Then all you have to do is to convert the Matlab variables to the equivalent representation of FORTRAN variables.
I've used f2c successfully to do this with an integrator. The original code has over 100'000 lines of code. Calling C from Matlab is easy also.
6 Comments
Clément Carré
on 16 Mar 2022
Jan
on 16 Mar 2022
A Mex wrapper is not complicated. It gets a list of the input variables. With mxGetData you get a pointer to the memory of the input values. You can create new arrays for the output and forward their pointers to the original FORTRAN code, or to the C code created by f2c.
John D'Errico
on 16 Mar 2022
Edited: John D'Errico
on 16 Mar 2022
I'd suggest that an automatic translation is like Jan says, a bit of slightly risky business. But a manual translation is also dangerous, and probably more so, unless you fully understand what they were doing in the code, and you fully understand both the source and the destination languages. In either case, you would want to do some fairly intensive testing of the code to validate the results. See that you get the same result from both tools.
And that suggests Jan's recommendation is the correct approach: to just use MEX to allow you to call the code directly from MATLAB. This requires no more than learning how to pass the correct inputs to the tool as arguments, and to properly compile the result to be then used directly from MATLAB. This must be the better solution. Regardless you would still need to validate it to insure you did the job correctly.
If you cannot do the mex creation, then you would best find a programmer who is able to do the task for you, and I assume this would involve paying them for the service. But remember, that would save your own time, which is surely valuable too.
James Tursa
on 16 Mar 2022
Edited: James Tursa
on 16 Mar 2022
Which Fortran code did you use with Ben Barrows f2matlab? You should use the simpler FIV or F77 code as the source, not any F90 code.
Also, what does this code do? Just calculations? Read/write files? Keyboard/console I/O? Some of these capabilities are easily converted, and others not so much. A lot of Fortran syntax is identical to MATLAB, and loops & control statements are generally pretty easy to convert. Where you will run into trouble is if you have any GOTO statements, which MATLAB doesn't support. Also subroutines, which behave as pass-by-reference in Fortran, would need to be rewritten using special syntax in MATLAB to get the same behavior.
Clément Carré
on 17 Mar 2022
Steven Lord
on 17 Mar 2022
Rather than trying to convert each line of Fortran code into MATLAB, if you do want to perform that conversion rather than using that code through MEX I'd take a slightly higher level approach: the skyscraper view rather than the ground level view (looking at each line) or the 30,000 foot view (looking at the application as a whole.)
You indicated the code has many subroutines. That's where I'd start attacking the problem. Take a subroutine and read through it carefully. Understand what it requires as inputs, what it returns as outputs, and what it does (not in terms of individual instructions like "add flour to a bowl", "add eggs to the bowl", "mix", etc. but in terms of purpose like "this subroutine bakes a cake.") Then write an equivalent MATLAB function that does what you understand that subroutine to do. It may not achieve that purpose in the same way or with equivalent operations but that's okay.
To lock down the behavior of that function, write tests for it. [Don't worry if you're not familiar with using classes in MATLAB; that documentation page describes how to write class-based tests, function-based tests, and/or script-based tests.] You may also want to extract out the Fortran subroutines and pass those same test cases into it to check that the Fortran and MATLAB code gives the same results.
Once you have one function written and extracted out of the Fortran code, look for subroutines that depend only on the subroutines you've already converted. Keep carving off bite-sized pieces until you're done or until you have the components necessary to tackle the larger bits.
It's not an easy task. Believe me, I've done this conversion for some pretty involved Fortran code myself. But it can be manageable.
Ben Barrowes
on 17 Mar 2022
0 votes
Your link goes to a PDF scan of the code. Do you have this code in a proper Fortran text file? Have you been able to compile it? Those are necessary first steps before trying to convert the code into Matlab.
Once you have running Fortran code, f2matlab has a good shot at getting you closer to runnable matlab code, but you would have to refactor all the goto's out first.
If you get stuck on the conversion, send me a PM With the working Fortran code, and I can take a look.
1 Comment
Clément Carré
on 17 Mar 2022
Edited: Clément Carré
on 17 Mar 2022
Clément Carré
on 17 Mar 2022
0 votes
5 Comments
James Tursa
on 17 Mar 2022
Edited: James Tursa
on 17 Mar 2022
I have done a high level scan through this source code. Not only does this code have a lot of GOTO's, it has a lot of three-way if-branching. It all adds up to lots of complicated spaghetti control flow. Some of these GOTO's can be easily converted to while-loops or if-then-else branching, but others will not. This code is not trivial to convert to MATLAB, and I would expect any automated conversion s/w to have lots of problems with it. IMO this code will require a lot of manual work to convert by someone who is very familiar with Fortran and MATLAB.
E.g., take this section of Fortran code:
3 IF (J.LE.2) GO TO 5
IF (J.EQ.N) GO TO 4
JJ=3
GO TO 6
4 JJ=2
J=N-1
GO TO 6
5 JJ=1
J=3
6 K=J-1
M=J-2
L=J+1
In this case the GOTO's are simply forward branches that can be replaced with if-else-endif logic. The MATLAB equivalent (assuming it is OK for the variables to be doubles in the MATLAB code) is
if( J <= 2 )
JJ = 1;
J = 3;
elseif( J == N )
JJ = 2;
J = N - 1;
else
JJ = 3;
end
K = J - 1;
M = J - 2;
L = J + 1;
But now take a look at this Fortran snippet:
1 CALL INPUT (TITLE,ITER,IPLOT,IPUNCH,IOP,ICAMTK,INTR,YLTE,YNOSE,YUT
1E,NINT,XINT,CNEW,NP,X,Y,W,THETA,YPS,YPPS,NOSE,CHORD,IERR,nu,nl)
IF (IERR-1) 2,1,5
C
C SMOOTH AIRFOIL COORDINATES
C
2 CALL SMOXY (THETA,X,Y,W,YSMO,YPS,YPPS,NP,NOSE,YLTE,YNOSE,YUTE,EPS,
1DF,ITER,TITLE,IOP,IERR)
! a bunch of other code here
5 CONTINUE
That three way if-branch is going to be more tricky to convert. One branch goes backwards and two branches go forwards. By looking at the flow it appears the intent is a while-loop for the INPUT call until IERR is not a certain value, and then the rest is forward branching so an if-endif construct could replace it. The subroutine calls themselves would need to be replaced with syntax that mimics the pass-by-reference behavior of Fortran. This is doable, but not necessarily straightforward.
And who, in their right mind, breaks up the name of a variable between two lines!!!??? Why on Earth would you take the variable named YUTE and put the YUT part on one line and the E on the next line!!!??? This is bizarre, as if this code itself is the result of an automated code writing/conversion s/w. I can't think of a good reason why a human being writing this code would do that.
Etc., etc.
James Tursa
on 17 Mar 2022
Actually, I just thought of a reason a human being might split the name of a variable between two lines. If the coder was using a card-punch machine to write the code and suddenly hit the 72-character limit in the middle of the variable name, there would be two choices. Either start over and re-punch the entire card without that last variable name and then punch the next continuation line card starting with the full variable name, or simply keep the card already punched and put the last letter of the variable name on the next punched card. We can see what choice was made ...
Ben Barrowes
on 18 Mar 2022
This is indeed spaghetti code, but it is not alone. There are millions upon millions of lines of spaghetti code like this in fortran in use and trusted every day. Something tells me that in 50 years, people will look back on (what we now consider) quality matlab code and cringe... "They were still coding by hand?!!" "Counting bits and bytes?!" "How bug-bedeviled!!"
And James, you are right, these types of branches and goto's are hard to convert, but between polyhedron's spag and my own "remgoto.m" (closed source), I can automatically refactor all goto's and arithmetic if's in fortran on its way to modern fortran, matlab, or python.
I'm waiting for Clement to post compilable code in fortran before I can try my tools on it.
Paul
on 18 Mar 2022
I was going to ask about tools like Polyhedron's Spag. Is that still around?
Ben Barrowes
on 21 Mar 2022
Yes! Spag and its author John Appleyard are still around and actively developed. John responds to my requests for improvements and is good to work with. Go here and click on the link to plusfort:
Clément Carré
on 21 Mar 2022
0 votes
4 Comments
Ben Barrowes
on 21 Mar 2022
Clement, I download your code and took a look. Things went well, until... SMOOTH.FOR unfortunately manipulates memory in an old fashioned was that Matlab cannot do. In the fortran, the problem is that the common blocks rename variables in different routines to different names. Take this for example in the subroutine afsmo:
COMMON /HLM/ DUMMX(2000)
But in subroutine badpt we have this definition:
COMMON /HLM/ TI(100),YI(100),YN(100),THETA(100),BIP(1600)
Both blocks share the same memory space for 2000 four-byte reals, but different variables are named in this memory block. While DUMMX is a single variable vector of 2000 four-byte reals, in badpt, the first 100 reals are called the vector TI, and second 100 reals are called YI, and so on.
This kind of memory manipulation is near impossible in matlab. It can be done with the handle class, but it is better to fix the fortran code and then try to convert. Sorry for the bad news. The only thing as bad as renaming common variables (in terms of memory manipulation) is how some programmers use "equivalence" in fortran.
Clément Carré
on 22 Mar 2022
Paul
on 22 Mar 2022
Aren't there F-LINT tools that at least would be helpful in finding that COMMON block variable mashing and other old-school FORTRAN tricks that might also be problematic for converting to Matlab? I don't recall if the F-LINT tools will fix the code, but I'm pretty sure they will find all instances.
James Tursa
on 22 Mar 2022
Edited: James Tursa
on 22 Mar 2022
@Ben Barrowes Those COMMOM blocks with different named variables might not be that bad. It appears to me that maybe this was done simply as a memory saving device, and not as a means to pass variables between routines. E.g., That DUMMX variable doesn't appear anywhere else in the code, so I suspect it is simply there to create a memory allocation block to be used as workspace by the other routines, and that these routines don't actually use it a a means to pass variable values back & forth. A quick glance at a routine that uses this block with different named variables reveals that the first thing it does is read values into the variables, which supports this supposition. Regardless, your point is well taken and one would have to examine every routine that uses this block to verify that it is simply used as a temporary workspace and not for variable passing. If that could be verified, then in MATLAB simply just ignore the COMMON block and declare the variables directly.
A quick check (but not a proof) of this concept would be to get rid of all the COMMON blocks and instead declare the variables directly as local variables and see if the program produces the same output. If it does, then go through the effort of trying to verify that no variable passing is intended. If it doesn't, then find the places where variable passing is taking place and determine if it is intended or if it is an original coding error (i.e., it is always possible that there is a bug in the way these COMMON blocks were originally coded).
Why did programmers do this originally? Back in the old days programs were run in batches on large mainframe machines. It was not uncommon for the department or organization running the program to be charged not just for CPU time but for memory footprint also. A department or organization could save money by employing these memory saving techniques. So I try not to judge these programmers too harshly when I see this stuff. We just have to deal with it if we want to reuse the code ...
Categories
Find more on Fortran with MATLAB in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!