NetCDF Fortran on Conda Forge for Windows

I just spotted that about a month or so ago, the netcdf-fortran Conda package from Conda Forge got a Windows build (there has been Linux and Mac versions for ages, but Windows had some issues): Netcdf Fortran ::

This is, potentially, awesome. An easy way to install NetCDF Fortran on Windows!

However, after giving it a quick test, I stumbled across the age old issue of incompatible GFortran versions: cannot read module file netcdf.mod because it was created by a different version of GNU Fortran.

Correct me if I’m wrong, but this basically means that the only way to use this Conda package in the usual use netcdf way is to use the same version of GFortran as the Conda build used. Which from what I can tell is the old m2w64 version 5.3.

I know @lkedward has mentioned his NetCDF interfaces package before as an awesome solution for this in a lot of cases (GitHub - LKedward/netcdf-interfaces: fpm package containing module interfaces for netcdf-fortran). But it still left me wondering whether the situation is as I’ve summarised here, and I’m not missing some other solution?

Ancient compilers and incompatible mod files: two of the albatrosses around Fortran’s neck.

1 Like

I’m always surprised that a standard transportable mod file format is not a higher priority when it comes to new Fortran features. Take it from someone who got stuck with the task of supporting multiple versions of MPI, HDF5, netCDF etc. just because of the mod file incompatability problem a transportable mod file format will solve a lot more problems for Fortran developers than a some of things that will sadly end up in Fortran 2023 and Fortran will be stuck with forever. For example, I refer everyone to @jacobwilliams (excellent) March 27, 2022 post on Degenerate Conic | The New Features of Fortran 202x and his comments about the new “multiple subscript” and using an integer array to specify rank and bounds. I am in total agreement with Jacob on these two new “features”. In 40 plus years of developing and modifying CFD and Finite element codes I have never seen a case where either of these two features would lead to a better code.

1 Like

The question is whether it is possible for the Fortran Standards Committee to provide some basic standards for Fortran’s .mod files to ensure compatibility, C/C++ uses text files as header files, and Fortran’s .mod seems to be some kind of binary code, resulting in differences in .mod files in different historical versions of the same compiler, and .mod files between compilers from different vendors are not interoperable.

That program is a nice demo of the difference between sin() and sinpi(). However, I would not say that the first column is “wrong”. I would expect those numbers are the closest number to the exact value of sin(x) for those values of x. If they are, then they are not “wrong”, they are “right”, and if the first column were all zeros, like the second column, then they would in fact be “wrong”.

1 Like

Can you elaborate on these statements a little? If one considers 0.0_dp to be the mathematically exact resullt for both columns of numbers, then spacing(0.0_dp) is many orders of magnitude smaller than the values on the left from sin(x). My previous post explains why those values are what they are. Namely, x is a fp value near the mathematical vaue of PI. Whatever that value is (which of course depends on the floating point representation), the exact sin(x) value is nonzero. The slope of sin(x) is about -1 in that neighborhood, so whatever the difference is between the floating point value and the exact value will then result in an exact sin(x) value of that same magnitude. The values in the first column are presumably the correctly rounded values of those differences. There are other issues involved with range reduction, particularly for large values of the arguments, but I don’t think that is a central part of this issue regarding the difference between sin(x) and sinpi(x) and what the “exact” values should be for the two columns.

The other issue you mention is FE_INEXACT. I think that occurs for any floating point multiplication that involves rounding (i.e. where bits are lost in the representation of the result). There are some cases, such as when an operand is a power of 2, that do not involve rounding, but most multiplications do involve rounding. So in a complicated function like sin(x), some or all of the multiplications involved in the evaluation are going to raise that exception.

Could you elaborate how do you compute ULP in there? I’ve seen a couple formulas for it, but perhaps you have a different approach.

I am writing some code for computing non-elementary functions. I am also comparing the computed value with a higher precision one, but then the error checking has merely consisted in plotting the relative error and checking it is below 5e-8 (for floats; or at least, below 1e-7).

