Let's check this worked by importing the generated module and looking inside it to see what it contains:
In [1]:
import lanczos1
print(dir(lanczos1))
In [2]:
lanczos1.dfiltrq?
We'll define some basic filter paramters to test this code, note we have to pre-allocate the arrays that will store the output of dfiltrq
:
In [3]:
import numpy as np
# Filter parameters:
nwt = 115
fca = 0.1
fcb = 0.3
nsigma = 1
ihp = 2
# Output arrays:
wt = np.empty([nwt])
resp = np.empty([2 * nwt - 1])
freq = np.empty([2 * nwt - 1])
ier = 0
# Call the Fortran routine:
lanczos1.dfiltrq(fca, fcb, nsigma, ihp, wt, resp, freq, ier)
Let's plot the frequency response of the filter, to check that the code is actually working:
In [4]:
import matplotlib.pyplot as plt
plt.plot(freq, resp)
plt.show()
Using this procedure it was simple to generate the Python code from the Fortran, but the result is somewhat difficult to use. We are having to use the Fortran style of pre-allocating our output arrays and passing them into the function, and having it populate them. We are using Python, and we can do better!
We'll take a slightly different approach now and split the process up into two stages. First we'll generate an interface file using f2py:
f2py lanczos1.f -m lanczos2 -h lanczos2.pyf
This will generate a text file lanczos2.pyf
that we can review and edit before continuing to compile the module.
We can edit this file to simplify the Python module that will be generated by:
dfilwtq
which we don't wantWe can generate the Python module from the interface using the command:
f2py -c lanczos2.pyf lanczos1.f
This will generate a Python module named lanczos2
.
Let's check this worked by importing the generated module and looking inside it to see what it contains:
In [5]:
import lanczos2
print(dir(lanczos2))
In [6]:
lanczos2.dfiltrq?
Now that we have simplified the interface we can call the function in a nicer (more Pythonic) way where we pass inputs as arguments and receive outputs as the function's return value:
In [7]:
wt, resp, freq, ier = lanczos2.dfiltrq(nwt, fca, fcb, nsigma, ihp)
We can quickly check if the output is as expected by plotting the frequency response:
In [8]:
plt.plot(freq, resp)
plt.show()
The result of this method is much more pleasing to use, although it required some awkward fiddling with the interface file. Finally we'll demonstrate a method that combines the simplicity of the first, with the desirable result of the second.
We can generate an interface file from the modified source code in the same way as before. This time we'll include the extra option only: dfiltrq
to tell f2py
to only generate an interface for the procedure we want:
f2py lanczos3.f -m lanczos3 -h lanczos3.pyf \
only: dfiltrq
Note how this interface file looks the same as our hand-modified one from method 2 (lanczos2.pyf
), but we didn't have to edit it at all, the addition of 2 comments to the source code allowed the interface to be generated as we wanted.
In fact, we only generated the interface file here to demonstrate that it is correct. Now that we have declared our argument intents in the source we could have used the quick method to generate a Python module straight away:
f2py -c lanczos3.f -m lanczos3 only: dfiltrq
Finally we can verify that the generated module is as we expect:
In [9]:
import lanczos3
print(dir(lanczos3))
In [10]:
lanczos3.dfiltrq?
Plot the frequency response one last time to verify the solution is still correct:
In [11]:
wt, resp, freq, ier = lanczos3.dfiltrq(nwt, fca, fcb, nsigma, ihp)
plt.plot(freq, resp)
plt.show()