R MacDonell
R MacDonell

Reputation: 41

Numpy distutils not recognizing Fortran file types

I am trying to write a python package with Anaconda3 which includes some compiled Fortran libraries. Based on the examples given online, I need to use numpy.distutils.core.Extension to have the extension build correctly. Here is my somewhat-minimal working example directory:

MANIFEST.in
setup.py
bin
 └─── test_smat
mypkg
 ├─── __init__.py
 ├─── compiled
 |     ├─── __init__.py
 |     └─── gaussian.f90
 └─── pystuff
       ├─── __init__.py
       └─── buildmat.py

MANIFEST.in contains:

recursive-include mypkg *.f90

setup.py contains:

from setuptools import find_packages
from setuptools import setup
from numpy.distutils.core import Extension


ext_modules = [
    Extension('mypkg.compiled.gaussian',
              sources=['mypkg/compiled/gaussian.f90'])
               ]


setup(
    name='mypkg',
    version='0.1',
    description='This should work',
    packages=find_packages(),
    scripts=['bin/test_smat'],
    install_requires=['numpy>=1.7.0'],
    ext_modules = ext_modules
      )

gaussian.f90 contains (EDIT: simplified):

!                                                                           
!  Calculates the overlap between two Gaussians                             
!                                                                           
subroutine overlap(x1, x2, a1, a2, S)                                       
    implicit none                                                           
    double precision, intent(in)  :: x1, x2, a1, a2                         
    double precision, intent(out) :: S                                      

    double precision, parameter   :: pi=atan(1.0_8)                         
    double precision              :: N1, N2, dist, expt                     

    N1 = (pi / (2*a1)) ** (-0.75)                                           
    N2 = (pi / (2*a2)) ** (-0.75)                                           
    dist = abs(x2 - x1)                                                     
    expt = a1*a2*dist**2 / (a1 + a2)                                        
    S = N1 * N2 * exp(-expt) * (pi / (a1 + a2)) ** 1.5                      

    return                                                                  
end subroutine overlap

buildmat.py contains:

"""                                                                         
Module for building matrices of Gaussian properties                         
"""                                                                         
import numpy as np                                                          
import mypkg.compiled.gaussian as gaussian                                  


def olap_matrix(x, a):                                                      
    """Builds an overlap matrix from a set of positions and widths."""      
    ngauss = len(x)                                                         
    Smat = np.empty((ngauss, ngauss))                                       

    for i in range(ngauss):                                                 
        for j in range(ngauss):                                             
            Smat[i,j] = gaussian.overlap(x[i], x[j], a[i], a[j])            

    return Smat

test_smat contains:

#!/usr/bin/env python                                                       
"""                                                                         
Script to test Python modules depending on Fortran libraries.               
"""                                                                         
import mypkg.pystuff.buildmat as buildmat                                   


def main():                                                                 
    """The main routine."""                                                 
    x = [-1, -0.9, -0.5, -0.1, 0.0, 0.0001, 0.001, 0.01, 0.1]               
    a = [1.2, 0.8, 0.3, 1.5, 3.2, 0.9, 0.8, 0.1, 1.6]                       
    mat = buildmat.olap_matrix(x, a)                                        

    print(mat)                                                              


if __name__ == '__main__':                                                  
    main()

Ideally, I should be able to install with python setup.py install and run test_smat to get a printed output. However, when I try to install I get:

running install                                                             
running bdist_egg                                                           
running egg_info                                                            
writing mypkg.egg-info/PKG-INFO                                             
writing dependency_links to mypkg.egg-info/dependency_links.txt             
writing requirements to mypkg.egg-info/requires.txt                         
writing top-level names to mypkg.egg-info/top_level.txt                     
reading manifest file 'mypkg.egg-info/SOURCES.txt'                          
reading manifest template 'MANIFEST.in'                                     
writing manifest file 'mypkg.egg-info/SOURCES.txt'                          
installing library code to build/bdist.linux-x86_64/egg                     
running install_lib                                                         
running build_py                                                            
creating build                                                              
creating build/lib.linux-x86_64-3.6                                         
creating build/lib.linux-x86_64-3.6/mypkg                                   
copying mypkg/__init__.py -> build/lib.linux-x86_64-3.6/mypkg               
creating build/lib.linux-x86_64-3.6/mypkg/pystuff                           
copying mypkg/pystuff/buildmat.py -> build/lib.linux-x86_64-3.6/mypkg/pystuff
copying mypkg/pystuff/__init__.py -> build/lib.linux-x86_64-3.6/mypkg/pystuff
creating build/lib.linux-x86_64-3.6/mypkg/compiled                          
copying mypkg/compiled/__init__.py -> build/lib.linux-x86_64-3.6/mypkg/compiled
running build_ext                                                           
building 'mypkg.compiled.gaussian' extension                                
C compiler: gcc -pthread -B /home/rymac/.anaconda3/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC

error: unknown file type '.f90' (from 'mypkg/compiled/gaussian.f90')

Am I missing something that tells NumPy distutils that the extension is a Fortran 90 file? Other examples on this website seem to have a setup.py file that is just as simple without encountering this error. Changing the Fortran extension to .f95 or .f leads to the same type of error.

Upvotes: 2

Views: 965

Answers (1)

R MacDonell
R MacDonell

Reputation: 41

The issue lies in trying to use setuptools.setup with numpy.disutils.core.Extension. The numpy version of Extension contains additional information about f2py that isn't included in setuptools.Extension, but this can only be used to build Fortran libraries if numpy.distutils.core.setup is used as well.

The solution: replace from setuptools import setup with from numpy.distutils.core import setup in setup.py.

Upvotes: 2

Related Questions