This sounds very sensible. Do we know if something like this has been proposed before? I can’t believe it hasn’t been, it’s surely not just a handful of us that struggle with this .mod file incompatibility. What are the barriers? I’m guessing back compatibility is the main one.

My answer to a transportable mod file would be to base it on something like a markup language (XML or a derivative maybe). Compiler options could select between native or standard format for
output. I’m willing to allow the compiler vendors native format and a standard format to coexist just as long a there are options to read and write the standard format. You could view the standard format as something like using the COO sparse matrix format as a bridge for converting between other formats. The vendors could write their own translators to their native formats. There is probably a way to have some kind of encryption decryption capabilty for folks selling commercial libraries to protect their IP. As to why this hasn’t been done before, anything I say would be speculation.

The specific reasons may be familiar to some of the old Fortran users, I’m just a beginner, but I think there’s always a way to change, the key is who drives it? We don’t have to get to this point right away, maybe we can look for a unified interface mod file for Fortran for the next decade.

It is clearly fragmented at the moment, and the lack of intercommunication of .mod files is one of the reasons why some well-known libraries like MKL, IMSL, LAPACK, FFTW tend to use F77 style interfaces. HDF5 and NetCDF have compatibility risks because they use F90 module functions.

On Windows, I was able to use MSYS2-gfortran to call mkl’s F77 dynamic link library, but once mkl was F90-style and used module functionality, the .mod interface would not necessarily be parsed by MSYS2-gfortran.

Most Fortran compilers use .mod as the file suffix for the module files that they generate. Until recently, the Absoft compiler would attempt to read and use .mod files if they existed, rather than regenerate them in the course of compilation. There were times when it would attempt to read .mod files produced by Gfortran (which are plain text) and the ensuing behavior was entertaining. Thus, some provision will be needed to enable each compiler to distinguish between its own module files from other compiler’s module files, unless there is complete compatibility of mod files across all compilers.

Maybe I’m missing something but I’m not asking for vendors to read other vendors formats. I’m asking for a standard format that everyone can read (and translate to their native format if so desired). Even then how hard would it be to add a string to a vendors current mod file (I’m guessing they all have a header block of some kind at the start of the file) that says what compiler produced the file.

A bit of history.

I’ve worked with another language that used modules - Modula 2. Here is a link to a page about the language.

Modules created by these compilers weren’t compatible with the compilers I used.

Perhaps the more solvable problem is how to work with Conda Forge to get them to support more recent compilers? I too have these issues. I can’t use the ancient gfortran compilers because they don’t support the language features I use (or they have show stopping bugs). Also I need to be able to support the intel compiler. In some cases, there will be a conda package (e.g. HDF5) that has built in fortran bindings, but I can’t use it because it was compiled with gfortran. So I’m back to having to compile it myself on multiple platforms.

In a future where all Fortran libraries are FPM compatible, these issues may go away since it could be trivial to just compile everything you need very easily. Right now, it’s still very chaotic and tedious (make files, cmake, scons, random build scripts, downloading and manually editing files from some random webpage, poor Windows support, etc.)

1 Like

Agreed. On a similar note, I noticed when building a Conda package on Windows just now that you get a warning message that… legacy MSVC compiler setup. This will be removed in conda-build 4.0. If this recipe does not use a compiler, this message is safe to ignore. Otherwise, use {{compiler('<language>')}} jinja2 in requirements/build.

…if you use the MSYS2 GFortran (v5.3). If you do as they suggest and use {{ compiler('fortran') }}, I think you get an even more ancient version of classic Flang.

I hope we have some success getting more modern Fortran compilers onto Conda Forge before they enact that threat!

1 Like

Even if .mod files were compatible across compilers, wouldn’t there still be a problem with object files? As far as I know there are no standard calling conventions for Fortran, and runtime library calls would also not be compatible.

I have a question about the netcdf-fortran installed by conda in windows. It shows the error of “undefined reference to `__netcdf_MOD_nf90_create’” and other “_netcdf_MOD_nf90” errors. I have set the -I"xxxx/include" and -L"xxxx/lib" -lnetcdff -lnetcdf.