pyafm: Fill in the chapter on my control stack
authorW. Trevor King <wking@tremily.us>
Wed, 1 May 2013 20:47:00 +0000 (16:47 -0400)
committerW. Trevor King <wking@tremily.us>
Wed, 1 May 2013 20:47:00 +0000 (16:47 -0400)
Use minted for syntax highlighting in code excerpts (yay pygments!).

14 files changed:
src/figures/binary/pulling_chan_1_2d22.png [new file with mode: 0644]
src/local_cmmds.tex
src/packages.tex
src/packaging/main.bib
src/pyafm/auxiliary.tex
src/pyafm/conclusions.tex
src/pyafm/discussion.tex
src/pyafm/frameworks.tex
src/pyafm/main.bib [new file with mode: 0644]
src/pyafm/main.tex
src/pyafm/stack.tex
src/root.bib
src/root.tex
src/sawsim/discussion.tex

diff --git a/src/figures/binary/pulling_chan_1_2d22.png b/src/figures/binary/pulling_chan_1_2d22.png
new file mode 100644 (file)
index 0000000..a3507d2
Binary files /dev/null and b/src/figures/binary/pulling_chan_1_2d22.png differ
index debdbbc556ff955069929166498d06507abc3c86..36131c3a64c6efc6a1363840d87793930a125fb4 100644 (file)
 \newcommand{\diNaHPO}{Na\textsubscript{2}HPO\textsubscript{4}}
 \newcommand{\NadiHPO}{NaH\textsubscript{2}PO\textsubscript{4}}
 
+% Workaround for inline minted markup
+%   http://code.google.com/p/minted/issues/detail?id=15
+% usage: \imint{language}|value|
+\NewDocumentCommand\imint{mv}{\texttt{#2}}
+
 % Aliases for citations
 \defcitealias{calibcant}{calibcant}
 \defcitealias{comedi}{Comedi}
+\defcitealias{cygwin}{Cygwin}
+\defcitealias{cython}{Cython}
+\defcitealias{epics}{EPICS}
 \defcitealias{gentoo}{Gentoo}
+\defcitealias{h5config}{h5config}
+\defcitealias{hdf5}{HDF5}
 \defcitealias{interix}{Interix}
 \defcitealias{king10}{sawsim}
+\defcitealias{labview}{LabVIEW}
 \defcitealias{prefix}{Gentoo Prefix}
 \defcitealias{pyafm}{pyafm}
 \defcitealias{pycomedi}{pycomedi}
+\defcitealias{pymodbus}{pymodbus}
 \defcitealias{pymol}{PyMol}
+\defcitealias{pypid}{pypid}
 \defcitealias{pypiezo}{pypiezo}
 \defcitealias{sandal09}{Hooke}
 \defcitealias{stepper}{stepper}
+\defcitealias{beazley96}{SWIG}
+\defcitealias{unfold-protein}{unfold-protein}
+\defcitealias{wavemetrics-igor}{IGOR Pro}
 \defcitealias{xcode}{Xcode}
+\defcitealias{yaml}{YAML}
 
 \newcommand{\Comedi}{\citetalias{comedi}}
 \newcommand{\Hooke}{\citetalias{sandal09}}
 \newcommand{\calibcant}{\citetalias{calibcant}}
+\newcommand{\hFconfig}{\citetalias{h5config}}
 \newcommand{\pyafm}{\citetalias{pyafm}}
+\newcommand{\pypid}{\citetalias{pypid}}
+\newcommand{\pypiezo}{\citetalias{pypiezo}}
+\newcommand{\pycomedi}{\citetalias{pycomedi}}
 \newcommand{\pysawsim}{\texttt{pysawsim}}
 \newcommand{\sawsim}{\citetalias{king10}}
 \newcommand{\stepper}{\citetalias{stepper}}
+\newcommand{\unfoldprotein}{\citetalias{unfold-protein}}
index 12df7cbb436a930023e6a78c5c8f28c6132382c0..c03f03437be25b8a43787236270c047d8561a03e 100644 (file)
@@ -11,6 +11,9 @@
 
 \bibliographystyle{unsrtnat} % Number citations in the order referenced.
 
+% use symbols for footnotes, so they aren't confused with references
+\usepackage[symbol*]{footmisc}
+
 % Nicer references with \cref, \Cref, etc.
 \usepackage[capitalize]{cleveref}
 
 \usepackage{dsfont}
 % nicer table formatting (\toprule, \cimidrule, \midrule, and \bottomrule)
 \usepackage{booktabs}
+% syntax highlighting for source code
+\usepackage{minted}
+% for \NewDocumentCommand
+\usepackage{xparse}
 
 \usepackage{xcolor}
 
 \usepackage{tikz}         % a nice, inline PGF frontend
 \usetikzlibrary{automata} % graph-theory library
 \usetikzlibrary{calc}     % coordinate-calculation library
+\usetikzlibrary{shapes.misc}  % for 'rounded rectangle'
 
 \usepackage[inline]{asymptote}    % more fancy graphics ;).
 
 \usepackage{epsdice}      % dice-face font
 
-% nicer verbatim environments (Verbatim)
-\usepackage{fancyvrb}
-
-\RecustomVerbatimEnvironment{Verbatim}{Verbatim}{%
-  frame=lines,commandchars=\\\{\}}
-
 \usepackage{wtk_cmmds}    % common personal macros, in ~/texmf/tex/latex/
 \input{local_cmmds}
index a5521b390bd8a6d8f8a18b503ad90c28bff962d0..736d67fe664da1c022fe8372a80969700afa0944 100644 (file)
   note = "Version 0.7",
 }
 
