This work is done as part of LIGO Ticket 12980:
https://services.ligo-la.caltech.edu/FRS/show_bug.cgi?id=12980

My goal was to propagate a transfer function in the form of zeros poles and gain (zpk) through python, into the filterbanks generated by foton. There is a python version of foton, named foton.py, that wraps around the C++ libraries which foton is written in. This can be found on the gds SVN here:
https://redoubt.ligo-wa.caltech.edu/viewvc/gds/trunk/GUI/foton/

The end goal is to used this foton.py to import the suspension models (giant zpk arrays) directly through python.

This version doesn't support directly importing a zpk array, however Lee McCuller has done a lot of work upgrading this, and a beta foton.py can be obtained obtain from:
https://alog.ligo-la.caltech.edu/aLOG/index.php?callRep=38086

I tasked myself with testing this beta version, though getting it to run and run correctly took a lot of fiddling. This beta was written against a newer version of the ROOT library (which bridges the python code to the C++ libraries). There are a number of problems I ran into when trying to use the newer (not newest) version of ROOT on the control room computers, which I can summarise in saying that it needs to be installed and configured properly to run anything. My solution (for testing purposes) was to strip sections of code that relied on new functions of ROOT which did not exist in the version currently used on those systems. At some point I needed the libssl.1.0.x libarary to run some part of ROOT - this is not installed on the control room computers, so I downloaded the library and copied locally to a folder so ROOT can use it if it is needed.

My working beta version in question is posted here as [fotontst.py]. I did find a tiny bug in Lee's code that breaks the ZPK functionality: [line 527 in foton.py from Lee's code] should be "zero_list.append(matlab_complex_str(zero))", so that zero's get pushed to foton.

Steps for testing [all in python 2.7]:
1) [test_foton/zpk_create.py]. I wrote a short script to create a matlab-like .mat array file, that contains zeros,poles and gains of some filter. I compared against the data structured improted from the sus model arrays to make sure it is the same format. I used a 6th order elliptical filter to create a nice shap feature as the reference. This output is [testdata.mat].
2) [test_foton/zpk_foton.py] through [test_foton/run.sh]. [run.sh] imports the libssl library (from the lib folder), runs the [zpk_foton.py] script, and copies the new filters file to the directory above it. [zpk_foton.py] simply reads the .mat file, passes the data into the ZPK_set functionality of the beta version of [fotontst.py] into a specific filter block that was unsused, and writes it out. Final file is [H1CALCS_from_py.txt]
3) [H1CALCS_from_foton.txt]. I use fotons gui interface to create a filter (ellip("LowPass",6,1,40,35)) with the same parameters and save it to this file. [diff.txt] is the difference between [H1CALCS_from_py.txt] and [H1CALCS_from_foton.txt]. You can see the small numerical differences you might expect would arise from slightly different number precisions used in C++ and Python to generate the transfer functions.
4) [tf_compare/foton_tf] and [tf_compare/foton_tf]. These two files are outputs from within foton's gui. I output the transfer functions as an array of frequency, real, imaginary. This is done for the filter generated through foton [foton_tf] and filter generated through python and imported in steps (1) and (2).
5) [tf_compare/tfcompare.py]. This script compares transfer functions and spits out pretty pictures like [pyth_vs_foton.png], [pyth_vs_pyth_through_foton.png] and [pyth_through_foton_vs_foton.png]. I tested the tree combinations of comparisons for:
	a) [pyth_vs_pyth_through_foton.png] make the filter in python and compare it against the same filter after it has propagated through the foton in steps (1) and (2).
	b) [pyth_vs_foton.png] make the filter in python and compare it directly against the filter made in foton.	
	c) [pyth_through_foton_vs_foton.png] python filter after it has propagated through the foton compared against the filter made in foton.

Result discussion:
5a) [pyth_vs_pyth_through_foton.png]. This is the important one. This compares the same function propagating through foton and comparing it against that it was originally in python. As you can see there is miniscule changes in the maginitude ration on the order of 0.005%, which is probably numerical error on fotons output. This is the key plot, since the goal is to check if importing a ZPK array though foton.py and comparing that gainst what you started with should be the same. Notable also, is the phase difference at high frequencies, as this points to some difference in how TFs of ZPKs are handled between foton and python.
5b) [pyth_vs_foton.png]. Here we compare a filter directly made in python vs the output from foton. We see a similar phase error as the case above, and we see spikes in the magnitude ration arising from small numerical differences in the positions of the poles and zeros. What is relevant is the 0.05% difference in the magnitude ratio at high frequencies, but that differences (as I have been told by Jeff Kissel) is acceptable.
5c) [pyth_through_foton_vs_foton.png]. This one shows that the phase difference vanish when you are looking at data outputted from foton - indicating that the phase difference at high frequency in 5a and 5b isnt really real, and is a difference to how python vs foton calculate the phase from ZPKs at the output. The magnitude error is the same as 5b.

Conclusion:
The goal is to take a 'known good' array of ZPK data and propagate that to a filterbank. Remeber that in importing the sus model the ZPK arrays are already made. The magnitude error from 5a is relevant here as that checks reproducability. 5a sees some phase offsets that are not seen when both data sets are outputted from foton (5c), pointing to a difference there.

All in all, it looks like foton.py is importing the filters correctly with minial error, and should be fit to import data from a complete susmodel. Next step is to produce a plot similar to 5a that looks at how python plots the TF based on the ZPKs vs how foton plots the ZPKs of the huge susmodel array.
