I am a novice in the use of Modules, and I've got a question.
I have a very old code that uses dozens of named common blocks. I am considering replacing each with a Module of the same name. Is that a wise thing to do? I think I will end up with a single .f90 file containing all the named Modules, and replacing all the named COMMON statements and associated variable declarations appearing throughout the code with USE statements with the same names.
Every routine throughout the code has IMPLICIT NONE in it, and I think that will help me along the way.
Yes the should work but there are some BUTS. Commons are were often used as a workspace to save memory, so the variables in a particular common my not be the same names or types in different parts of the software in this case your approach will fail big time!
Creating a separate module for each COMMON seems extreme to me, though it does allow you to see who is using any particular shared variable. Is that a requirement?
I am in favor of the approach "If it ain't broke, don't fix it." I don't see that you'll gain anything significant by simply converting COMMONs to module variables, other than an "appearance" of being more modern. Unless there is a good reason to make this change, I'd suggest not doing it.
As an alternative, think about WHY the program uses COMMONs and how the program might be rewritten to avoid use of global variables at all. This will become especially important if you want to parallelize the application. In addition to the "save memory" approach Andrew mentions, COMMONs were also used to provide lots of context for subroutines without having to pass variables individually. COMMONs are error-prone and inhibit optimizations.
As best I can tell, the commons are used to pass collections of variables to subroutines instead of using long lists of arguments. I agree with Steve, "if it ain't broke, don't fix it". But it recently became necessary to increase array sizes in the common blocks, and the code mysteriously began to crash in Release build but not Debug build. After several days working on that, I have been unable to find the cause. It has been suggested that it is either a problem with the common blocks, or a compiler bug. Thus my motivation for the switch from common's to modules.
Almost all of the common's use the same variable names and declarations in every instance. There a few that don't, but I will either fix those, or leave them as common blocks.
I am also trying to buy the latest version of the Intel Fortran and C++ compilers, with IMSL. But this is proving to be way harder than it should be (I've encountered this problem before). The resellers offer up identical products with vastly different prices, and their sales people don't know what's different (it is not a matter of upgrade prices versus full version prices). They say the part numbers are Intel's numbers, but even Google can't find the numbers on the Intel site. Here's an example for which the resellers do not know what is different.
Studio XE Composer Edition for Fortran with Rogue Wave IMSL 7.0 for Windows
I managed to find what I'm looking for on the Intel site. So now I'm trying to find out if I qualify for Academic prices, which are much less than these prices.
$1,199.00 C++ and Fortran Part Number : PCE999WLGE01X1Z Product Type: Product With Maintenance/Support Operating System: Windows $999.00 IMSL Addon Part Number : RFL999WLGE01X1Z Product Type: Product With Maintenance/Support Operating System: Windows
Additional details here, https://software.intel.com/en-us/articles/academic-pricing (this includes an IMSL option). Click on the FAQ link also.
At the page above, when you click on a product to order, email and phone number contact information is shown for the Intel® Software Products Webstore if you hadn't already found that too. They should be able to advise on Academic qualification or not.
Let us know if you still require additional info/help.
Intel told me a .edu email address qualifies me for the Academic price, and I have one. So I just bought it. In the next few days I hope to see what the new version of XE Composer does with my crashing program.
I've been using Visual Studio 2010 with XE Composer 2013. I don't know what the new XE Composer will do about that when I install it. I am very interested in any tips anyone has.
The convenience of the link provided caused me to take a look after several years. I also downloaded the Fortran Composer product brief. I am happy to see the inclusion of Python; when was this done. I was not happy however to see nothing about Quickwin. Does this project type continue to be supported, even if it "goes without saying"?
By "new XE Composer" let's assume that implies our Parallel Studio XE 2017 Composer Edition, that will not integrate with your VS 2010. The system requirements are in the Release Notes, here.
You can elect to use the Microsoft Visual Studio 2013 Shell that is provided with our product; however, that limits you to Fortran only. The VS 2013 Shell does not support integration of any C++ compilers. If you require both Fortran and C++ under VS, then you might qualify to use the Microsoft Visual Studio Community edition (https://www.visualstudio.com/vs/). At the moment, MS VS Community edition defaults to the 2017 version which is not currently supported by our PSXE 2017 release. That support is coming in our next update release in the coming month.
I did find this VS 2015 Community download link, https://imagine.microsoft.com/en-us/Catalog/Product/101
Hope that helps.
@dboggs - Intel® Distribution for Python* was introduced with the initial Parallel Studio XE 2017 release late last year. QuickWin is still a supported project type.
The product which I just bought is:
Product: Intel® Parallel Studio XE Composer Edition for Fortran and C++ Windows* Serial Number 1: xxxx-xxxxxxxx SKU: PCE999WLAE01X1Z
Didn't this come with some sort of Visual Studio that will work with both Fortran and C?
Before installing this, I need to know for sure it will work. I don't want to suddenly be unable to build my projects.
Please edit your post to remove the serial number!
Commercial and Academic licenses include a Fortran-only environment based on Visual Studio. It does not support C++. If you need C/C++, you will need to get Visual Studio from Microsoft. The free Community Edition will work with both the Intel Fortran and C++ compilers.
Thanks, Steve. Sorry about the serial number. I have edited the post to remove it.
I am downloading Visual Studio Community 2015 32-bit (English). A whopper and a half at 3.69 GB!
Brian Murphy wrote:
.. I agree with Steve, "if it ain't broke, don't fix it". But it recently became necessary to increase array sizes in the common blocks, and the code mysteriously began to crash in Release build but not Debug build. ..
I abhor the view, "if it ain't broke, don't fix it" It is neither inspirational nor aspirational for a succeeding generation in any sphere of life but I'll spare the lecture.
When it comes to legacy code, especially FORTRAN, I currently follow the rule, "3 strikes and you are out"! If I have to refer to, modify or rebuild, or otherwise work with any legacy code for three times, I initiate my modernizing process on that code if possible i.e., if it's within my rights to do so. But before I make any change, I review, evaluate, extend/modify, and complete the testing and validation aspects of the current code base in conjunction with code coverage analysis and only when it appears comprehensive enough that I move to the next phase.
There are many existing codebases that would appear perfectly fine even with present-day compilers and one may at first wonder why change anything. However, the realities and requirements associated with the ever changing and advancing computational environments everywhere start to expose the limitations in one form or other and sooner or later things will come to a head.
With the use of COMMONs in FORTRAN to work with 'global data', I use a simple example with a quadrature calculation:
FUNCTION INTGRT(F, XMIN, XMAX) C Integrate F using trapezoidal rule IMPLICIT NONE C Argument list DOUBLE PRECISION F EXTERNAL F DOUBLE PRECISION XMIN DOUBLE PRECISION XMAX C Function result DOUBLE PRECISION INTGRT C Local variables DOUBLE PRECISION YMIN DOUBLE PRECISION YMAX C Calculations YMIN = F(XMIN) YMAX = F(XMAX) INTGRT = (XMAX-XMIN)*(YMAX+YMIN)/2D0 C END FUNCTION
FUNCTION Y(X) C Some user function: IMPLICIT NONE C Argument list DOUBLE PRECISION X C Function result DOUBLE PRECISION Y C Global data DOUBLE PRECISION M DOUBLE PRECISION C COMMON / CQUAD / M, C C Calculations Y = M*X + C C END FUNCTION
PROGRAM QUADRT C IMPLICIT NONE C Declarations DOUBLE PRECISION INTGRT EXTERNAL INTGRT DOUBLE PRECISION M DOUBLE PRECISION C COMMON / CQUAD / M, C DOUBLE PRECISION Y EXTERNAL Y DOUBLE PRECISION R, XMIN, XMAX C Instructions XMIN = 0D0 XMAX = 1D0 M = 1D0 C = 1D0 R = INTGRT(Y, XMIN, XMAX) C Reporting PRINT *, 'Result from INTGRT: ' , R PRINT *, ' Expected Result: ' , (M*XMAX**2/2D0+C*XMAX)- & (M*XMIN**2/2D0+C*XMIN) C END PROGRAM QUADRT
The code, as shown above. can be argued is "ain't broke" and other than the use of the now obsolescent fixed-form syntax per Fortran standard, it should raise no warnings from the compiler. But few of the existing legacy codes can withstand the assault of /warn:all /stand (and /check run-time tests) settings applied to the compiler though and the ensuing errors and warnings are better addressed promptly.
However there are any number of enhancements one can make to the code starting with defined floating-point representation, and the use of modules, and explicit interfaces, and with derived types and type-bound procedures to make the code more readily maintainable (here consider also who one would or can pass the baton to), portable, extensible, and parallelizable. Codes that manage such a shift, at least a bit ahead of the time if not any sooner than when such needs start to matter, are the ones that will find continued use.
Any of the books in this blog can provide more detail on the options if you are interested. In addition, there are references online, for example the work by Decyk, by Rouson et al.,, that one can review for more details.
Thanks for the remarks, FortranFan. The code I am working on was written over 25 years ago, but is still used quite a bit by users in many countries around the globe. I should now be past the half-way point of converting the common's to modules. Unfortunately, there is more mangling of variable names than I thought there was. Ugh! When I have the converted code ready to test, I'll be very pleasantly surprised if it runs without any troubles.
My remark was aimed at people who insist that old code has to be converted just because it is old. I agree that if you are making significant changes to an application it is worthwhile seeing if parts can be modernized. But wholesale conversion just for the sake of change usually introduces new bugs and is largely unnecessary.
Turns out there are just too many variable name changes among the common blocks of this old code, so I have abandoned my effort of converting them to Modules. The risk of introducing bugs is not worth it.
Once I figure out how to safely install my new version of Intel Fortran, I'm hopeful it may cure the crashing problem, or maybe identify where the problem is.
You might consider getting a 30-day free trial of Intel Inspector XE and running the program (a debug build works best) under its memory analysis - it may turn up something. (It does tend to gripe a lot about Fortran programs for things that aren't problems, but once in a while it spots a real problem.)
Brian Murphy wrote:
Turns out there are just too many variable name changes among the common blocks of this old code, so I have abandoned my effort of converting them to Modules. ..
I hope you will not abandon your effort altogether, but just postpone it a little.
What exactly do you mean by "variable name changes among the common blocks"? If you keep the simple example in Message #15 in mind, is your situation such that with a certain COMMON block, say CQUAD, the variable components such as M and C are referred to by different names in different contexts but still they have the same type, kind, and rank (TKR) characteristics everywhere? Or is EQUIVALENCE coming into play also? If the former, it may be workable for you with MODULEs too.
Can you provide a simple prototype of your code along the lines of the example in Message #15?