+@misc{ unfold-protein,
+  author = WKing,
+  title = {Unfold-protein},
+  year = 2013,
+}
+%  url = {http://pypi.python.org/pypi/unfold-protein/},
+%  note = "Version 0.2",
+
 @misc{ pyafm,
   author = WKing,
   title = "Pyafm",
   year = 2012,
   note = "Version 0.4",
 }
+
+@misc{ h5config,
+  author = WKing,
+  title = "H5config",
+  url = "http://pypi.python.org/pypi/h5config/",
+  year = 2013,
+  note = "Version 0.3",
+}
index 36c358552e3a88fefddcd2897d3a77c3e3b2f942..625688c905160773988603e38630135b06bc609e 100644 (file)
@@ -1,4 +1,139 @@
-\section{Auxilliary packages}
+\section{Auxiliary packages}
+\label{sec:pyafm:auxiliary}
+
+The previous section covered the core of the experiment stack
+(\cref{sec:pyafm:stack}), but skipped over some of the more peripheral
+packages.
+
 \subsection{h5config}
+\label{sec:pyafm:h5config}
+
+The \hFconfig\ package makes it easy to save and load configuration
+classes from disk.  After populating base configuration classes with
+parameters (\cref{fig:h5config}), \hFconfig\ automatically generates
+\citetalias{hdf5} and \citetalias{yaml} backends for saving and
+loading that class.
+
+\begin{figure}
+  \begin{center}
+\begin{minted}[mathescape]{python}
+import h5config.config as _config
+
+class AxisConfig (_config.Config):
+    "Configure a single piezo axis"
+    settings = [
+        _config.FloatSetting(
+            name='gain',
+            help=(
+                'Volts applied at piezo per volt output from the DAQ card '
+                '(e.g. if your DAQ output is amplified before driving the '
+                'piezo),')),
+        _config.FloatSetting(
+            name='sensitivity',
+            help='Meters of piezo deflection per volt applied to the piezo.'),
+        # $\ldots$
+        _config.ConfigSetting(
+            name='channel',
+            help='Configure the underlying DAC channel.',
+            config_class=OutputChannelConfig,
+            default=None),
+        # $\ldots$
+        ]
+\end{minted}
+    \caption{Portions of the configuration class for a single piezo
+      axis (from \pypiezo, \cref{sec:pyafm:pypiezo}).  The more
+      generic analog output channel configuration is nested under the
+      \imint{python}|channel| setting.\label{fig:h5config}}
+  \end{center}
+\end{figure}
+
+Basic configuration types include booleans, integers, floating point
+numbers, enumerated choices, and freeform text.  There is also support
+for lists of these basic types (e.g.~lists of integers).  The killer
+feature is nesting configuration classes.  This means that your higher
+level tools can have their own configuration settings and also include
+the configuration settings for their lower level components.  For
+example, the piezo axis configuration given in \cref{fig:h5config}
+contains configuration settings specific to piezo axes, and it also
+contains a reference to the configuration settings for a generic
+analog output channel.  The piezo axis code doesn't need to know what
+the analog output channel configuration settings are, those are
+defined somewhere else.
+
+The nesting continues all the way up the stack, to the
+\unfoldprotein\ configuration.  This means that a single file
+(\imint{console}|~/.config/unfold_protein.yaml|) contains every
+configurable setting required for the whole experiment in an
+easy-to-edit text format.  Adding additional configuration settings at
+any level of the experiment stack is just a matter of adjusting a
+single \imint{python}|h5config.config.Config| subclass the
+corresponding entry in the configuration file.  There is no need to
+adjust the higher level code, the new setting is passed down the stack
+to its point of use automatically.
+
+Besides making it easy to configure your experiment, \hFconfig\ also
+makes it easy to save the configuration alongside your data.  The
+section of \unfoldprotein\ that writes the whole configuration stack
+into the per-pull HDF5 file is only four lines long.  This makes
+post-processing much easier, because almost every setting needed to
+analyze the data is already stored in the data file (the only missing
+values are those that you did not need during the experiment control
+phase).
+
 \subsection{stepper}
+\label{sec:pyafm:stepper}
+
+The \stepper\ package provides Python control of stepper
+motors\cite{jones95}.  The package is mostly concerned with the
+maintenance of internal motor state:
+
+\begin{description}
+  \item[position] is a half-step counter that records the current
+    motor position.
+  \item[full step] selects full or half stepping.
+  \item[logic] selects active high or active low operation.
+  \item[delay] sets the time delay between steps in seconds, in case
+    the motor response is slower than the digital output driver.
+  \item[step size] approximates step size in meters.
+  \item[backlash] estimates the drive chain backlash in half-steps.
+\end{description}
+
+Actualizing the motor control signal is left up to the caller, in this
+case \pyafm.
+
+TODO: backlash and step-size graphics.
+
 \subsection{pypid}
+\label{sec:pyafm:pypid}
+
+The final component of the experiment control stack is \pypid, which
+uses \citetalias{pymodbus} to communicate with a Melcor Series MTCA
+Thermoelectric Cooler Controller\citep{melcor} over a serial line.
+The controller monitors the fluid cell temperature with a
+thermocouple, and reading temperatures from the controller is fairly
+straightforward (\cref{fig:unfold-protein:unfolder}).  Temperature
+control is via a peltier mounted underneath the sample surface.
+
+The controller tries to keep the measured temperature at the setpoint
+temperature via a modified proportional-integral-derivative (PID)
+feedback algorithm.  PID systems have been around for a
+while\citep{ziegler42}, but finding appropriate feedback terms for
+sensitive systems is not trivial.  There are a number of tuning
+procedures which characterize the system by evaluating its response
+under simpler driving conditions.  The \pypid\ package implements
+Ziegler--Nichols' step response\citep{ziegler42}, bang-bang
+response\citep{TODO}, ultimate cycle response\citep{ziegler42} tuning
+rules, as well as Cohen--Coon's\citep{cohen53} and
+Wang--Juang--Chan's\citep{wang95} step response tuning
+rules\citep{astrom93}.
+
+\nomenclature{PID}{Proportional-integral-derivative feedback.  For a
+  process value $p$, setpoint $p_0$, and manipulated variable $m$, the
+  standard PID algorithm is
+  \begin{align}
+    m(t) &= K_p e(t) + K_i \integral{0}{t}{\tau}{e(\tau)}
+            + K_d \deriv{t}{e(t)} \\
+    e(t) &= p_0 - p \;,
+  \end{align}
+  where $e$ is the error function, $K_p$ is the proportional gain,
+  $K_i$ is the integral gain, and $K_d$ is the derivative gain.}
index ec0bd4d6ba71a47566cb5114232d90f55d218c4a..803450db03764e3c6e9b4c85c257e975d959c8b8 100644 (file)
@@ -1 +1,38 @@
 \section{Conclusions}
+\label{sec:pyafm:conclusions}
+
+Developing an open software stack for controlling single molecule
+force spectroscopy is hard work, especially for scientists who lack
+experience designing or managing moderately large software projects.
+Coming into this project, I already had several years of experience
+working with LabVIEW, but I had very little experience in other
+languages and no formal training in project maintenance.  I spent the
+first two years of my research project floundering about until I
+aquired enough experience to start making progress on a sustainable
+stack\footnote{%
+  Since last summer I've been helping the
+  \href{http://software-carpentry.org/}{Software Carpentry}
+  project\citep{wilson06b} reach out to scientists (mostly graduate
+  students) to provide boot camp introductions to software development
+  and version control.  It's a chance to tell other folks what I wish
+  I'd been told when I was starting out.
+}, and I've spent the remaining time tuning this stack (and the
+analysis software) while running experiments.
+
+A FLOSS stack allows collaborative development so that this
+development cost can be shared between labs, as well as lowering the
+barrier to entry for new labs entering the field.  Besides benefiting
+SMFS groups, lower-level packages in the stack will be useful to a
+wider audience (who can share the maintenance cost).  My existing
+stack and future distributed maintenance will allow researchers to
+focus on generating new science, instead of generating new software.
+
+Besides development efficiencies, a common stack could provide a
+benchmark for comparative analysis between experiments carried out by
+different labs.  With every lab using in-house software and in-house
+hardware, it's hard to judge the reliability or accuracy of the lab's
+published research.  A common stack should include methods like those
+used in \cref{sec:pyafm:discussion} to characterize and validate your
+apparatus.  A common stack also provides a common file format for
+experimental data, which makes it easier to share data and analysis
+tools.
index 62f54a319e2a8e27d62030ec40a0b74f242e1a02..0dde6f6b4ac17a63f344e4df4a37c4d1e5d8f34b 100644 (file)
@@ -1 +1,122 @@
 \section{Discussion}
+\label{sec:pyafm:discussion}
+
+With the radical shift from LabVIEW and Microsoft Windows over to
+Comedi and Linux, it is a good idea to compare my new experiment
+control software with the earlier stack.  Because the fundamental
+procedure in my experiments is the velocity-clamp pull
+(\cref{sec:procedure}), I used both approaches in quick succession to
+collect pulls.  Because the stacks diverge after the PCI DAQ card, I
+was able to collect several pulls using my setup, power down the Linux
+computer, swap the PCI card into the Windows computer, power up, and
+collect several pulls using the Windows stack on top of the exact same
+hardware.
+
+\begin{figure}
+  \begin{center}
+    \subfloat[][]{\label{fig:pyafm:labview-comparison:many}
+      \includegraphics[width=0.9\textwidth]{%
+        figures/labview-comparison/full}}
+    \caption{\protect\subref{fig:pyafm:labview-comparison:many}Several
+      velocity clamp pulls using both the LabVIEW/Windows stack (blue)
+      and the Comedi/Linux stack (red).  The contact voltage and
+      pulling distance were not synchronized between the two
+      experiments, and the raw data has been shifted to locate the
+      contact point at the origin.  One LabVIEW/Windows curve has a
+      flat deflection in the high-contact region, where the laser was
+      deflected beyond the photodiode's working range.  This is
+      probably due to a high approach setpoint, followed by surface
+      drift during the binding phase, but is not relevant to the
+      stack comparison.\label{fig:pyafm:labview-comparison}}
+  \end{center}
+\end{figure}
+
+\begin{figure}
+  \ContinuedFloat
+  \begin{center}
+    \subfloat[][]{\label{fig:pyafm:labview-comparison:single:contact}
+      \includegraphics[width=0.9\textwidth]{%
+        figures/labview-comparison/single-contact}} \\
+    \caption{\protect\subref{fig:pyafm:labview-comparison:single:contact}The
+      contact region from a single pull from
+      \protect\subref{fig:pyafm:labview-comparison:many}.  The
+      LabVIEW/Windows stack takes $0.5\U{nm}$ piezo steps with ten
+      deflection reads at each step.  The Comedi/Linux stack makes a
+      single read per step, but can as many small steps as possible
+      within DAQ card's memory buffer, frequency, and precision
+      limitations.  For $1\U{$\mu$m/s}$ pulls, a stepping/sampling
+      frequency of $50\U{kHz}$ generated steps that were less than one
+      DAC bit wide.}
+  \end{center}
+\end{figure}
+
+\begin{figure}
+  \ContinuedFloat
+  \begin{center}
+    \subfloat[][]{\label{fig:pyafm:labview-comparison:single:non-contact}
+      \includegraphics[width=0.9\textwidth]{%
+        figures/labview-comparison/single-non-contact}}
+    \caption{\protect\subref{fig:pyafm:labview-comparison:single:non-contact}The
+      non-contact region from a single pull from
+      \protect\subref{fig:pyafm:labview-comparison:many}.  The signal
+      oscillates because the AFM is sitting directly on the lab bench,
+      our usual isolation mechanisms being unavailable at the time.
+      All protein unfolding experiments were carried out with
+      isolation, so the vibration was not a problem in those cases.}
+  \end{center}
+\end{figure}
+
+Because the goal of these experiments was to compare the two software
+stacks, the comparison was carried out using our standard AFM
+cantilevers and gold surface, but distilled water was used instead of
+PBS and no protein was bound to the surface.  This gives a simpler
+system with fewer distracting features.  As shown in
+\cref{fig:pyafm:labview-comparison,fig:pyafm:labview-comparison:stats},
+large-scale features are identical, with similar contact slopes and
+non-contact noise.
+
+\begin{figure}
+  \begin{center}
+    \subfloat[][]{\label{fig:pyafm:labview-comparison:contact-slope}
+      \includegraphics[width=0.5\textwidth]{%
+        figures/labview-comparison/contact-slope}}
+    \subfloat[][]{\label{fig:pyafm:labview-comparison:non-contact-noise}
+      \includegraphics[width=0.9\textwidth]{%
+        figures/labview-comparison/non-contact-noise}} \\
+    \caption{\protect\subref{fig:pyafm:labview-comparison:contact-slope}Contact
+      slope for the pull in \cref{fig:pyafm:labview-comparison}.  The
+      low-slope outlier is from the pull with out-of-range
+      deflection.
+      \protect\subref{fig:pyafm:labview-comparison:non-contact-noise}Power
+      spectral densities (PSDs) of the non-contact noise for the pulls
+      from \ref{fig:pyafm:labview-comparison:many}.  To produce this
+      image, the PSD of the non-contact data extracted from
+      \ref{fig:pyafm:labview-comparison:many} was averaged for each
+      software stack.  The number of points in the non-contact region
+      truncated to the nearest power of two (for efficient fast
+      Fourier transformation), which has the convenient side effect of
+      aligning the frequency axis for easy cross-pull
+      averaging.\label{fig:pyafm:labview-comparison:stats}}
+  \end{center}
+\end{figure}
+
+Although grossly similar, the two stacks do have some statistically
+significant differences.  The slope of the contact region for the
+LabVIEW/Windows stack (excluding the out-of-deflection-range outlier)
+is $6.59\pm0.13$, while the Comedi/Linux stack slope is $6.17\pm0.03$
+(both in deflection bits per $z$-piezo bit,
+\cref{fig:pyafm:labview-comparison:contact-slope}).  While small, the
+7\% difference is significant, both statistically ($3\sigma$ for the
+LabVIEW/Windows standard deviation) and practically, because contact
+slope plays a key role in cantilever calibration
+(\cref{sec:calibcant:bump}).
+
+Due to the table vibration, comparisons of non-contact noise between
+the two stacks are less conclusive.  However, rough comparisons of the
+noise spectra show that noise in the Comedi/Linux data is generally a
+factor of two two three less than noise in the LabVIEW/Windows data
+across a range of frequencies
+(\cref{fig:fig:pyafm:labview-comparison:non-contact-noise}).  While
+the noise difference should be taken with a grain of salt, it does
+highlight the importance (and difficulty) of characterizing your
+apparatus and controlling software.
index 9050eeb308d40b6cd5f6f0f29db754301836f611..1f102f37e5f2c8609b1839b5f84c642221af1afc 100644 (file)
@@ -1,3 +1,182 @@
 \section{Analog input output frameworks}
+\label{sec:aio-frameworks}
+
+For many users, computers are fairly self-contained systems.  Users
+read and write files, using a variety of editors, and share
+information between computers via networked connections.  Using
+computers to control and monitor arbitrary physical processes is
+common in the scientific community and industry, but less so in the
+the general consumer market.  This means that interfaces between the
+digital and analog worlds haven't seen the focused development in the
+FLOSS community that more mainstream problem areas have received.  In
+this section I'll discuss a few possible options---both open and
+proprietary---in the context of my experiment control stack.
+
 \subsection{LabVIEW}
+\label{sec:labview}
+
+National Instruments\citep{national-instruments} is a major player in
+the experiment control and data aquisition market.  On the hardware
+side, they produce a wide range of DAQ cards.  On the software side,
+they produce LabVIEW\citep{labview}, a graphical programming language
+designed to make writing control and aquisition experiments
+straightforward.  Both LabVIEW and NI-DAQ cards are ubiquitous in
+scientific computing; in the four research labs I've worked in over my
+career, every lab has used both.  By the time I joined Prof.~Yang's
+lab, I'd been using LabVIEW for years, and had become familiar with
+its two major limitations: name based linking and a binary file
+format.
+
+\nomenclature{DAQ}{Data acquisition.  Although the term only refers to
+  input, it is sometimes implicitly extended to include signal output
+  as well (for controlling experiments as well as measuring results).}
+
+Programming in a graphical language is quite similar to programming in
+a textual language.  In both, you reduce complexity by encapsulating
+functional subroutines of your process, and then assembling those
+subroutines in other, higher-level
+subroutines\citep{dijkstra70,wirth74,shneiderman79,hughes89}.  This
+means that the application level code can focus on application-level
+task (approach the surface, wait for binding, \ldots) without getting
+bogged down in the details (increment analog output channel zero in 5
+bit steps until analog input channel exceeds 39322 bits).  In textual
+languages like C or Python, you can use functions and libraries to
+package the functional subroutines.  In LabVIEW, you package the
+subroutines in \emph{virtual instruments} (VIs).
+
+\nomenclature{VI}{Virtual instrument.  LabVIEW's analog to functions
+  for encapsulating subroutines.}
+
+The problem comes when you want to update one of your subroutines.
+LabVIEW VIs are linked dynamically by VI name\citep{ni-vi-management},
+so there was no easy way to swap a new version of the VI into your
+application for testing without renaming the subroutine.  With the
+Project Explorer (new in LabVIEW 8.0\citep{ni-vi-management}, released
+2005), these renames became easier.  However, throughout my time in
+the Yang lab, the Windows machines all ran LabVIEW 7.1 (released in
+2004).
+
+Because of difficulties with name-based VI linking and the relative
+inexperience of many scientists in the maintenance benefits of modular
+programming\citep{hilburn93,wilson06b}, LabVIEW code often ends up
+without a clean separation between high-level and low-level tasks
+(\cref{fig:labview}).  This lack of structure makes it difficult to
+reuse existing code to address similar tasks.
+
+\begin{figure}
+  \begin{center}
+    \includegraphics[width=0.8\textwidth]{%
+      figures/binary/pulling_chan_1_2d22.png}
+    \caption{An excerpt from the main frame of the LabVIEW stack.
+      This frame codes for the velocity-clamped pull phase of a
+      push--bind--pull experiment.\label{fig:labview}}
+  \end{center}
+\end{figure}
+
+The second obstacle to maintaining LabVIEW code is the binary file
+format for VIs.  The established method for recording software history
+is to use a version control system (VCS), which recording versions of
+the project in a repository.  Each change to the project is committed
+to the repository with some associated metadata (timestamp, committer
+name, explanatory message, \ldots).  Users can access this database to
+recover earlier versions of the project.  For example, if you find a
+bug in your package, you can use your VCS to determine if that bug
+affected the data you gathered six months ago.
+
+There are a number of FLOSS version control systems in common use
+(Git, Mercurial, and Subversion, \dots), but in order to track and
+merge \emph{changes}, they need a way to calculate the difference
+between two versions of a given file.  For textual programming
+languages, the line-based textual differences used by VCSs work
+extremely well, but for binary file formats, performance decreases
+drastically.  There are third-party merge tools\citep{ni-merge} for
+LabVIEW, but the tools are not officially supported.
+
+\nomenclature{VCS}{Version control system.  A system for tracking
+  project development by recording versions of the project in a
+  repository.}
+\nomenclature{FLOSS}{Free, Libre, and Open Source (software).  A
+  catch-all for copyleft licensing.}
+
+While National Instruments seems to put a reasonable amount of effort
+into maintaining backwards compatibility, long term archival of binary
+formats is still a difficult problem.  For example, our legacy LabVIEW
+7.1 installation is no longer compatible with recent LabVIEW releases.
+Support for the releases is so low, that without access to the old
+LabVIEW release, you may not even be able to determine which version
+of LabVIEW your VI corresponds to.  One officially suggested method
+for extracting the version from an older VI is\citep{ni-vi-version}:
+
+\begin{quote}
+  Open the VI in the earliest version on your computer.  If an error
+  occurs, the VI is saved in a later version.  Close the VI and repeat
+  this process for the next version of LabVIEW.  The first version
+  that opens a VI without any error is the version in which the VI is
+  compiled.
+\end{quote}
+
+This does not inspire confidence in an ability to extract experiment
+control software from VIs after a decade of archival.
+
+\subsection{NI-DAQmx}
+\label{sec:ni-daqmx}
+
+After deciding to avoid LabVIEW, my first attempt at writing an
+experiment control framework involved calling National Instrument's
+DAQmx library from C\citep{ni-daqmx} (\cref{fig:ni-daqmx}).  I spent
+most of 2007 working this framework, using \citetalias{cygwin} as the
+development environment.  Inspired by \citetalias{epics}, I built a
+message passing server with experiment control and hardware interface
+modules connected via sockets.
+
+As the experiment server evolved, I started running into problems.
+The overhead of sending all the data through sockets to generic
+hardware interface modules was larger than I had na\"ively expected.
+I also had trouble with multithreaded socket code on Cygwin, and
+decided to scrap Microsoft Windows altogether in favor of a FLOSS
+operating system.
+
+\begin{figure}
+  \begin{center}
+\begin{minted}{c}
+static int set_digital_output_data(DIGITAL_OUTPUT *d, unsigned int data)
+{
+  d->data = (uInt32) data;
+  DAQmxErrChk_struct( Write_WriteDigPort(d->taskHandle, d->data) );
+ Error:
+  if (d->error != 0) {
+    CHK( close_digital_output(d) );
+    M_EXIT(FAILURE, "Error in NIDAQ stepper output\n");
+  }
+  CHK( nsleep(100) );
+  PING(1);
+  return SUCCESS;
+}
+\end{minted}
+    \caption{An excerpt from the digital output module of my
+      experiment server stack.  Most of the C code is error checking
+      and tracing macros.  The hardcoded delay time and
+      stepper-specific error message are symptoms of my previously
+      poor programming practices.  \imint{c}|Write_WriteDigPort| is a
+      simplifying wrapper around \imint{c}|DAQmxWriteDigitalU32| from
+      the examples bundled with NI-DAQmx.\label{fig:ni-daqmx}}
+  \end{center}
+\end{figure}
+
 \subsection{Comedi}
+\label{sec:comedi}
+
+After transitioning to Linux-based systems, I could no longer use
+NI-DAQmx (which only supported Microsoft Windows).  Luckily, the
+\citetalias{comedi} project already provided FLOSS driver code for our
+DAQ card (an NI-PCI-6052E).  Comedi (from ``Control and Measurement
+Device Interface'') is general purpose library for interacting with
+DAQ devices, and supports a wide range of hardware.  When I moved to
+Comedi, it was a stand-alone kernel module, but since November 2008 it
+has been included in the Linux source as a staging driver.
+
+Comedi development goes back to 2000, so by the time I arrived things
+were already pretty stable.  I submitted
+\href{http://comedi.org/git?p=comedi/comedi.git;a=commit;h=4284c2266987ad08a26f2758cd09fef06d1ce3cf}{a
+  small patch} to support simultaneous analog input/output triggering
+on National Instruments cards, and started building my stack.
diff --git a/src/pyafm/main.bib b/src/pyafm/main.bib
new file mode 100644 (file)
index 0000000..8312c77
--- /dev/null
@@ -0,0 +1,162 @@
+@string{DBeazley = "Beazley, David M."}
+@string{DWJones = "Jones, Douglas W."}
+@string{HDFG = "The HDF Group"}
+@string{EKerry = "Kerry, Elijah"}
+@string{NI = "National Instruments"}
+@string{USENIX = "USENIX Association"}
+@string{WM = "WaveMetrics"}
+
+@misc{ wavemetrics-igor,
+  author = WM,
+  title = {{IGOR Pro}},
+  url = {http://www.wavemetrics.com/products/igorpro/igorpro.htm},
+}
+
+@misc{ labview,
+  author = NI,
+  title = {{LabVIEW}},
+  url = {http://www.ni.com/labview/},
+}
+
+@misc{ national-instruments,
+  title = {{National Instruments}},
+  url = {https://www.ni.com/},
+}
+
+@article{ ni-vi-management,
+  author = NI,
+  title = {Best Practices for Managing {NI} {LabVIEW} Applications Using
+    the {Project Explorer}},
+  year = 2013,
+  month = jan,
+  day = 28,
+  journal = {Software Engineering with LabVIEW},
+  url = {http://www.ni.com/white-paper/7197/en},
+}
+
+@misc{ ni-merge,
+  author = EKerry,
+  title = {Source Code Control: Using {TortoiseSVN} ({Subversion}) with
+    {LabVIEW} for Diff and Merge Operations},
+  year = 2012,
+  month = dec,
+  day = 6,
+  url = {https://decibel.ni.com/content/docs/DOC-2936},
+}
+
+@misc{ ni-vi-version,
+  author = NI,
+  title = {How Can {I} Determine the {LabVIEW} Version that was Used
+    to Save a {VI}?},
+  year = 2012,
+  month = apr,
+  day = 9,
+  url = {http://digital.ni.com/public.nsf/allkb/0C72D335AA87DD6486256FC40069C17F},
+  note = {Document ID: 3JDC8IZH},
+}
+
+@misc{ ni-daqmx,
+  author = NI,
+  title = {Using {NI-DAQmx} in {LabWindows/CVI}},
+  year = 2007,
+  month = mar,
+  date = 14,
+  url = {http://www.ni.com/white-paper/2931/en},
+}
+
+@misc{ cygwin,
+  title = {Cygwin},
+  url = {http://www.cygwin.com/},
+}
+
+@misc{ epics,
+  title = {{EPICS}: Experimental Physics and Industrial Control System},
+  url = {http://www.aps.anl.gov/epics/},
+}
+
+@inproceedings{ beazley96,
+  author = DBeazley,
+  title = {{SWIG}: An easy to use tool for integrating scripting
+    languages with {C} and {C++}},
+  booktitle = {Proceedings of the 4th conference on USENIX Tcl/Tk Workshop},
+  series = {Tcl/Tk 1996},
+  volume = 4,
+  location = {Monterey, California},
+  year = 1996,
+  pages = {15--15},
+  numpages = 1,
+  url = {http://www.swig.org/},
+  eprint = {http://www.swig.org/papers/Tcl96/tcl96.html},
+  paper_url = {http://dl.acm.org/citation.cfm?id=1267498.1267513},
+  publisher = USENIX,
+  address = {Berkeley, CA, USA},
+}
+
+@misc{ cython,
+  title = {Cython: C-Extensions for {Python}},
+  url = {http://www.cython.org/},
+}
+
+@misc{ scipy-leastsq,
+  title = {\texttt{scipy.optimize.leastsq}},
+  url = {http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.leastsq.html},
+}
+
+@misc{ minpack,
+  title = {{MINPACK}},
+  url = {http://www.netlib.org/minpack/},
+}
+
+@misc{ hdf5,
+  author = HDFG,
+  title = {Hierarchical data format version 5},
+  year = 2013,
+  url = {http://www.hdfgroup.org/HDF5/},
+  note = {Version 1.8.10},
+}
+
+@misc{ yaml,
+  title = {{YAML} Ain't Markup Language ({YAML\texttrademark})
+    Version 1.2},
+  year = 2009,
+  month = oct,
+  day = 1,
+  edition = 3,
+  url = {http://www.yaml.org/},
+  eprint = {http://www.yaml.org/spec/1.2/spec.html},
+}
+
+@misc{ jones95,
+  author = DWJones,
+  title = {Control of Stepping Motors},
+  year = 1995,
+  url = {http://homepage.cs.uiowa.edu/~jones/step/},
+  note = {This material expands on material originally posted to the
+    rec.railroad newsgroup in 1990. Significant parts of this material
+    have been republished as sections 5.2.10, 10.8, 10.9 and 10.10 of
+    the Handbook of Small Electric Motors edited by W. H. Yeadon and
+    A. W. Yeadon, McGraw-Hill, 2001, and as Applications Note 907
+    published by Microchip Inc in 2004.},
+}
+
+@misc{ pymodbus,
+  title = {Pymodbus},
+  url = {https://github.com/bashwork/pymodbus},
+  note = {Version TODO},
+}
+
+@misc{ melcor,
+  title = {Melcor},
+  note = {Companies don't stay in business forever, but lab equipment
+    does.  Our controller is still going strong (since 1999), but
+    Melcor has moved around.  According to their
+    \href{http://www.lairdtech.com/NewsItem.aspx?id=953}{2005
+    announcement} the Laird Group PLC purchased Melcor from Fedders
+    Corporation, and by 2009 (according to the
+    \href{http://web.archive.org/web/20090204201524/http://melcor.com/}{Internet
+    Archive Wayback Machine}) they phased out the old website at
+    \href{http://melcor.com/}{melcor.com} in favor of
+    \href{http://lairdtech.thomasnet.com/category/thermal-management-solutions/}{their
+    own thermal site}.  It looks like there is no longer support for
+    the older MTCA controllers.},
+}
index 18e987e10c72b46d05606bb1547b7cfef0105709..fd70d73f247a7c27f5ffbaa4ce4744f65c786702 100644 (file)
@@ -1,6 +1,24 @@
-\chapter{Experiment control software, \pyafm\ and related packages}
+\chapter{Experiment control software, \pyafm, and related packages}
 \label{sec:pyafm}
 
+Velocity clamp experiments have been carried out since the initial
+work by \citet{rief97a}, so I was somewhat surprised that there
+weren't already community-driven packages for carrying out and
+analyzing these
+experiments\citep{claerbout92,buckheit95,schwab00,vandewalle09}.  When
+I joined Prof.~Yang's lab, we were using experiment control software
+written in \citetalias{labview} and analysis software written in
+\citetalias{wavemetrics-igor}, both developed in-house.  The existing
+software was not designed to control sample temperature or for easy
+extension, so I proceeded to write my own control and analysis stack
+to add this capabilities.  In this chapter, I will discuss the earlier
+frameworks and some abortive attempts that lead me towards my current
+architecture (\cref{sec:aio-frameworks,sec:pyafm:stack}).  I will also
+discuss some auxiliary packages I developed to support the main stack
+(\cref{sec:pyafm:auxiliary}).  I'll wrap up by comparing my stack with
+Prof.~Yang's earlier framework and summarizing lessons I've learned
+along the way (\cref{sec:pyafm:discussion,sec:pyafm:conclusions}).
+
 \input{pyafm/frameworks}
 \input{pyafm/stack}
 \input{pyafm/auxiliary}
index 79da3499fff648f8e174a5ae734992e155f4f7aa..42954224535b6d93c5003cd3c81e2e31ad8d4b72 100644 (file)
@@ -1,4 +1,357 @@
 \section{The pyafm stack}
+\label{sec:pyafm:stack}
+
+In order to reduce future maintenance costs, I have based my stack as
+much as possible on existing FLOSS software, and split my stack into
+reusable components where such components might appeal to a wider
+audience.  From the bottom up, \pycomedi\ wraps the Comedi device
+driver for generic input/output, \pypiezo\ builds generic
+piezo-control logic on top of \pycomedi, \pyafm\ combines a
+\pypiezo-controlled piezo with a \stepper-controlled stepper motor and
+\pypid-controlled temperature controller, and \unfoldprotein\ adds
+experiment logic to \pyafm\ to carry out velocity-clamp force
+spectroscopy (\cref{fig:pyafm:stack}).
+
+\begin{figure}
+  \begin{tikzpicture}
+    \tikzstyle{every node}=[text depth=0pt, rounded rectangle,
+      draw=blue!50, very thick, minimum height=1.7em]
+   \node (pycomedi) at (0,0) {\pycomedi};
+    \node (pypiezo) at ($(pycomedi) + (0,1)$) {\pypiezo};
+    \node (pyafm) at ($(pypiezo) + (0,1)$) {\pyafm};
+    \node (unfold-protein) at ($(pyafm) + (0,1)$) {\unfoldprotein};
+    \node (stepper) at ($(pycomedi) + (2,1)$) {\stepper};
+    \node (pypid) at ($(stepper) + (2,0)$) {\pypid};
+    \node (h5config) at ($(pycomedi) + (-3,0)$) {\hFconfig};
+    \node (calibcant) at ($(unfold-protein) + (-3,0)$) {\calibcant};
+    \draw (pycomedi) -- (pypiezo);
+    \draw (pycomedi) -- (stepper);
+    \draw (pypiezo) -- (pyafm);
+    \draw (stepper) -- (pyafm);
+    \draw (pypid) -- (pyafm);
+    \draw (pyafm) -- (unfold-protein);
+    \draw (pyafm) -- (calibcant);
+    \draw (h5config) -- (pypiezo);
+    \draw (h5config) -- (pyafm);
+    \draw (h5config) -- (unfold-protein);
+    \draw (h5config) -- (calibcant);
+  \end{tikzpicture}
+  \caption{Dependency graph for my modular experiment control
+    stack.\label{fig:pyafm:stack}}
+\end{figure}
+
 \subsection{Pycomedi}
+\label{sec:pyafm:pycomedi}
+
+After my experience with C (\cref{sec:ni-daqmx}), I knew I wanted a
+higher level language for the bulk of my experiments.
+\citetalias{comedi} already had \citetalias{beazley96}-generated
+Python bindings, so I set to work creating \pycomedi, an
+object-oriented interface around the SWIG bindings.  The first
+generation \pycomedi\ interface was much easier to use than the raw
+SWIG bindings, especially for simultaneous analog input/output, which
+I needed to monitor cantilever deflection during piezo-sweeping
+velocity-clamp pulls.
+
+The SWIG-based interface to Comedi provided a solid base for my
+experiment control stack, but as the stack matured, I started bumping
+up against problems due to both my poor design
+choices\footnote{\citet{brooks95} says ``plan to throw one away,''
+  although I'm a more optimistic about the feasibility of long-term
+  maintenance than he is.} and general awkwardness with the thin SWIG
+bindings.  In 2011 I ripped out most of this layer and used
+\citetalias{cython} to bind directly to Comedi's userspace library.
+This lead to a much more Pythonic interface, and removed a number of
+previously sticky workarounds required by earlier versions of
+\pycomedi.
+
+As a generic Python interface to Comedi, \pycomedi\ has a wider user
+base than the rest of my experiment control stack (there are more
+folks writing Python code for DAQ cards on Linux than there are
+writing velocity-clamp AFM controllers on Linux).  I've had a number
+of people contact me directly with \pycomedi\ questions, including a
+neuroscientist, a radiologist, and an automotive electrician.
+\href{http://pieleric.free.fr/}{\'Eric Piel} even contributed a few
+patches for software-calibrated devices.
+
+Comparing the NI-DAQmx implementation of digital writes
+(\cref{fig:ni-daqmx}) with a more complete \pycomedi\ implementation
+(\cref{fig:pycomedi}), the \pycomedi\ implementation reads much more
+naturally.  The main difference is that Python's object-oriented
+structure allows us to bundle complex Comedi subdevice handling into a
+series of intuitive methods.  We also benefit from Python's exception
+handling.  While C requires you to actively check for exceptions where
+they might occur (``hey, this write failed''), Python exceptions
+bubble up the call stack so you can deal with them at a more
+appropriate level (``hey, the stepper motor failed'').  This allows us
+to centralize error handling in higher level code, making the low
+level code much cleaner.
+
+\begin{figure}
+  \begin{center}
+\begin{minted}{python}
+from pycomedi.device import Device
+from pycomedi.channel import DigitalChannel
+from pycomedi.constant import SUBDEVICE_TYPE, IO_DIRECTION
+
+device = Device('/dev/comedi0')
+device.open()
+
+subdevice = device.find_subdevice_by_type(SUBDEVICE_TYPE.dio)
+channels = [subdevice.channel(i, factory=DigitalChannel)
+            for i in (0, 1, 2, 3)]
+for chan in channels:
+    chan.dio_config(IO_DIRECTION.output)
+
+def write(value):
+    subdevice.dio_bitfield(bits=value, write_mask=2**4-1)
+\end{minted}
+    \caption{A four-channel digital output example in \pycomedi\ (from
+      the \stepper\ doctest).  Compare this with the much more verbose
+      \cref{fig:ni-daqmx}, which is analogous to the
+      \texttt{subdevice.dio\_bitfield()} call.\label{fig:pycomedi}}
+  \end{center}
+\end{figure}
+
 \subsection{Pypiezo}
+\label{sec:pyafm:pypiezo}
+
+The piezo controlling code builds on the framework established by
+\pycomedi\ to define an interface for controlling the peizo-mounted
+surface (\cref{fig:piezo-schematic}).  This involves code to sweep the
+piezo in a hardware-timed ramp as well as code for discrete jumps.  To
+carry out these tasks, \pypiezo also contains code to convert piezo
+motion (in meters) to DAC output voltages (in bits), an
+\hFconfig-based framework for automatically configuring
+\pycomedi\ channels and piezo axes, and surface detection logic.
+
+Because of the tight coupling needed between piezo motion and
+cantilever deflection detection for synchronized ramps, the basic
+\texttt{Piezo} class can be configured with generic \pycomedi\ input
+channels.  In practice, only the cantilever deflection is monitored,
+but if other \pypiezo\ users want to measure other analog inputs, the
+functionality is already built in.
+
+\nomenclature{DAC}{Digital to analog converter.  A device that
+  converts a digital signal into an analog signal.  The inverse of an
+  ADC}
+\nomenclature{ADC}{Analog to digital converter.  A device that
+  digitizes an analog signal.  The inverse of a DAC.}
+
+The surface detection logic is somewhat heuristic, although it has
+proven quite robust in practice.  Given a particular piezo axis,
+target deflection, number of steps, and an allowed piezo range, the
+procedure is:
+
+\begin{enumerate}
+  \item \label{item:pypiezo-surface-retract-1} Ramp the piezo from its
+    current position away to its maximum separation $z_\text{max}$.
+  \item \label{item:pypiezo-surface-step-approach} Step the piezo in
+    towards its minimum separation, checking the deflection after each
+    step to see if the target deflection threshold has been crossed.
+    This is the high-contact piezo position $z_\text{min}$.
+  \item \label{item:pypiezo-surface-retract-2} Ramp the piezo away to
+    its maximum separation $z_\text{max}$.  Because of protein on the
+    surface, the detachment region between the contact region and
+    non-contact region may have additional forces
+    (\cref{fig:expt-sawtooth}).  This can make the determination of
+    the contact kink difficult.  The full retraction breaks any
+    protein-based contacts between the cantilever and the surface.
+  \item \label{item:pypiezo-surface-ramp-approach} Ramp the piezo in
+    to the high-contact position $z_\text{min}$.  Because any
+    protein-based contacts were broken in the previous step, the
+    contact kink at $z_\text{kink}$ should be clear and crisp.
+  \item \label{item:pypiezo-surface-reset} Ramp the piezo back to the
+    original position.
+\end{enumerate}
+
+The deflection data $d(z)$ from
+\ref{item:pypiezo-surface-ramp-approach}, which should clearly show
+the contact kink, is fit to a bilinear model (a linear non-contact
+region and a linear contact region, which meet at the the contact
+kink).  The fitting is carried out my minimizing the residual
+difference between the approach data and bilinear model with SciPy's
+\imint{python}|leastsq| optimizer, a wrapper around MINPACK's
+\imint{fortran}|lmdif| and \imint{fortran}|lmder|
+algorithms\citep{scipy-leastsq,minpack}.
+
+\begin{align}
+  d(z) = \begin{cases}
+      d_\text{kink} + \sigma_{p,\text{c}} (z - z_\text{kink})
+        &  z \le z_\text{kink} \\
+      d_\text{kink} + \sigma_{p,\text{nc}} (z - z_\text{kink})
+        &  z \ge z_\text{kink}
+    \end{cases}
+\end{align}
+
+Initial parameters for the fit are:
+
+\begin{align}
+  d_\text{kink} &= d(z_\text{max}) \\
+  z_\text{kink} &= \frac{z_\text{max} - z_\text{min}}{2} \\
+  \sigma_{p,\text{c}} &= 2\cdot
+     \frac{d(z_\text{max}) - d(z_\text{min})}{z_\text{max} - z_\text{min}} \\
+  \sigma_{p,\text{nc}} &= 0
+\end{align}
+
+The fitted $d_\text{kink}$ is accepted unless:
+
+\begin{itemize}
+  \item the fitted slope ratio
+    $|\sigma_{p,\text{c}}/\sigma_{p,\text{nc}}|$ is less than a
+    minimum threshold (which defaults to 10), or
+  \item the fitted kink position $z_\text{kink}$ is within an excluded
+    $z_\text{window}$ of the boundaries ($z_\text{window}$ defaults to
+    2\% of the total range $z_\text{max} - z_\text{min}$).
+\end{itemize}
+
+The default slope ratios work well for the cantilevers I generally
+use, but softer cantilevers may have enough drift that the minumum
+slope ratio threshold needs to be reduced.  I have not yet run into
+problems with the default kink window.  Although these are low level
+parameters, appropriate values may depend on details of the particular
+experimental setup.  The \hFconfig-based configuration structure makes
+it easy to configure (and record) the values of many similar heuristic
+parameters like these involved in robust experiment control.
+
+In the event that the surface detection is not acceptable,
+\pypiezo\ raises an exception which bubbles up the call stack until it
+is handled in \unfoldprotein\ (\cref{sec:pyafm:unfold-protein}).
+
 \subsection{Pyafm}
+\label{sec:pyafm:pyafm}
+
+Sweeping piezos around and measuring the resulting cantilever
+deflection is the core of velocity-clamp force spectroscopy.  However,
+our experimental apparatus contains some additional supporting
+hardware: a stepper motor for coarse positioning and a
+peltier/thermocouple module for temperature control.  The
+\pyafm\ module builds on \pypiezo,
+\stepper\ (\cref{sec:pyafm:stepper}), and
+\pypid\ (\cref{sec:pyafm:pypid}) to provide an easy to use (and easy
+to configure) \imint{python}|AFM| class for controlling the whole
+package.
+
+While the piezo tube is able to move the surface relative to the
+cantilever tip (\cref{fig:afm-schematic-and-piezo}), it only has a
+limited range (on the order of microns).  Achieving such a small
+separation by hand when assembling the microscope is unlikely, so a
+stepper motor controlling a fine pitch screw is used for course
+positioning.  Generic stepper control is handled by the
+\stepper\ package, and \pyafm\ builds on this to add \hFconfig-based
+configuration (time delay between steps, approximate step size,
+approximate stepper backlash, digital control port, \ldots) and a few
+course positioning methods:
+
+\begin{description}
+  \item[\imint{python}|AFM.move_away_from_surface|] provides a safety
+    mechanism that higher level applications can use to bail out.  For
+    example, when \unfoldprotein\ can not locate the surface (for
+    example, a bubble in the fluid cell may be blocking the laser
+    beam), it uses this method to put some distance between the
+    cantilever and the surface, to avoid crashing the tip and breaking
+    the cantilever.  Less drastically, this method is also used by
+    \calibcant\ (\cref{sec:calibcant}) when it changes from the
+    surface bump stage (\cref{TODO}) to the thermal vibration stage
+    (\cref{TODO}).
+  \item[\imint{python}|AFM.stepper_approach|] quickly positions the
+    surface within piezo-range of the cantilever tip by stepping in
+    (with the stepper motor) until the cantilever deflection crosses a
+    target threshold.  The piezo extension is kept constant during the
+    approach, but a single stepper step only moves the surface $\sim
+    170\U{nm}$, and our cantilevers can safely absorb deflections on
+    that scale.
+  \item[\imint{python}|AFM.move_just_onto_surface|] is a more refined
+    version of \imint{python}|AFM.stepper_approach|.  This method uses
+    \pypiezo's surface detection algorithm to locate the surface kink
+    position $z_\text{kink}$, and adjusts the stepper in single steps
+    until the measured kink is within two stepper steps ($\sim
+    340\U{nm}$) of the centered piezo position.  Then it shifts the
+    piezo to position the cantilever tip at an exact offset from the
+    measured kink.  This precise positioning is used for running
+    \calibcant's bumps, but the per-step piezo manipulation makes long
+    distance approaches much slower than
+    \imint{python}|AFM.stepper_approach|.
+\end{description}
+
+\subsection{Unfold-protein}
+\label{sec:pyafm:unfold-protein}
+
+Capping the experimental control stack, \unfoldprotein\ adds the
+actual experiment logic to the lower level control software.  The
+abstractions provided by the lower level code make for clean, easily
+adaptable code
+(\cref{fig:unfold-protein:unfolder,fig:unfold-protein:scanner}).
+
+\begin{figure}
+  \begin{center}
+\begin{minted}[mathescape]{python}
+class Unfolder (object):
+    # $\ldots$
+    def run(self):
+        """Approach-bind-unfold-save[-plot] cycle.
+        """
+        ret = {}
+        ret['timestamp'] = _email_utils.formatdate(localtime=True)
+        ret['temperature'] = self.afm.get_temperature()
+        ret['approach'] = self._approach()
+        self._bind()
+        ret['unfold'] = self._unfold()
+        self._save(**ret)
+        if _package_config['matplotlib']:
+            self._plot(**ret)
+        return ret
+\end{minted}
+    \caption{The main unfolding loop in \unfoldprotein.  Compare this
+      with the much more opaque pull phase in
+      \cref{fig:labview}.\label{fig:unfold-protein:unfolder}}
+  \end{center}
+\end{figure}
+
+\begin{figure}
+  \begin{center}
+\begin{minted}[mathescape]{python}
+class UnfoldScanner (object):
+    # $\ldots$
+    def run(self, stepper_tweaks=True):
+        self._stop = False
+        _signal.signal(_signal.SIGTERM, self._handle_stop_signal)
+        self.unfolder.afm.move_away_from_surface()
+        self.stepper_approach()
+        for i in range(self.config['velocity']['num loops']):
+            _LOG.info('on loop {} of {}'.format(
+                    i, self.config['velocity']['num loops']))
+            for velocity in self.config['velocity']['unfolding velocities']:
+                if self._stop:
+                    return
+                self.unfolder.config['unfold']['velocity'] = velocity
+                try:
+                    self.unfolder.run()
+                except _ExceptionTooFar:
+                    if stepper_tweaks:
+                        self.stepper_approach()
+                    else:
+                        raise
+                except _ExceptionTooClose:
+                    if stepper_tweaks:
+                        self.afm.move_away_from_surface()
+                        self.stepper_approach()
+                    else:
+                        raise
+                else:
+                    self.position_scan_step()
+\end{minted}
+    \caption{The scanning loop \unfoldprotein.  Unfolding pulls are
+      carried out with repeated calls to
+      \imint{python}|self.unfolder.run()|
+      (\cref{fig:unfold-protein:unfolder}), looping over the
+      configured range of velocities for a configured number of
+      cycles.  If \imint{python}|stepper_tweaks| is
+      \imint{python}|True|, the scanner adjusts the stepper position
+      to keep the surface within the piezo's range.  After a
+      successful pull, \imint{python}|self.position_scan_step()|
+      shifts the piezo in the $x$ direction, so the next pull will not
+      hit the same surface
+      location.\label{fig:unfold-protein:scanner}}
+  \end{center}
+\end{figure}
index 6f094334f28452d01a4ae02e6a66c3c7ad317b84..ad5e2bf7f0377d502fe7b5d46ab46bc1c41c0258 100644 (file)
@@ -1,5 +1,10 @@
 @string{AAPT = "AAPT"}
-@string{ACSChemBiol = "ACS Chem Biol"}
+@string{CoRR = "arXiv Computing Research Repository"}.
+@string{ACM = "Association for Computing Machinery"}
+@string{KAstrom = "{\AA}str{\"o}m, K.~J."}
+@string{ACM:SIGCSE = "ACM Special Interest Group on Computer Science Education Bulletin"}
+@string{ACM:CSur = "ACM Computing Surveys"}
+@string{ACS:ChemBiol = "ACS Chem Biol"}
 @string{AIP = "AIP"}
 @string{APL = "Applied Physics Letters"}
 @string{DAbramavicius = "Abramavicius, Darius"}
@@ -7,7 +12,8 @@
 @string{JAbu-Threideh = "Abu-Threideh, J."}
 @string{KAdachi = "Adachi, Kengo"}
 @string{MDAdams = "Adams, M. D."}
-@string{AdvExpMedBiol = "Adv Exp Med Biol"}
+@string{AW = "Addison-Wesley Longman Publishing Co., Inc."}
+@string{AdvExpMedBiol = "Advances in Experimental Medicine and Biology"}
 @string{SAinavarapu = "Ainavarapu, Sri Rama Koti"}
 @string{FAli = "Ali, F."}
 @string{JFAllemand = "Allemand, Jean-Fran\c{c}ois"}
@@ -18,6 +24,7 @@
 @string{NMAmer = "Amer, Nabil M."}
 @string{AJP = "American Journal of Physics"}
 @string{APS = "American Physical Society"}
+@string{AS = "American Scientist"}
 @string{ASA = "American Statistical Association"}
 @string{HAn = "An, H."}
 @string{KNAn = "An, Kai-Nan"}
 @string{ARBBS = "Annu Rev Biophys Biomol Struct"}
 @string{ARBC = "Annual Review of Biochemistry"}
 @string{DAnselmetti = "Anselmetti, Dario"}
+@string{AAntoniadis = "Antoniadis, Anestis"}
 @string{AMC = "Applied Mathematics and Computation"}
 @string{SArcidiacono = "Arcidiacono, S"}
 @string{CArciola = "Arciola, Carla Renata"}
 @string{ABArtyukhin = "Artyukhin, Alexander B."}
+@string{DAruliah = "Aruliah, Dhavide A."}
 @string{SAsakawa = "Asakawa, S."}
 @string{AAwe = "Awe, A."}
 @string{SBedard = "B\'edard, Sabrina"}
 @string{SBroder = "Broder, S."}
 @string{SBroedel = "Broedel, Sheldon E."}
 @string{ABrolo = "Brolo, Alexandre G."}
+@string{FBrooks = "Brooks, Jr., Frederick P."}
 @string{BrooksCole = "Brooks/Cole"}
 @string{BDBrowerToland = "Brower-Toland, Brent D."}
+@string{CTBrown = "Brown, C. Titus"}
 @string{MBrucale = "Brucale, Marco"}
 @string{TBruls = "Bruls, T."}
 @string{VBrumfeld = "Brumfeld, Vlad"}
 @string{JDBryngelson = "Bryngelson, J. D."}
+@string{JBuckheit = "Buckheit, Jonathan B."}
 @string{ABuguin = "Buguin, A."}
 @string{ABulhassan = "Bulhassan, Ahmed"}
 @string{BBullard = "Bullard, Belinda"}
 @string{MCarrionVazquez = "Carrion-Vazquez, Mariano"}
 @string{CCarter = "Carter, C."}
 @string{ACarver = "Carver, A."}
-@string{JJCatanese = "Catanese, J. J."}
+@string{JJCatanese = "Catanese, J.~J."}
 @string{PCaulk = "Caulk, P."}
 @string{CCecconi = "Cecconi, Ciro"}
 @string{ACenter = "Center, A."}
-@string{HSChan = "Chan, H. S."}
+@string{CTChan = "Chan, C.~T."}
+@string{HSChan = "Chan, H.~S."}
 @string{AChand = "Chand, Ami"}
 @string{IChandramouliswaran = "Chandramouliswaran, I."}
 @string{CHChang = "Chang, Chung-Hung"}
 @string{KChaturvedi = "Chaturvedi, K."}
 @string{CChauzy = "Chauzy, C."}
 @string{SChe = "Che, Shunai"}
+@string{CEC = "Chemical Engineering Communications"}
 @string{CHEMREV = "Chemical reviews"}
 @string{CHEM = "Chemistry (Weinheim an der Bergstrasse, Germany)"}
 @string{CPC = "Chemphyschem"}
 @string{TYChung = "Chung, Tse-Yu"}
 @string{CLChyan = "Chyan, Chia-Lin"}
 @string{GCiccotti = "Ciccotti, Giovanni"}
+@string{JClaerbout = "Claerbout, Jon F."}
 @string{AGClark = "Clark, A. G."}
 @string{Clarke = "Clarke"}
 @string{JClarke = "Clarke, Jane"}
 @string{JMClaverie = "Claverie, J. M."}
 @string{KClerc-Blankenburg = "Clerc-Blankenburg, K."}
 @string{NJCobb = "Cobb, Nathan J."}
+@string{GHCohen = "Cohen, G.~H."}
 @string{FSCollins = "Collins, Francis S."}
 @string{CUP = "Columbia University Press"}
 @string{CPR = "Computer Physics Reports"}
+@string{CSE = "Computing in Science \& Engineering"}
 @string{UniProtConsort = "Consortium, The UniProt"}
 @string{MConti = "Conti, Matteo"}
+@string{CEP = "Control Engineering Practice"}
+@string{GACoon = "Coon, G.~A."}
 @string{PVCornish = "Cornish, Peter V."}
 @string{MNCourel = "Courel, M. N."}
 @string{GCowan = "Cowan, Glen"}
 @string{FDahlquist = "Dahlquist, Frederick W."}
 @string{SDanaher = "Danaher, S."}
 @string{LDavenport = "Davenport, L."}
+@string{MDavis = "Davis, Matt"}
 @string{SDecatur = "Decatur, Sean M."}
 @string{WDeGrado = "DeGrado, William F."}
 @string{PDebrunner = "Debrunner, P."}
 @string{KDiemer = "Diemer, K."}
 @string{HDietz = "Dietz, Hendrik"}
 @string{SDietz = "Dietz, S."}
+@string{EDijkstra = "Dijkstra, Edsger Wybe"}
 @string{KADill = "Dill, K. A."}
 @string{RDima = "Dima, Ruxandra I."}
 @string{DDischer = "Discher, Dennis E."}
 @string{NDoggett = "Doggett, N."}
 @string{MDombroski = "Dombroski, M."}
 @string{MDonnelly = "Donnelly, M."}
+@string{DDonoho = "Donoho, David L."}
 @string{CDornmair = "Dornmair, C."}
 @string{MDors = "Dors, M."}
 @string{LDougan = "Dougan, Lorna"}
 @string{AGomezCasado = "Gomez-Casado, Alberto"}
 @string{BGompertz = "Gompertz, Benjamin"}
 @string{FGong = "Gong, F."}
+@string{GordonBreach = "Gordon Breach Scientific Publishing Ltd."}
 @string{MGorokhov = "Gorokhov, M."}
 @string{JHGorrell = "Gorrell, J. H."}
 @string{KGraham = "Graham, K."}
 @string{HJGuntherodt = "Guntherodt, Hans-Joachim"}
 @string{NGuo = "Guo, N."}
 @string{YGuo = "Guo, Yi"}
+@string{RTGuy = "Guy, Richard T."}
 @string{PHanggi = {H\"anggi, Peter}}
 @string{THa = "Ha, Taekjip"}
 @string{JHaack = "Haack, Julie A."}
+@string{SHaddock = "Haddock, Steven H.~D."}
 @string{GHager = "Hager, Gabriele"}
+@string{THagglund = "H{\"a}gglund, T."}
 @string{RHajjar = "Hajjar, Roger J."}
 @string{AHalpern = "Halpern, A."}
 @string{KHalvorsen = "Halvorsen, Ken"}
 @string{FHan = "Han, Fangpu"}
+@string{CCHang = "Hang, C.~C."}
 @string{SHannenhalli = "Hannenhalli, S."}
 @string{HHansma = "Hansma, H. G."}
 @string{PHansma = "Hansma, Paul K."}
 @string{BHeymann = "Heymann, Berthold"}
 @string{NHiaro = "Hiaro, N."}
 @string{MEHiggins = "Higgins, M. E."}
+@string{THilburn = "Hilburn, Thomas B."}
 @string{LHillier = "Hillier, L."}
 @string{HHinssen = "Hinssen, Horst"}
 @string{PHinterdorfer = "Hinterdorfer, Peter"}
 @string{HistochemJ = "Histochem J"}
 @string{SHladun = "Hladun, S."}
+@string{WKHo = "Ho, W.~K."}
 @string{RHochstrasser = "Hochstrasser, Robin M."}
 @string{CHoff = "Hoff, C."}
 @string{WHoff = "Hoff, Wouter D."}
 @string{JLHolden = "Holden, J. L."}
 @string{RAHolt = "Holt, R. A."}
 @string{MHonda = "Honda, M."}
+@string{NPCHong = "Hong, Neil P. Chue"}
 @string{XHong = "Hong, Xia"}
 @string{LHood = "Hood, L."}
 @string{JHoover = "Hoover, J."}
 @string{CKHu = "Hu, Chin-Kun"}
 @string{BHuang = "Huang, Baiqu"}
 @string{HHuang = "Huang, Hector Han-Li"}
+@string{KHuff = "Huff, Katy"}
+@string{JHughes = "Hughes, John"}
 @string{GHummer = "Hummer, Gerhard"}
 @string{SJHumphray = "Humphray, S. J."}
 @string{WLHung = "Hung, Wen-Liang"}
 @string{JHutter = "Hutter, Jeffrey L."}
 @string{CHyeon = "Hyeon, Changbong"}
 @string{IEEE:TIT = "IEEE Transactions on Information Theory"}
+@string{IEEE:SPM = "IEEE Signal Processing Magazine"}
 @string{CIbegwam = "Ibegwam, C."}
 @string{JRIdol = "Idol, J. R."}
 @string{SImprota = "Improta, S."}
 @string{TInoue = "Inoue, Tadashi"}
 @string{IJBMM = "International Journal of Biological Macromolecules"}
+@string{IJCIS = "International Journal of Computer \& Information Sciences"}
 @string{HItoh = "Itoh, Hiroyasu"}
 @string{AIrback = "Irback, Anders"}
 @string{BIsralewitz = "Isralewitz, B."}
 @string{JP:CM = "Journal of Physics: Condensed Matter"}
 @string{JP:CON = "Journal of Physics: Conference Series"}
 @string{JASA = "Journal of the American Statistical Association"}
+@string{WSJuang = "Juang, F.~S."}
 @string{DAJuckett = "Juckett, D. A."}
 @string{SRJun = "Jun, Se-Ran"}
 @string{DKaftan = "Kaftan, David"}
 @string{AKardinal = "Kardinal, Angelika"}
 @string{BKarlak = "Karlak, B."}
 @string{MKarplus = "Karplus, Martin"}
+@string{MKarrenbach = "Karrenbach, Martin"}
 @string{JKasha = "Kasha, J."}
 @string{KKawasaki = "Kawasaki, K."}
 @string{ZKe = "Ke, Z."}
 @string{DKlimov = "Klimov, Dmitri K."}
 @string{LKline = "Kline, L."}
 @string{LKlumb = "Klumb, L."}
+@string{KAPPP = "Kluwer Academic Publishers--Plenum Publishers"}
 @string{CDKodira = "Kodira, C. D."}
 @string{SKoduru = "Koduru, S."}
 @string{BKolmerer = "Kolmerer, B."}
 @string{JKorenberg = "Korenberg, J."}
 @string{IKosztin = "Kosztin, Ioan"}
+@string{JKovacevic = "Kovacevic, Jelena"}
 @string{CKraft = "Kraft, C."}
 @string{HAKramers = "Kramers, H. A."}
 @string{AKrammer = "Krammer, Andre"}
 @string{AMatouschek = "Matouschek, Andreas"}
 @string{BMatthews = "Matthews, Brian W."}
 @string{DMay = "May, D."}
+@string{RMayer = "Mayer, Richard"}
 @string{LMayne = "Mayne, Leland"}
 @string{AMays = "Mays, A."}
 @string{OTMcCann = "McCann, O. T."}
 @string{AMiller = "Miller, A."}
 @string{NMilshina = "Milshina, N."}
 @string{SMinoshima = "Minoshima, S."}
+@string{IMitchell = "Mitchell, Ian"}
 @string{SMitternacht = "Mitternacht, Simon"}
 @string{CMobarry = "Mobarry, C."}
 @string{NMohandas = "Mohandas, N."}
 @string{TNguyen = "Nguyen, T."}
 @string{MNguyen-Duong = "Nguyen-Duong, M."}
 @string{INicholls = "Nicholls, Ian A."}
+@string{NNichols = "Nichols, N.~B."}
 @string{SNie = "Nie, S."}
 @string{MNodell = "Nodell, M."}
 @string{AANoegel = "Noegel, Angelika A."}
 @string{POmling = {Omlink, P{\"a}r}}
 @string{JNOnuchic = "Onuchic, J. N."}
 @string{YOono = "Oono, Y."}
+@string{GOppenheim = "Oppenheim, Georges"}
 @string{COpitz = "Optiz, Christiane A."}
 @string{KOroszlan = "Oroszlan, Krisztina"}
 @string{EOroudjev = "Oroudjev, E."}
 @string{Physica = "Physica"}
 @string{GPing = "Ping, Guanghui"}
 @string{NPinotsis = "Pinotsis, Nikos"}
+@string{MPlumbley = "Plumbley, Mark"}
 @string{DPlunkett = "Plunkett, David"}
 @string{PPodsiadlo = "Podsiadlo, Paul"}
 @string{ASPolitou = "Politou, A. S."}
 @string{GDSchuler = "Schuler, G. D."}
 @string{KSchulten = "Schulten, Klaus"}
 @string{ZSchulten = "Schulten, Zan"}
+@string{MSchwab = "Schwab, M."}
 @string{ISchwaiger = "Schwaiger, Ingo"}
 @string{RSchwartz = "Schwartz, R."}
 @string{RSchweitzerStenner = "Scheitzer-Stenner, Reinhard"}
 @string{NShimizu = "Shimizu, N."}
 @string{RShimoKon = "Shimo-Kon, Rieko"}
 @string{AShintani = "Shintani, A."}
+@string{BShneiderman = "Shneiderman, Ben"}
 @string{BShue = "Shue, B."}
 @string{RSiebert = "Siebert, R."}
 @string{EDSiggia = "Siggia, Eric D."}
 @string{TSmith = "Smith, T."}
 @string{JSoares = "Soares, J."}
 @string{NDSocci = "Socci, N. D."}
+@string{SEG = "Society of Exploration Geophysicists"}
 @string{ESodergren = "Sodergren, E."}
 @string{CSoderlund = "Soderlund, C."}
 @string{JSpanier = "Spanier, Jonathan E."}
 @string{RTampe = "Tamp{\'e}, Robert"}
 @string{JTang = "Tang, Jianyong"}
 @string{BNTaylor = "Taylor, Barry N."}
+@string{THEMath = "Technische Hogeschool Eindhoven, Nederland,
+  Onderafdeling der Wiskunde"}
 @string{STeukolsky = "Teukolsky, S."}
+@string{CJ = "The Computer Journal"}
 @string{JCP = "The Journal of Chemical Physics"}
 @string{JPC:B = "The Journal of Physical Chemistry B"}
 @string{JPC:C = "The Journal of Physical Chemistry C"}
 @string{TTlusty = "Tlusty, Tsvi"}
 @string{JTocaHerrera = "Toca-Herrera, Jose L."}
 @string{AToyoda = "Toyoda, A."}
+@string{TASME = "Transactions of the American Society of Mechanical Engineers"}
 @string{BTrask = "Trask, B."}
 @string{TBI = "Tribology International"}
 @string{JTrinick = "Trinick, John"}
 @string{UTMB = "University of Texas Medical Branch"}
 @string{MUrbakh = "Urbakh, M."}
 @string{KJVanVliet = "Van Vliet, Krystyn J."}
+@string{PVandewalle = "Vandewalle, Patrick"}
 @string{CVech = "Vech, C."}
 @string{OVelasquez = "Velasquez, O."}
 @string{EVenter = "Venter, E."}
 @string{JCVenter = "Venter, J. C."}
 @string{PHVerdier = "Verdier, Peter H."}
 @string{IVetter = "Vetter, Ingrid R."}
+@string{MVetterli = "Vetterli, Martin"}
 @string{WVetterling = "Vetterling, W."}
 @string{MViani = "Viani, Mario B."}
 @string{JCVoegel = "Voegel, J.-C."}
 @string{AJWalton = "Walton, Alan J"}
 @string{EBWalton = "Walton, Emily B."}
 @string{AWang = "Wang, A."}
+@string{FSWang = "Wang, F.~S."}
 @string{GWang = "Wang, G."}
 @string{JWang = "Wang, J."}
 @string{MWang = "Wang, M."}
 @string{HWatanabe = "Watanabe, Hiroshi"}
 @string{KWatanabe = "Watanabe, Kaori"}
 @string{RHWaterston = "Waterston, R. H."}
+@string{BWaugh = "Waugh, Ben"}
 @string{MWei = "Wei, M."}
 @string{YWei = "Wei, Yen"}
 @string{JWeissenbach = "Weissenbach, J."}
 @string{GWen = "Wen, G."}
 @string{MWen = "Wen, M."}
 @string{JWetter = "Wetter, J."}
+@string{EPWhite = "White, Ethan P."}
 @string{AWhittaker = "Whittaker, A."}
 @string{YWickramasinghe = "Wickramasinghe, H. K."}
 @string{RWides = "Wides, R."}
 @string{MWilliams = "Williams, M."}
 @string{SWilliams = "Williams, S."}
 @string{MWilmanns = "Wilmanns, Matthias"}
+@string{GWilson = "Wilson, Greg"}
+@string{PWilson = "Wilson, Paul"}
 @string{RKWilson = "Wilson, R. K."}
 @string{SWilson = "Wilson, Scott"}
 @string{SWindsor = "Windsor, S."}
 @string{EWinn-Deen = "Winn-Deen, E."}
+@string{NWirth = "Wirth, Niklaus"}
 @string{CWitt = "Witt, Christian"}
 @string{KWolfe = "Wolfe, K."}
 @string{TGWolfsberg = "Wolfsberg, T. G."}
 @string{XZhu = "Zhu, X."}
 @string{YJZhu = "Zhu, Ying-Jie"}
 @string{WZhuang = "Zhuang, Wei"}
+@string{JZiegler = "Ziegler, J.G."}
 @string{NZinder = "Zinder, N."}
 @string{RCZinober = "Zinober, Rebecca C."}
 @string{JZlatanova = "Zlatanova, Jordanka"}
     title = "Statistics of Extremes",
     year = 1958,
     publisher = CUP,
-               address = "New York",
-               note = "TODO: read",
+    address = "New York",
+    note = "TODO: read",
 }
 
 @misc{ wikipedia:GEV,
     year = 2007,
     month = jan,
     day = 23,
-    journal = ACSChemBiol,
+    journal = ACS:ChemBiol,
     volume = 2,
     number = 1,
     pages = "53--61",
     title = "Designing an extracellular matrix protein with enhanced mechanical
         stability",
     year = 2007,
-               month = jun,
-               day = 5,
+    month = jun,
+    day = 5,
     journal = PNAS,
     volume = 104,
     number = 23,
     number = 4,
     pages = "851–854",
     year = 2007,
-               month = aug,
-               day = 24,
+    month = aug,
+    day = 24,
     issn = "0022-2836",
     doi = "10.1016/j.jmb.2007.06.015",
     url = "http://www.sciencedirect.com/science/article/pii/S0022283607007966",
     the deviation of the predicted behavior with respect to the
     experimental data.",
   language = "eng",
-} 
+}
 
 @article { measey09,
-  author =       TMeasey #" and "# KBSmith #" and "# SDecatur #" and "# 
+  author =       TMeasey #" and "# KBSmith #" and "# SDecatur #" and "#
                  LZhao #" and "# GYang #" and "# RSchweitzerStenner,
   title =        "Self-aggregation of a polyalanine octamer promoted by
                  its {C}-terminal tyrosine and probed by a strongly
     them to unfold single titin molecules over an order of magnitude
     faster than previously reported with conventional cantilevers.",
   ISSN = "0021-8979",
-       issn_online = "1089-7550",
-       doi = "10.1063/1.371039",
+  issn_online = "1089-7550",
+  doi = "10.1063/1.371039",
   URL = "http://jap.aip.org/resource/1/japiau/v86/i4/p2258_s1",
   language = "eng",
 }
     detection. Finally, a time of flight method that permits the
     reconstruction of the optical potential well was demonstrated.",
   ISSN = "0034-6748",
-       issn_online = "1089-7623",
+  issn_online = "1089-7623",
   doi = "10.1063/1.1460929",
   URL = "http://rsi.aip.org/resource/1/rsinak/v73/i4/p1687_s1",
   language = "eng",
   volume = 49,
   number = 23,
   pages = "1587--1589",
-       abstract = "A new high‐resolution profilometer has been demonstrated
-       based upon a noncontacting near‐field thermal probe. The thermal
-       probe consists of a thermocouple sensor with dimensions
-       approaching 100 nm. Profiling is achieved by scanning the heated
-       sensor above but close to the surface of a solid. The conduction
-       of heat between tip and sample via the air provides a means for
-       maintaining the sample spacing constant during the lateral
-       scan. The large difference in thermal properties between air and
-       solids makes the profiling technique essentially independent of
-       the material properties of the solid. Noncontact profiling of
-       resist and metal films has shown a lateral resolution of 100 nm
-       and a depth solution of 3 nm. The basic theory of the new probe is
-       described and the results presented.",
-       issn = "0003-6951",
-       issn_online = "1077-3118",
+  abstract = "A new high‐resolution profilometer has been demonstrated
+    based upon a noncontacting near‐field thermal probe. The thermal
+    probe consists of a thermocouple sensor with dimensions
+    approaching 100 nm. Profiling is achieved by scanning the heated
+    sensor above but close to the surface of a solid. The conduction
+    of heat between tip and sample via the air provides a means for
+    maintaining the sample spacing constant during the lateral
+    scan. The large difference in thermal properties between air and
+    solids makes the profiling technique essentially independent of
+    the material properties of the solid. Noncontact profiling of
+    resist and metal films has shown a lateral resolution of 100 nm
+    and a depth solution of 3 nm. The basic theory of the new probe is
+    described and the results presented.",
+  issn = "0003-6951",
+  issn_online = "1077-3118",
   doi = "10.1063/1.97288",
   URL = "http://apl.aip.org/resource/1/applab/v49/i23/p1587_s1",
   language = "eng",
   volume = 61,
   number = 10,
   pages = "4723--4729",
-       abstract = "A modified version of the atomic force microscope is
-       introduced that enables a precise measurement of the force between
-       a tip and a sample over a tip‐sample distance range of 30--150
-       \AA. As an application, the force signal is used to maintain the
-       tip‐sample spacing constant, so that profiling can be achieved
-       with a spatial resolution of 50 \AA. A second scheme allows the
-       simultaneous measurement of force and surface profile; this scheme
-       has been used to obtain material-dependent information from
-       surfaces of electronic materials.",
-       issn = "0021-8979",
-       issn_online = "1089-7550",
+  abstract = "A modified version of the atomic force microscope is
+    introduced that enables a precise measurement of the force between
+    a tip and a sample over a tip‐sample distance range of 30--150
+    \AA. As an application, the force signal is used to maintain the
+    tip‐sample spacing constant, so that profiling can be achieved
+    with a spatial resolution of 50 \AA. A second scheme allows the
+    simultaneous measurement of force and surface profile; this scheme
+    has been used to obtain material-dependent information from
+    surfaces of electronic materials.",
+  issn = "0021-8979",
+  issn_online = "1089-7550",
   doi = "10.1063/1.338807",
   URL = "http://jap.aip.org/resource/1/japiau/v61/i10/p4723_s1",
   language = "eng",
   volume = 53,
   number = 12,
   pages = "1045--1047",
-       abstract = "A sensitive and simple optical method for detecting the
-       cantilever deflection in atomic force microscopy is described. The
-       method was incorporated in an atomic force microscope, and imaging
-       and force measurements, in ultrahigh vacuum, were successfully
-       performed.",
-       issn = "0003-6951",
-       issn_online = "1077-3118",
+  abstract = "A sensitive and simple optical method for detecting the
+    cantilever deflection in atomic force microscopy is described. The
+    method was incorporated in an atomic force microscope, and imaging
+    and force measurements, in ultrahigh vacuum, were successfully
+    performed.",
+  issn = "0003-6951",
+  issn_online = "1077-3118",
   doi = "10.1063/1.100061",
   URL = "http://apl.aip.org/resource/1/applab/v53/i12/p1045_s1",
   language = "eng",
 }
+
+@book{ dijkstra70,
+  author = EDijkstra,
+  title = {Notes on Structured Programming},
+  year = 1970,
+  month = apr,
+  url = {http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD249.PDF},
+  publisher = THEMath,
+  note = {T.H. Report 70-WSK-03},
+}
+
+@article{ wirth74,
+ author = NWirth,
+ title = {On the Composition of Well-Structured Programs},
+ journal = ACM:CSur,
+ year = 1974,
+ month = dec,
+ volume = 6,
+ number = 4,
+ pages = {247--259},
+ numpages = {13},
+ issn = {0360-0300},
+ doi = {10.1145/356635.356639},
+ url = {http://doi.acm.org/10.1145/356635.356639},
+ publisher = ACM,
+ address = {New York, NY, USA},
+}
+
+@article{ shneiderman79,
+  author = BShneiderman #" and "# RMayer,
+  title = {Syntactic/semantic interactions in programmer behavior: A
+    model and experimental results},
+  year = 1979,
+  journal = IJCIS,
+  volume = 8,
+  number = 3,
+  pages = {219--238},
+  issn = {0091-7036},
+  doi = {10.1007/BF00977789},
+  url = {http://dx.doi.org/10.1007/BF00977789},
+  publisher = KAPPP,
+  keywords = {Programming; programming languages; cognitive models;
+    program composition; program comprehension; debugging;
+    modification; learning; education; information processing},
+  language = {English},
+}
+
+@article{ hughes89,
+  author = JHughes,
+  title = {Why Functional Programming Matters},
+  journal = CJ,
+  year = 1989,
+  volume = 32,
+  number = 2,
+  pages = {98--107},
+  doi = {10.1093/comjnl/32.2.98},
+  URL = {http://comjnl.oxfordjournals.org/content/32/2/98.abstract},
+  eprint = {http://comjnl.oxfordjournals.org/content/32/2/98.full.pdf+html},
+  abstract ={As software becomes more and more complex, it is more and
+    more important to structure it well. Well-structured software is
+    easy to write, easy to debug, and provides a collection of modules
+    that can be re-used to reduce future programming
+    costs. Conventional languages place conceptual limits on the way
+    problems can be modularised. Functional languages push those
+    limits back. In this paper we show that two features of functional
+    languages in particular, higher-order functions and lazy
+    evaluation, can contribute greatly to modularity. As examples, we
+    manipulate lists and trees, program several numerical algorithms,
+    and implement the alpha-beta heuristics (an Artificial
+    Intelligence algorithm used in game-playing programs). Since
+    modularity is the key to successful programming, functional
+    languages are vitally important to the real world.},
+}
+
+@article{ hilburn93,
+ author = THilburn,
+ title = {A top-down approach to teaching an introductory computer science course},
+ journal = ACM:SIGCSE,
+ year = 1993,
+ month = mar,
+ volume = 25,
+ number = 1,
+ issn = {0097-8418},
+ pages = {58--62},
+ numpages = 5,
+ doi = {10.1145/169073.169349},
+ url = {http://doi.acm.org/10.1145/169073.169349},
+ acmid = {169349},
+ publisher = ACM,
+ address = {New York, NY, USA},
+}
+
+@book{ brooks95,
+  author = FBrooks,
+  title = {The mythical man-month},
+  edition = {20$^\text{th}$ anniversary},
+  year = 1995,
+  isbn = {0-201-83595-9},
+  publisher = AW,
+  address = {Boston, MA, USA},
+  url = {http://dl.acm.org/citation.cfm?id=207583},
+  note = {First published in 1975},
+}
+
+@inproceedings{ claerbout92,
+  author = JClaerbout #" and "# MKarrenbach,
+  title = {Electronic documents give reproducible research a new meaning},
+  booktitle = {SEG Technical Program Expanded Abstracts 1992},
+  chapter = 161,
+  year = 1992,
+  pages = {601--604},
+  doi = {10.1190/1.1822162},
+  issn = {1052-3812},
+  publisher = SEG,
+  url = {http://library.seg.org/doi/abs/10.1190/1.1822162},
+  eprint = {http://sepwww.stanford.edu/doku.php?id=sep:research:reproducible:seg92},
+}
+
+@incollection{ buckheit95,
+  author = JBuckheit #" and "# DDonoho,
+  title = {WaveLab and Reproducible Research},
+  booktitle = {Wavelets and Statistics},
+  series = {Lecture Notes in Statistics},
+  editor = AAntoniadis #" and "# GOppenheim,
+  year = 1995,
+  volume = 103,
+  pages = {55--81},
+  isbn = {978-0-387-94564-4},
+  doi = {10.1007/978-1-4612-2544-7_5},
+  url = {http://dx.doi.org/10.1007/978-1-4612-2544-7_5},
+  eprint = {http://www-stat.stanford.edu/~wavelab/Wavelab_850/wavelab.pdf},
+  publisher = SPRINGER,
+  language = {English},
+}
+
+@article{ schwab00,
+  author = MSchwab #" and "# MKarrenbach #" and "# JClaerbout,
+  title = {Making scientific computations reproducible},
+  journal = CSE,
+  year = 2000,
+  month = {November--December},
+  volume = 2,
+  number = 6,
+  pages = {61--67},
+  doi = {10.1109/5992.881708},
+  ISSN = {1521-9615},
+  keywords = {document handling;file organisation;natural sciences
+    computing;research and development
+    management;ReDoc;authors;computational results;reproducible
+    scientific computations;research paper;software filing
+    system;standardized rules;Computer
+    interfaces;Documentation;Electronic
+    publishing;Laboratories;Organizing;Reproducibility of
+    results;Software maintenance;Software systems;Software
+    testing;Technological innovation},
+  abstract = {To verify a research paper's computational results,
+    readers typically have to recreate them from scratch. ReDoc is a
+    simple software filing system for authors that lets readers easily
+    reproduce computational results using standardized rules and
+    commands},
+}
+
+@article{ wilson06a,
+  author = GWilson,
+  title = {Where's the Real Bottleneck in Scientific Computing?},
+  journal = AS,
+  year = 2006,
+  month = {January--February},
+}
+
+@article{ wilson06b,
+  author = GWilson ,
+  title = {Software Carpentry: Getting Scientists to Write Better
+    Code by Making Them More Productive},
+  journal = CSE,
+  year = 2006,
+  month = {November--December},
+}
+
+@article{ vandewalle09,
+  author = PVandewalle #" and "# JKovacevic #" and "# MVetterli ,
+  title = {Reproducible Research in Signal Processing - What, why, and how},
+  journal = IEEE:SPM,
+  year = 2009,
+  month = may,
+  volume = 26,
+  number = 3,
+  pages = {37--47},
+  doi = {10.1109/MSP.2009.932122},
+  issn = {1053-5888},
+  url = {http://rr.epfl.ch/17/},
+  eprint = {http://rr.epfl.ch/17/1/VandewalleKV09.pdf},
+  keywords={research and development;signal processing;high-quality
+    reviewing process;large data set;reproducible research;signal
+    processing;win-win situation;Advertising;Digital signal
+    processing;Education;Programming;Reproducibility of
+    results;Scholarships;Signal processing;Signal processing
+    algorithms;Testing;Wikipedia},
+  abstract = {Have you ever tried to reproduce the results presented
+    in a research paper? For many of our current publications, this
+    would unfortunately be a challenging task. For a computational
+    algorithm, details such as the exact data set, initialization or
+    termination procedures, and precise parameter values are often
+    omitted in the publication for various reasons, such as a lack of
+    space, a lack of self-discipline, or an apparent lack of interest
+    to the readers, to name a few. This makes it difficult, if not
+    impossible, for someone else to obtain the same results. In our
+    experience, it is often even worse as even we are not always able
+    to reproduce our own experiments, making it difficult to answer
+    questions from colleagues about details. Following are some
+    examples of e-mails we have received: ``I just read your paper
+    X. It is very completely described, however I am confused by
+    Y. Could you provide the implementation code to me for reference
+    if possible?'' ``Hi! I am also working on a project related to
+    X. I have implemented your algorithm but cannot get the same
+    results as described in your paper. Which values should I use for
+    parameters Y and Z?''},
+}
+
+@article{ aruliah12,
+  author = DAruliah #" and "# CTBrown #" and "# MPCHong #" and "#
+    MDavis #" and "# RTGuy #" and "# SHaddock #" and "# KHuff #" and "#
+    IMitchell #" and "# MPlumbley #" and "# BWaugh #" and "#
+    EPWhite #" and "# GWilson #" and "# PWilson,
+  title = {Best Practices for Scientific Computing},
+  journal = CoRR,
+  volume = {abs/1210.0530},
+  year = 2012,
+  month = nov,
+  day = 29,
+  numpages = 6,
+  url = {http://arxiv.org/abs/1210.0530},
+  eprint = {http://arxiv.org/pdf/1210.0530v3},
+  note = {v3: Thu, 29 Nov 2012 19:28:27 GMT},
+}
+
+@article{ ziegler42,
+  author = JZiegler #" and "# NNichols,
+  title = {Optimum Settings for Automatic Controllers},
+  journal = TASME,
+  year = 1942,
+  month = nov,
+  volume = 64,
+  pages = {759--765},
+  url = {http://www.driedger.ca/Z-N/Z-N.html},
+  eprint = {http://www.driedger.ca/Z-N/Z-n.pdf},
+}
+
+@article{ cohen53,
+  author = GHCohen #" and "# GACoon,
+  title = {Theoretical considerations of retarded control},
+  year = 1953,
+  journal = TASME,
+  volume = 75,
+  pages = {827--834},
+}
+
+@article{ wang95,
+  author = FSWang #" and "# WSJuang #" and "# CTChan,
+  title = {Optimal tuning of {PID} controllers for single and
+    cascade control loops},
+  year = 1995,
+  journal = CEC,
+  volume = 132,
+  number = 1,
+  pages = {15--34},
+  publisher = GordonBreach,
+  issn = {0098-6445},
+  doi = {10.1080/00986449508936294},
+  url = {http://www.tandfonline.com/doi/abs/10.1080/00986449508936294},
+  keywords = {process control; cascade control; controller tuning},
+  abstract = {Design of one parameter tuning of three-mode PID
+    controller was developed in this present study. The integral time
+    and the derivative time of the controller were expressed in terms
+    of the time constant and dead time of the process. Only the
+    proportional gain was observed to be dependent on the implemented
+    tunable parameter in which the stable region could be
+    predetermined by the Routh test. Extension of the concept towards
+    designing cascade PID controllers was straightforward such that
+    only two parameters for the inner and outer PID controllers
+    required to be tuned, respectively. The optimal tuning correlative
+    formulas of the proportional gain for single and cascade control
+    systems were obtained by the least square regression method.},
+}
+
+@article{ astrom93,
+  author = KAstrom #" and "# THagglund #" and "# CCHang #" and "# WKHo,
+  title = {Automatic tuning and adaptation for {PID} controllers---a survey},
+  journal = CEP,
+  year = 1993,
+  volume = 1,
+  number = 4,
+  pages = {699--714},
+  issn = "0967-0661",
+  doi = "10.1016/0967-0661(93)91394-C",
+  url = "http://www.sciencedirect.com/science/article/pii/096706619391394C",
+  keywords = {Adaptive control},
+  keywords = {automatic tuning},
+  keywords = {gain scheduling},
+  keywords = {{PID} control},
+  abstract = {Adaptive techniques such as gain scheduling, automatic
+    tuning and continuous adaptation have been used in industrial
+    single-loop controllers for about ten years. This paper gives a
+    survey of the different adaptive techniques, the underlying
+    process models and control designs. An overview of industrial
+    products is also presented, which includes a fairly detailed
+    investigation of four different adaptive single-loop
+    controllers.},
+}
index 1ecaa88da81775b3d88c48e168a6ef4615d9704e..c914ea4b8d044f28776ff4794a18422e09140d00 100644 (file)
@@ -24,8 +24,8 @@
 
 \author{William Trevor King}
 \title{Open source single molecule force spectroscopy}
-\DUTmonth{July}
-\DUTyear{2012}
+\DUTmonth{May}
+\DUTyear{2013}
 \degree{Doctor of Philosophy}
 \advisor{Guoliang Yang, Ph.D.}
 \advisor{Louis Cruz Cruz, Ph.D.}
@@ -74,6 +74,7 @@ defaultpen(fontsize(10));  // match drexel-thesis's default 10pt font size
 \bibliography{%
   apparatus/main,%
 %  sawsim/main,% currently empty
+  pyafm/main,%
   cantilever-calib/main,%
   packaging/main,%
   figures/main,%
index f6985786d54c86ccd60cbdbeca6a26f1d2963187..ae199d13682959d79f2d6f12a84696e4251d1a00 100644 (file)
@@ -445,7 +445,7 @@ makes full use of your experimental histograms, which you specify in a
 plain-text histogram file:
 \begin{center}
 \begin{spacing}{1}
-\begin{Verbatim}
+\begin{Verbatim}[commandchars=\\\{\}]
 #HISTOGRAM: -v 6e-7
 #Force (N)      Unfolding events
 1.4e-10 1
@@ -482,17 +482,17 @@ command line interfaces for generating and manipulating \sawsim\ runs.
 For example, to compare the experimental histograms listed above with
 simulated data over a 50-by-50 grid of $k_{u0}$ and $\Delta x$, you
 would use something like
-\begin{Verbatim}[samepage]
+\begin{minted}[samepage]{console}
 $ sawsim_hist_scan.py -f '-s cantilever,hooke,0.05 -N1 -s folded,null -N8
      -s "unfolded,wlc,{0.39e-9,28e-9}" -k "folded,unfolded,bell,{%g,x%g}"
      -q folded' -r '[1e-5,1e-3,50],[0.1e-9,1e-9,50]' --logx histograms.txt
-\end{Verbatim}
+\end{minted}
 That's a bit of a mouthful, so let's break it down.  Without the
 \sawsim\ template (\Verb+-f ...+), we can focus on the comparison
 options:
-\begin{Verbatim}[samepage]
+\begin{minted}[samepage]{console}
 $ sawsim_hist_scan.py \ldots -r '[1e-5,1e-3,50],[0.1e-9,1e-9,50]' --logx histograms.txt
-\end{Verbatim}
+\end{minted}
 This sets up a two-parameter sweep, with the first parameter going
 from $1\E{-5}$ to $1\E{-3}$ in 50 logarithmic steps, and the second
 going from $0.1\E{-9}$ to $1\E{-9}$ in 50 linear steps.  The