Package: f90wrap
f90wrap: Fortran to Python interface generator with derived type supportf90wrap is a tool to automatically generate Python extension modules
which interface to Fortran code that makes use of derived types. It
builds on the capabilities of the popularf2pyutility by generating a
simpler Fortran 90 interface to the original Fortran code which is then
suitable for wrapping with f2py, together with a higher-level Pythonic
wrapper that makes the existance of an additional layer transparent to
the final user.Copyright (C) James Kermode 2011-2021. Released under the GNU Lesser General
Public License, version 3. Parts originally based on f90doc - automatic
documentation generator for Fortran 90. Copyright (C) 2004 Ian Rutt.If you would like to license the source code under different terms,
please contact James Kermodejames.kermode@gmail.comDependenciesPython3.7+ (Python 2.7 no longer supported)Recent version ofnumpywhich includesf2pyFortran compiler - tested withgfortran4.6+ and recentifort12+InstallationFor the latest stable release, install withpip:pip install f90wrapThere is also aconda packageon conda-forge:conda install -c conda-forge f90wrapFor the development version, installation is as follows:pip install git+https://github.com/jameskermode/f90wrapNote that if your Fortran 90 compiler has a non-standard name
(e.g. gfortran-9) then you need to set theF90environment variable
prior to installing f90wrap to ensure it uses the correct one, e.g.F90=gfortran-9 pip install f90wrapExamples and TestingTo test the installation, runmake testfrom theexamples/directory. You may find the code in the various examples useful.Citing f90wrapIf you findf90wrapuseful in academic work, please cite the following
(open access) publication:J. R. Kermode, f90wrap: an automated tool for constructing
deep Python interfaces to modern Fortran codes.
J. Phys. Condens. Matter (2020)doi:10.1088/1361-648X/ab82d2BibTeX entry:@ARTICLE{Kermode2020-f90wrap,title="f90wrap: an automated tool for constructing deep Pythoninterfaces to modern Fortran codes",author="Kermode, James R",journal="J. Phys. Condens. Matter",month=mar,year=2020,keywords="Fortran; Interfacing; Interoperability; Python; Wrapping codes;f2py",language="en",issn="0953-8984, 1361-648X",pmid="32209737",doi="10.1088/1361-648X/ab82d2"}Case studiesf90wrap has been used to wrap the following large-scale scientific
applications:QUIP- molecular dynamics codeCASTEP- CasPyTep wrappers for electronic structure codeQEpy- Python wrapper for Quantum Espresso electronic structure codeSee thisJupyter notebookfrom a recent seminar for more details.UsageTo usef90wrapto wrap a set of Fortran 90 source files and produce
wrappers suitable for input to f2py use:f90wrap -m MODULE F90_FILESwhereMODULEis the name of the Python module you want to produce (e.g.
the name of the Fortran code you are wrapping) andF90_FILESis a list
of Fortran 90 source files containing the modules, types and subroutines
you would like to expose via Python.This will produce two types of output: Fortran 90 wrapper files suitable
for input tof2pyto produce a low-level Python extension module, and a
high-level Python module desinged to be used together with the
f2py-generated module to give a more Pythonic interface.One Fortran 90 wrapper file is written for each source file, namedf90wrap_F90_FILE.f90, plus possibly an extra file namedf90wrap_toplevel.f90if there are any subroutines or functions defined
outside of modules inF90_FILES.To use f2py to compile these wrappers into an extension module, use:f2py -c -m _MODULE OBJ_FILES f90wrap_*.f90 *.owhere_MODULEis the name of the low-level extension module.Optionally, you can replacef2pywithf2py-f90wrap, which is a
slightly modified version off2pyincluded in this distribution
that introduces the following features:Allow the Fortranpresent()intrinsic function to work correctly with
optional arguments. If an argument to an f2py wrapped function is
optional and is not given, replace it withNULL.Allow Fortran routines to raise a RuntimeError exception with a
message by calling an external functionf90wrap_abort().
This is implemented using asetjmp()/longjmp()trap.Allow Fortran routines to be interrupted withCtrl+Cby installing
a custom interrupt handler before the call into Fortran is made.
After the Fortran routine returns, the previous interrupt handler
is restored.NotesUnlike standardf2py,f90wrapconverts allintent(out)arrays tointent(in, out). This was a deliberate design decision to allow allocatable and automatic arrays of unknown output size to be used. It is hard in general to work out what size array needs to be allocated, so relying on the the user to pre-allocate from Python is the safest solution.Scalar arguments withoutintentare treated asintent(in)byf2py. To haveinoutscalars, you need to callf90wrapwith the--default-to-inoutflag and declare the python variables as 1-length numpy arrays (numpy.zeros(1)for example).Pointer arguments are not supported.Arrays of derived types are currently not fully supported: a workaround is provided for 1D-fixed-length arrays, i.e.type(a), dimension(b) :: c. In this case, the super-typeType_a_Xb_Arraywill be created, and the array of types can be accessed throughc.items. Note that dimension b can not be:, but can be a parameter.Doxygen documentation in Fortran sources are parsed and given as docstring in corresponding python interfaces. Doxygen support is partial and keyword support is limited tobrief,details,file,authorandcopyright.How f90wrap worksThere are five steps in the process of wrapping a Fortran 90 routine to
allow it to be called from Python.The Fortran source files are scanned, building up an
abstract symbol tree (AST) which describes all the modules, types,
subroutines and functions found.The AST is transformed to remove nodes which
should not be wrapped (e.g. private symbols in modules, routines
with arguments of a derived type not defined in the project, etc.)Thef90wrap.f90wrapgen.F90WrapperGeneratorclass is used to write
a simplified Fortran 90 prototype for each routine, with derived
type arguments replaced by integer arrays containing a
representation of a pointer to the derived type, in the manner
described inPletzer2008.
This allows opaque references to the
true Fortran derived type data structures to be passed back and
forth between Python and Fortran.f2py is used to combine the F90 wrappers and the original compiled
functions into a Python extension module (optionally, f2py can be
replaced by f2py-f90wrap, a slightly modified version which adds
support for exception handling and interruption during exceution of
Fortran code).Thef90wrap.pywrapgen.PythonWrapperGeneratorclass is used to
write a thin object-oriented layer on top of the f2py generated
wrapper functions which handles conversion between Python object
instances and Fortran derived-type variables, converting arguments
back and forth automatically.Advanced FeaturesAdditional command line arguments can be passed to f90wrap to customize
how the wrappers are generated. See theexamples/directory to see how
some of the options are used:-h, --help            show this help message and exit
  -v, --verbose         set verbosity level [default: None]
  -V, --version         show program's version number and exit
  -p PREFIX, --prefix PREFIX
                        Prefix to prepend to arguments and subroutines.
  -c [CALLBACK [CALLBACK ...]], --callback [CALLBACK [CALLBACK ...]]
                        Names of permitted callback routines.
  -C [CONSTRUCTORS [CONSTRUCTORS ...]], --constructors [CONSTRUCTORS [CONSTRUCTORS ...]]
                        Names of constructor routines.
  -D [DESTRUCTORS [DESTRUCTORS ...]], --destructors [DESTRUCTORS [DESTRUCTORS ...]]
                        Names of destructor routines.
  -k KIND_MAP, --kind-map KIND_MAP
                        File containting Python dictionary in f2py_f2cmap
                        format
  -s STRING_LENGTHS, --string-lengths STRING_LENGTHS
                        "File containing Python dictionary mapping string
                        length names to values
  -S DEFAULT_STRING_LENGTH, --default-string-length DEFAULT_STRING_LENGTH
                        Default length of character strings
  -i INIT_LINES, --init-lines INIT_LINES
                        File containing Python dictionary mapping type names
                        to necessary initialisation code
  -I INIT_FILE, --init-file INIT_FILE
                        Python source file containing code to be added to
                        autogenerated __init__.py
  -A ARGUMENT_NAME_MAP, --argument-name-map ARGUMENT_NAME_MAP
                        File containing Python dictionary to rename Fortran
                        arguments
  --short-names SHORT_NAMES
                        File containing Python dictionary mapping full type
                        names to abbreviations
  --py-mod-names PY_MOD_NAMES
                        File containing Python dictionary mapping Fortran
                        module names to Python ones
  --class-names CLASS_NAMES
                        File containing Python dictionary mapping Fortran type
                        names to Python classes
  --joint-modules JOINT_MODULES
                        File containing Python dictionary mapping modules
                        defining times to list of additional modules defining
                        methods
  -m MOD_NAME, --mod-name MOD_NAME
                        Name of output extension module (without .so
                        extension).
  -M, --move-methods    Convert routines with derived type instance as first
                        agument into class methods
  --shorten-routine-names
                        Remove type name prefix from routine names, e.g.
                        cell_symmetrise() -> symmetrise()
  -P, --package         Generate a Python package instead of a single module
  -a ABORT_FUNC, --abort-func ABORT_FUNC
                        Name of Fortran subroutine to invoke if a fatal error
                        occurs
  --only [ONLY [ONLY ...]]
                        Subroutines to include in wrapper
  --skip [SKIP [SKIP ...]]
                        Subroutines to exclude modules and subroutines from
                        wrapper
  --skip-types [SKIP_TYPES [SKIP_TYPES ...]]
                        Subroutines to exclude types from wrapper
  --force-public [FORCE_PUBLIC [FORCE_PUBLIC ...]]
                        Names which are forced to be make public
  --default-to-inout    Sets all arguments without intent to intent(inout)
  --conf-file CONF_FILE
                        Use Python configuration script to set options
  --documentation-plugin DOCUMENTATION_PLUGIN
                        Use Python script for expanding the documentation of
                        functions and subroutines. All lines of the given tree
                        object are passed to it with a reference to its
                        documentation
  --py-max-line-length PY_MAX_LINE_LENGTH
                        Maximum length of lines in python files written.
                        Default: 80
  --f90-max-line-length F90_MAX_LINE_LENGTH
                        Maximum length of lines in fortan files written.
                        Default: 120
  --type-check          Check for type/shape matching of Python argument with the wrapped Fortran subroutineAuthorJames KermodejameskermodeContributorsTamas StenczelstenczeltSteven Murraysteven-murrayGreg CorbettgregcorbettBob FischercitibobDavid VerelstdavidovitchJames OrrjamesorryveschMatthias CuntzBalthasar ReuterreuterbalDaniel VanzodanbeibeiDeveloper NotesTriggering the wheel buildWheels are built on push and pull requests tomasterusing cibuildwheel
withthis workflow.To make a release candidate create a tag with a suffix such as-rc1for the first attempt,
push to trigger the build:gitcommit-m'release v0.x.z.rc1'gittagv0.x.y.rc1
gitpush--tagsIf all goes well, the.whlfiles will show up as assets within a new GitHub
release. The installation process can now be tested locally.Release wheels to PyPIOnce everything works correctly, make a full release (i.e. create a tag named
justv0.x.ywithout the-rc1suffix). This will trigger the upload of wheels
and source distribution to PyPI.