aboutsummaryrefslogtreecommitdiff
path: root/acquisition
diff options
context:
space:
mode:
Diffstat (limited to 'acquisition')
-rw-r--r--acquisition/chapter.tex507
-rw-r--r--acquisition/quad.pngbin132067 -> 156161 bytes
-rw-r--r--acquisition/quad.py23
-rw-r--r--acquisition/screenshots/009.PNGbin0 -> 126165 bytes
4 files changed, 403 insertions, 127 deletions
diff --git a/acquisition/chapter.tex b/acquisition/chapter.tex
index ab1793d..78b4199 100644
--- a/acquisition/chapter.tex
+++ b/acquisition/chapter.tex
@@ -11,7 +11,6 @@
\section{Introduction} % =========================================================================
-MR-CMDS instruments need to be capable of several different things. %
At its core, MR-CMDS is about delivering multiple pulses of light to a sample. %
The frequency and relative arrival time (delay) of each pulse must be scanned in the context of a
basic multidimensional experiment. %
@@ -25,7 +24,7 @@ An automated monchromator is typically used to spectrally resolve or isolate out
Each of these features is an optomechanical device: a piece of hardware that must be controlled in
the context of an MR-CMDS experiment. %
-A scan in MR-CMDS typically means going to a whole series of different positions. %
+A scan in MR-CMDS typically means sending hardware to a whole series of different positions. %
As an example, a three-dimensional ``movie'' might be collected in the following way:
\begin{codefragment}{python, label=aqn:lst:psuedoaqn}
w1_points = [14300, 14400, 14500, 14600, 14700] # wn
@@ -59,21 +58,35 @@ software must be built in an extendable way to accommodate the ever-changing har
configurations. %
In this chapter I describe how I built such an acquisition software, PyCMDS. %
+For context, some description of the acquisition software that PyCMDS replaced is warranted. %
+
+On the ``ps table'' (focus on mixed vibrational-electronic spectroscopy of molecular systems),
+PyCMDS replaces `ps\_control', an older acquisition software first developed in [YEAR] by Kent
+Meyer [CITE]. %
+ps\_control was very-much not modular, designed by generations of graduate students to get to
+``minimum viable'' as quickly as possible. %
+When I joined the group, ps\_control had become unsustainable. %
+The ps table was being revamped with new hardware, and the old motherboard finally died, so new
+software was desperately needed. %
+
+On the ``fs table'' (focus on semiconductor photophysics), PyCMDS replaces `Control for Lots of
+Research in Spectroscopy' (COLORS), developed by Schuyler Kain [CITE]. %
+PyCMDS is, in many ways, inspired by COLORS. %
+Kain's design was modular in many ways. %
+Still, there were fundamental problems that COLORS could not address. %
+Chief among them was Kain's approach to the National Instruments DAQ card, which did not allow for
+the flexibility required to introduce more interesting chopping schemes [SECTION]. %
+
PyCMDS is a unified software for controlling hardware and collecting data in the Wright Group. %
-It is written almost entirely in Python, with a graphical user interface (GUI) made using Qt.
-[CITE] %
+It is written almost entirely in Python, with a graphical user interface (GUI) made using Qt
+[CITE]. %
It is cross-platform, with a core capable of running on Linux, Windows and macOS. %
It is open source, developed on GitHub. [CITE (GITHUB, PyCMDS)] %
-In the Wright Group, PyCMDS replaces the old acquisition softwares `ps control', written by
-Kent Meyer, [CITE] and `Control for Lots of Research in Spectroscopy' (COLORS) written by Schuyler
-Kain [CITE]. %
-Today PyCMDS is used to drive both of the MR-CMDS instruments maintained by the Wright Group: the
-``fs table'', focused on semiconductor photophysics, and the ``ps table'', focused on molecular
-systems. %
-% BJT: consider giving more historical context re: COLORS, ps_control
-
-PyCMDS is best thought of as a central program with three kinds of modular ``plugins'' that can be
-extended indefinitely:
+Today PyCMDS is used to drive both the ps and fs tables. %
+
+PyCMDS is best thought of as a core program with three kinds of modular ``plugins'' that can be
+extended as needed. %
+The three plugin kinds are
\begin{ditemize}
\item Hardware: things that can be set to a position (\autoref{aqn:sec:hardware}).
\item Sensors: things that can be used to measure a signal (\autoref{aqn:sec:sensors}).
@@ -92,11 +105,45 @@ Besides the extendable modular pieces, the rest of PyCMDS is a mostly-static cod
modules and does the necessary things to handle display of information from, and communication
between them. %
-% TODO: describe each of the sections of this chapter
+PyCMDS offers many ways to interact with component hardwares. %
+Hardware can be set directly, or it can be moved in the context of a scan. %
+Less obviously, hardware must also move in the context of ``active correction'', such as spectral
+delay correction. %
+I love to use the analogy of the nervous system when thinking of these two kinds of
+instructions. %
+I have borrowed the terms ``autonomic'' and ``somatic'':
+
+\begin{dquote}
+ The autonomic nervous system, which innervates primarily the smooth musculature of all organs,
+ the heart and the glands, mediates the neuronal regulation of the internal milieu. %
+ The actions of this system, as its name implies, are in general not under direct voluntary
+ control. %
+ These characteristics distinguish the autonomic nervous system from the somatic nervous system,
+ which mediates afferent and efferent communication with the enviornment and, for the most part,
+ is subject to voluntary control and accessible to consciousness. %
+
+ The autonomic and somatic systems operate hand in hand...
+
+ The functions of the autnomic nervous system are to keep the internal milieu of the body constant
+ (homeostasis...) or adjust it as required by changing circumstances (e.g., mechanical work, food
+ intake, water deprivation, heat or cold). %
+
+ \dsignature{W. J\"{a}nig, Autonomic Nervous System (1989) \cite{JanigW1989a}}
+\end{dquote}
+
+Within PyCMDS, the autonomic system [SECTION] handles the ``reflex'' motion that is part of active
+correction. %
+The somatic system [SECTION], on the other hand, handles the ``voluntary'' motion in the context of
+acquiring a multidimensional scan. %
+
+% BJT: consider a layout preview paragraph or two
\clearpage
\section{Graphical user interface} % =============================================================
+In this section I introduce the GUI of PyCMDS, with the goal of introducing the basic structure as
+experienced by a first time user of the software. %
+
When PyCMDS starts up, the GUI is constructed out of modules depending on which hardware and
sensors the user has instructed the program to address. %
A screenshot of the PyCMDS GUI, running on the fs table, is shown in
@@ -110,7 +157,7 @@ display. %
Each hardware knows its own limits, displayed in a tool tip when hovering over the control. %
Users cannot type values outside of hardware limits into the controls. %
Each hardware also has an ``ADVANCED'' button, which takes the user to a more extensive GUI to
-control lots more features (see section ....) %
+control lots more features [SECTION]. %
At the very top, on the left hand side, is the ``SHUT DOWN'' button. %
On the right hand side there is a extensive set of nested tabs. %
@@ -122,19 +169,9 @@ Some of these elements are themselves tabbed, like the ``Somatic'' tab (active i
At the top of the right hand side there is a progress bar and queue status display, which I will
discuss further in future sections. %
-\begin{landscape}
-\begin{figure}
- \includegraphics[scale=0.5]{"acquisition/screenshots/005"}
- \caption[PyCMDS at startup.]{
- PyCMDS at startup, on the fs system. %
- }
- \label{aqn:fig:pycmds_screenshot}
-\end{figure}
-\end{landscape}
-
When PyCMDS opens (\autoref{aqn:fig:pycmds_screenshot}), the user is first greeted with the
``Somatic/Queue'' tab on the right hand side of the GUI. %
-This is where the tells PyCMDS to do acquisitions. %
+This is where she may instruct PyCMDS to do acquisitions. %
In PyCMDS, all acquisitions are done in a queue system. %
A queue is just a list of acquisitions, where the acquisitions are carried out one by one in
order. %
@@ -142,18 +179,29 @@ order. %
To instruct PyCMDS to do an acquisition, the user must first create a queue by entering in a chosen
name (default is ``queue''), and pressing the ``MAKE NEW QUEUE'' button. %
Alternatively the user may open an existing queue using ``OPEN QUEUE''. %
-
Next, the user must add the desired acquisition(s) to the queue. %
-There are several acquisition modules, each with a different purpose. %
+There are several acquisition modules, each with a different purpose [SECTION]. %
Choose an acquisition module using the drop down menu. %
Enter a name for your acquisition, and any additional info that you might want to keep track of. %
Finally, fill out any additional information that acquisition module might require, and press
``APPEND TO QUEUE''. %
-
Once there are acquisitions in the queue, the user can press ``RUN QUEUE''. %
+
+\autoref{aqn:fig:pycmds_queue_screenshot} is a screenshot of the ``Somatic/Queue'' tab while a
+queue is in progress. %
+In this screen shot there are seven enqueued items, and PyCMDS is in the process of acquiring the
+final one (index 6). %
+For each item the status, start time, exit time, and description are shown. %
+Users may enqueue new items at any time, even while the queue is running. %
+They may delete items which are enqueued but not yet started.
+Using the green ``LOAD'' button in each row, users may populate the right hand input menu with the
+parameters from that acquisition. %
+This is useful when repeating an acquisition with slightly changed parameters, or simply when
+inspecting what parameters were used in a given item. %
+
\autoref{aqn:fig:pycmds_screenshot_during_scan} is a screenshot of PyCMDS during a representative
acquisition. %
-This time, thee ``Somatic/Scan'' tab is chosen. %
+This time, the ``Somatic/Scan'' tab is chosen. %
On the left hand side, we can see that the ``SHUT DOWN'' and ``SET'' buttons are grayed out and
unclickable, since the somatic system is in control of PyCMDS. %
At the moment when this screen shot was taken, PyCMDS is waiting for w3 (OPA-800CG) to finish
@@ -171,21 +219,51 @@ On the far right-hand side, the device and channel to display can be chosen via
Under ``Status'', the loop time and scan index help users gauge the progress of their scan. %
In this case, the displayed pixel (index 6, 40) took 2.448 seconds to acquire. %
+The other tabs are for more advanced interactions, and will be discussed further in future
+sections. %
+The ``Program'' tab contains various rarely-needed displays and inputs to configure PyCMDS. %
+The ``Hardware'' tab is where the advanced menu for each hardware appears [SECTION]. %
+The ``Devices'' tab is where sensor settings live [SECTION]. %
+The ``Autonomic'' tab is where users configure the autonomic system for active correction
+[SECTION]. %
+The ``Somatic'' tab has already been described in this section. %
+Finally, the ``Plot'' tab was intended to be a interactive, graphical post processing
+environment. %
+This functionality has not yet been implemented. %
+
+\begin{landscape}
+\begin{figure}
+ \includegraphics[scale=0.5]{"acquisition/screenshots/005"}
+ \caption[PyCMDS at startup.]{
+ PyCMDS at startup, on the fs system. %
+ }
+ \label{aqn:fig:pycmds_screenshot}
+\end{figure}
+\end{landscape}
+
+\begin{landscape}
+\begin{figure}
+ \includegraphics[width=9in]{"acquisition/screenshots/004"}
+ \caption[PyCMDS queue.]{
+ PyCMDS queue while acquiring data, on the ps system. %
+ }
+ \label{aqn:fig:pycmds_queue_screenshot}
+\end{figure}
+\end{landscape}
+
\begin{landscape}
\begin{figure}
\includegraphics[width=9in]{"acquisition/screenshots/000"}
\caption[PyCMDS while scanning.]{
- PyCMDS while acquiring data, on the ps system. %
+ PyCMDS scan tab while acquiring data, on the ps system. %
}
\label{aqn:fig:pycmds_screenshot_during_scan}
\end{figure}
\end{landscape}
-% TODO: queue figure
-
\section{Internal structure} % ===================================================================
-In this section I discuss the internal structure of PyCMDS. %
+In this section I describe the internal structure of PyCMDS. %
While there are a huge number of details not worthy of discussion (at time of writing, PyCMDS
consists of 16,582 lines of source code), PyCMDS is made to be maintained and extended by future
graduate students, so some insight into the internal structure is warranted. %
@@ -213,12 +291,12 @@ motion. %
In a single-threaded configuration, this tight loop would only run for one delay at a time, such
that PyCMDS would have to finish shepherding one delay stage before turning its attention to the
second. %
-In a multi-threaded configuration, each thread will run simultaniously, switching off CPU cycles at
-a low level far faster than human comprehension. %
+In a multi-threaded configuration, each thread will run simultaniously, switching off CPU cycles
+quickly at a low level. %
This switching is handled in an OS and hardware specific way---luckily it is all abstracted through
platform-agnostic Qt threads. %
-Threads are dangerous because it is hard to pass information between them. %
+It is hard to pass information between threads. %
Without any special protection, two threads have no reason not to simultaneously edit and read the
same location in memory. %
If a delay stage is writing its position to memory as a 64-bit double at the same time as the
@@ -247,7 +325,7 @@ Finally, PyCMDS makes extensive use of the ``signals and slots'' construct, whic
unique (and certainly original) to Qt. %
Signals and slots are powerful because they allow threads without instruction to go completely
silent, making them essentially free in terms of CPU usage. %
-Normally, a thread needs to sit in a loop merely listening for instructions. %
+Normally, a thread needs to sit in a loop to listen for instructions. %
Within the Qt framework, a thread can be ``woken'' by a signal without needing that thread to
explicitly ``listen''. %
These concepts fit within the broader umbrella of ``event-driven programming'', a concept that has
@@ -310,7 +388,7 @@ driver-specific code, typically \python{start}, \python{set} and \python{close}.
This means that code is more maintainable and less repeated. %
For example, when I added the autonomic system to PyCMDS, I edited the parent \python{Delay} class
to respect a new method \python{set_offset}. %
-I did \python{not} need to modify any of the child classes, because nothing about communicating
+I did \emph{not} need to modify any of the child classes, because nothing about communicating
with the particular delay stages, in native units, had changed. %
This allowed me to implement the core of the autonomic system in just one weekend, something that
probably would have taken weeks to do without inheritance. %
@@ -326,8 +404,8 @@ For those that want to dig deeper, most of these top level classes are defined i
\subsubsection{Data types} % ---------------------------------------------------------------------
-PyCMDS is made to be enhanced and extended by chemistry graduate students who may not have time or
-energy to learn about Mutexes, signals, slots and threads. %
+PyCMDS is made to be enhanced and extended by chemistry graduate students who may not have time,
+energy or enthusiasm to learn about Mutexes, signals, slots, and threads. %
They probably also don't have time to read Qt documentation and learn the details of GUI design and
layout. %
PyCMDS does its very best to abstract these details away from developers by offering a set of
@@ -409,8 +487,8 @@ The PyCMDS GUI must change depending on which exact hardware, sensors, and acqui
being used on a given instrument and given day. %
Internally, the GUI components are made to be modular and flexable to accommodate this
requirement. %
-
-[programmatically defined GUI]
+Rather than having each piece placed ``by hand'', the PyCMDS GUI is defined programmatically and,
+as such, the full power of abstraction and inheritance is available to the GUI-defining code. %
To keep things simple and easy to extend, PyCMDS is made up of only a few minimalist GUI
elements. %
@@ -460,6 +538,8 @@ delay stage. %
PyCMDS uses pyqtgraph \cite{pyqtgraph} for interactive plotting. %
pyqtgraph is great because it is optimized for speed and interactivity. %
+Currently only line plots are supported (through the \python{PyCMDS.project.widgets.Plot1D} class),
+but 2D plots are supported by pyqtgraph and could be added in future versions. %
For those wanting to learn more, all graphical components are defined in
\bash{PyCMDS/project/widgets.py}. %
@@ -499,6 +579,14 @@ hardware currently supported by PyCMDS. %
In general the nesting is type/model, although there can be additional levels of nesting when
required, as can be seen in the case of OPA/TOPAS/TOPAS-C and OPA/TOPAS/TOPAS-800. %
+The ``kind-defining'' classes (\python{Delay}, \python{Filter}, \python{OPA},
+\python{Spectrometer}) are particularly important. %
+Each of these defines \emph{what it means} to be that kind of hardware, as far as PyCMDS is
+concerned. %
+To put it another way, these classes are minimum viable versions of their hardware kind. %
+Each of these classes can be directly instantiated as a minimum-viable instance, which allows for
+``virtual'' hardware and offline development. %
+
\begin{figure}
\includepython{"acquisition/hardware.py"}
\caption[Parent hardware class.]{
@@ -522,8 +610,7 @@ required, as can be seen in the case of OPA/TOPAS/TOPAS-C and OPA/TOPAS/TOPAS-80
Delays are the kind of thing that have a position in absolute units, a zero position, and a
relative position measured in fs or ps. %
-They also are the kind of thing that is most commonly subject to offset by the Autonomic
-system... %
+They can be offset by the autonomic system to accommodate spectral delay correction. %
In addition to the inherited methods, delay hardware objects require the following:
\begin{ditemize}
@@ -541,12 +628,20 @@ The delay GUI, by default, offers
\item \python{on_set_motor}
\item \python{on_set_zero}
\end{ditemize}
+\autoref{aqn:fig:delay_advanced} is a screenshot of the advanced panel for one of the Newport MFA
+[CITE] delay stages. %
+This advanced panel is pretty typical. %
+Users may directly set the motor position or zero position. %
+They may also change the label. % BJT: because...
+There is a ``factor'' argument, which can be any non-zero integer (positive or negative). %
+At its simplest this factor can accommodate different directions that the stage is placed, but it
+can also account for double-passes and similar configurations. %
\begin{landscape}
\begin{figure}
\includegraphics[width=9in]{"acquisition/screenshots/006"}
\caption[Representative delay stage advanced menu.]{
- CAPTION TODO
+ Advanced menu for one of the MFA-CC (SMC-100) delay stages, on the fs system. %
}
\label{aqn:fig:delay_advanced}
\end{figure}
@@ -557,14 +652,20 @@ The delay GUI, by default, offers
Spectrometers are the kind of thing that can be set to a single color (typically native units are
in nm). %
They often have turrets that allow for switching between gratings. %
-Other features are not currently supported as PyCMDS has only been asked to drive one kind of
-monochromator so far. %
-
-Hardware:
+Other features are not currently supported as PyCMDS has only needed to drive one monochromator at
+this time. %
-Driver:
+Spectrometer hardware instances do not need any features beyond the default hardware object. %
-GUI:
+Spectrometer driver instances require the following:
+\begin{ditemize}
+ \item \python{get_grating_details}
+ \item \python{set_turret}
+\end{ditemize}
+
+\autoref{aqn:fig:spectrometer_advanced} is a screenshot of the MicroHR [CITE] advanced menu on the
+fs system. %
+Nothing can be changed in the advanced menu except the label, and the offset can be seen. %
\begin{landscape}
\begin{figure}
@@ -578,19 +679,47 @@ GUI:
\subsection{OPAs} % ------------------------------------------------------------------------------
-Hardware:
-
-Driver:
-
-GUI:
+OPAs are the most complicated piece of hardware addressed by PyCMDS. %
+They range between 3 and 6 motors. %
-\subsubsection{Curves}
+In addition to what's inherited from the parent hardware class, OPA hardware instances require the
+following:
+\begin{ditemize}
+ \item \python{@property curve}
+ \item \python{@property curve_paths}
+ \item \python{get_tune_points}
+ \item \python{home_motor}
+ \item \python{load_curve}
+ \item \python{@property motor names}
+ \item \python{run_auto_tune}
+ \item \python{set_motor}
+\end{ditemize}
-Recursive
+In addition to what's inherited from the parent driver class, OPA driver instances require the
+following:
+\begin{ditemize}
+ \item \python{bool poynting_correction}
+ \item \python{home_motor}
+ \item \python{home_all}
+ \item \python{curve}
+ \item \python{motor_names}
+ \item \python{set_motor}
+ \item \python{set_motors}
+ \item \python{interaction}
+ \item \python{load_curve}
+ \item \python{set_position_except}
+\end{ditemize}
-United
+Many of these additional features have to do with the tuning curve, a crucial feature of OPAs. %
+The tuning curve contains motor positions needed to achieve each valid output color. %
+Read more about my implementation of tuning curves in \ref{cha:opa}. %
-Interpolation
+\autoref{aqn:fig:opa_advanced} is a screenshot of the advanced menu for one of the TOPAS-C [CITE]
+OPAs on the fs table. %
+A large central plot displays the currently loaded tuning curve for one of the motors (chosen in
+the pull down menu). %
+Multiple filepath menus allow the user to specify each tuning curve. %
+Each motor can be independently set and homed. %
\begin{landscape}
\begin{figure}
@@ -602,32 +731,83 @@ Interpolation
\end{figure}
\end{landscape}
-\subsection{Filters} % ---------------------------------------------------------------------------
+\clearpage
+\section{Sensors (devices)} \label{aqn:sec:sensors} % ============================================
-Hardware:
+Sensors are the kind of things that actually measure data. %
+In spectroscopy these can be photodiodes, array detectors, photo-multiplier tubes etc. %
+In this section I describe the strategy that PyCMDS uses to represent sensors. %
-Driver:
+\subsection{The DAQ card} % ----------------------------------------------------------------------
-GUI:
+The National Instruments PCI-6251 card is capable of eight analog inputs and 1 million samples per
+second (one sample per microsecond). %
+Both instruments operate at 1 KHz, so that leaves 1000 samples per shot. %
+It is important to be able to configure all of the timings within each shot. %
-\clearpage
-\section{Sensors (devices)} \label{aqn:sec:sensors} % ============================================
+\autoref{aqn:fig:samples} shows the GUI designed to control the sample level timing of the NI
+PCI-6251 card. %
+All 1000 samples for the current shot are displayed in the large central plot. %
+Users may allocate regions of samples to be assigned to particular channels. %
+A second region may be allocated for explicit baseline subtraction. %
+For things like PMTs, make sure these two regions are the same size. % BJT: explain why
+For each region, a simple processing method is applied before the baseline is (optionally)
+subtracted and the signal is (optionally) inverted. %
+All of this results in a single processed value for each channel on each shot. %
+Users may also allocate exactly one sample for chopper monitoring. %
-Sensors are...
+\autoref{aqn:fig:shots} is a screenshot of the shots GUI. %
+Only one channel is shown, chosen by the pull down menu on the right hand side. %
+Each point is one processed value from all of the samples designated for that particular shot. %
+Because this instrument is using dual chopping at this time, only one out of four shots has a large
+amount of light, so most shots are near zero in \autoref{aqn:fig:shots}. %
-For DAQ cards, shots and samples...
+[SHOTS PROCESSING]
-Power of digital processing...
+% BJT: more about the power of digital processing
+%Old boxcar: 300 ns window, ~10 micosecond delay. Onset of saturation ~2 V.
-Old boxcar: 300 ns window, ~10 micosecond delay. Onset of saturation ~2 V.
+\begin{landscape}
+\begin{figure}
+ \includegraphics[width=9in]{"acquisition/screenshots/003"}
+ \caption{
+ CAPTION TODO
+ }
+ \label{aqn:fig:samples}
+\end{figure}
+\end{landscape}
-% TODO: screenshots
+\begin{landscape}
+\begin{figure}
+ \includegraphics[width=9in]{"acquisition/screenshots/002"}
+ \caption{
+ CAPTION TODO
+ }
+ \label{aqn:fig:shots}
+\end{figure}
+\end{landscape}
+
+\begin{figure}
+ \caption{
+ TODO: SHOTS PROCESSING SCRIPT
+ }
+\end{figure}
-\subsection{Sensors as axes} % -------------------------------------------------------------------
+\subsection{Multidimensional sensors} % ----------------------------------------------------------
-% TODO: equation from Skye
+Sensors need not be single valued at each hardware coordinate. %
+Sometimes, a sensor returns an entire array of information. %
+In cases like these, PyCMDS expands the dimensionality of the scan to accommodate the many-valued
+sensor. %
-% TODO: poweramp tune test (see darien slack)
+For example, consider \autoref{aqn:fig:array_as_axis}. %
+This simple tune test was taken with an array detector, rather than using a scanning
+monochromator. %
+Although only one piece of hardware was scanned, the data is considered to be
+\emph{two}-dimensional, with the second dimension being $\bar{\nu}_a$, the differential color axis
+for the array vs the OPA setpoint. %
+
+[EQUATION]
\begin{figure}
\includegraphics[scale=0.5]{"acquisition/tune_test"}
@@ -639,46 +819,145 @@ Old boxcar: 300 ns window, ~10 micosecond delay. Onset of saturation ~2 V.
\section{Autonomic} \label{aqn:sec:autonomic} % ==================================================
-\begin{dquote}
- The autonomic nervous system, which innervates primarily the smooth musculature of all organs,
- the heart and the glands, mediates the neuronal regulation of the internal milieu. %
- The actions of this system, as its name implies, are in general not under direct voluntary
- control. %
- These characteristics distinguish the autonomic nervous system from the somatic nervous system,
- which mediates afferent and efferent communication with the enviornment and, for the most part,
- is subject to voluntary control and accessible to consciousness. %
+The autonomic system is used to define ``reflexes'' for PyCMDS---operations that are automatically
+applied when certain conditions are met. %
+Currently the autonomic system has only functionality: \emph{offset} certain hardware as functional
+of other hardware's positions. %
- The autonomic and somatic systems operate hand in hand...
+The classic example of autonomic offsets comes from spectral delay correction (see section
+[ACT]). %
+Spectral delay refers to the small delay changes that occur when OPAs change output frequency. %
+To correct for spectral delay, the appropriate delay stages can simply be \emph{offset}. %
- The functions of the autnomic nervous system are to keep the internal milieu of the body constant
- (homeostasis...) or adjust it as required by changing circumstances (e.g., mechanical work, food
- intake, water deprivation, heat or cold). %
+In PyCMDS, the autonomic system is fully general---that is to say, any hardware can be offset
+according to any other hardware. %
+This means that spectral delay correction is possible for arbitrarily complex laser setups, and it
+means that PyCMDS is prepared for corrections that have not yet been fully implemented, such as
+automated power correction. %
- \dsignature{W. J\"{a}nig, Autonomic Nervous System (1989) \cite{JanigW1989a}}
-\end{dquote}
+Simple plain-text \bash{.coset} files define the offset arrays. %
+They are automatically generated using processing scripts in \python{attune} [CITE]. %
+Their headers prevent them from being loaded in the wrong spot. %
+These files are internally represented as instances of the \python{CoSet} class, which is capable
+of linear interpolation and extrapolation at the edges. %
-% TODO: concept of additive offsets
+A single hardware can be offset by multiple other hardwares. %
+In such cases, \emph{offsets always add}. %
+[DESCRIPTION OF FIGURE]
+
+\begin{landscape}
\begin{figure}
- \caption[Representative spectral delay correction]{
- CAPTION TODO
- }
- \label{aqn:fig:sdc}
+ \includegraphics[width=9in]{"acquisition/screenshots/009"}
+ \caption{AUTONOMIC SDC SCREENSHOT}
\end{figure}
-
+\end{landscape}
+
+\clearpage
\section{Somatic} \label{aqn:sec:somatic} % =======================================================
In contrast with the autonomic system (\autoref{aqn:sec:autonomic}), the somatic system is all
about voluntary, user specified motion. %
This is where the fun stuff happens---the acquisitions!
+PyCMDS uses the words ``scan'' and ``acquisition'' in very careful ways. %
+\begin{ditemize}
+ \item An acquisition is a single user-defined, enqueable, instruction.
+ \item A scan is a single traversal in the multidimensional hardware space. %
+\end{ditemize}
+Each scan corresponds to one \bash{.data} file, and one WrightTools \python{Data} instance (see
+section ...) %
+There can be many scans within a single acquisition. %
+And there can be many acquisitions in a queue. %
+
+PyCMDS saves the data that it is collecting within a nested folder structure
+queue/acquisition/scan. %
+A \bash{.queue} file holds everything needed to recreate the queue, \python{.aqn} files define each
+acquisition in plain text and \python{.data} files hold the multidimensional data itself. %
+
+In this section I describe each component of the somatic system in greater detail. %
+
+\subsection{Queue manager} % ---------------------------------------------------------------------
+
+The queue manager keeps track of all enqueued acquisitions, and tells each acquisition when to
+begin. %
+A singleton \python{Queue} class lives in the main thread and handles interfacing to the
+\bash{.queue} plain-text file. %
+When a user appends new acquisitions, or changes their order, the \python{queue} instance makes
+sure that those changes are reflected in the GUI and the file. %
+
+A special singleton \python{QueueStatus} keeps track of, well, the queue status: a series of
+booleans \python{go}, \python{going}, \python{pause}, \python{paused}, \python{stop}, and
+\python{stopped}. %
+The verb booleans (\python{go}, \python{pause}, \python{paused}), are control flags, to be
+written by the main thread. %
+The present particple booleans (\python{going}, \python{paused}, \python{stopped}) are flags to be
+written by the worker thread to indicate status of the current acquisition. %
+
+A singleton \python{Worker} class lives in the acquisition worker thread and carries out the actual
+operation. %
+The \python{queue} instance pushes operations to the \python{worker}, and the \python{worker} sends
+a signal that causes \python{queue.on_action_complete} to be called. %
+If there are more enqueued acquisitions, and \python{queue_status.go} is true, the \python{queue}
+instance pushes the next operation to the \python{worker} and the process starts over again. %
+
+The queue manager is capable of more than just acquisitions. %
+For example, users can enqueue a wait operation that simply pauses PyCMDS for a certain amount of
+time or until some condition is met. %
+
+Those who wish to learn more can refer to \bash{PyCMDS/somatic/queue.py}. %
+
\subsection{Scans} % -----------------------------------------------------------------------------
-The central loop of scans in PyCMDS. %
+Every single scan within PyCMDS is handled by one method of one class, \python{Worker.scan}
+from the file \bash{PyCMDS/somatic/acquisition.py}. %
+This method understands how to any scan that PyCMDS can do: any stepwise multidimensional scan with
+separate hardware and sensors. %
+
+The central scan method requires acquisition modules to provide all of the axes (instances of
+\python{PyCMDS.somatic.acquisition.Axis}) that need to be broadcast across each-other. %
+Then something very simple happens. %
+For each hardware that will move during the scan, a destinations object (instance of
+\python{PyCMDS.somatic.acquisition.Destinations}) is created. %
+This object has the same shape as the full multidimensional scan, and contains the destination for
+that hardware for that pixel in the scan. %
+Then, a \bash{.data} file is created to accept the data that is about to be collected. %
+A bunch of signals go off, telling PyCMDS that it needs to yield to somatic control. %
+Then PyCMDS simply sits in a loop generated by \python{numpy.ndindex} [CITE] and visits each pixel
+in turn. %
+\python{ndindex} is a n-dimensional iterator over a given array shape. %
+Written simply, it does the following:
+\begin{codefragment}{python}
+def ndindex(shape):
+ rs = [range(s) for s in shape]
+ pools = map(tuple, rs)
+ result = [[]]
+ for pool in pools:
+ result = [x+[y] for x in result for y in pool]
+ for prod in result:
+ yield tuple(prod)
+\end{codefragment}
+So that when evaluated:
+\begin{codefragment}{python}
+>>> for idx in ndindex((4, 3, 2)): print idx
+(0, 0, 0)
+(0, 0, 1)
+(0, 1, 0)
+(0, 1, 1)
+(0, 2, 0)
+(0, 2, 1)
+(1, 0, 0)
+...
+(3, 2, 0)
+(3, 2, 1)
+\end{codefragment}
+
+This simple algorithm is used to visit each pixel in the entire PyCMDS scan space. %
+At each pixel, something much like the following happens. %
\begin{codefragment}{python, label=aqn:lst:loop_simple}
-for coordinates in list_of_coordinates:
- for hardware, coordinate in zip(hardwares, coordinates):
- hardware.set(coordinate)
+for idx in ndindex(shape):
+ for hardware in hardwares::
+ hardware.set(idx)
for hardware in hardwares:
hardware.wait_until_still()
for sensor in sensors:
@@ -686,6 +965,8 @@ for coordinates in list_of_coordinates:
for sensor in sensors:
sensor.wait_until_done()
\end{codefragment}
+The pattern is simple: launch hardware, wait for still, launch sensors, wait for done. %
+The simplicity of this central loop truly shows the power of abstraction in PyCMDS. %
\subsection{Acquisition modules} % ---------------------------------------------------------------
@@ -731,20 +1012,6 @@ Automatically do appropriate scans and process as in chapter...
Dedicated to poynting (get content from Kyle S)...
-z\subsection{Queue manager} % ---------------------------------------------------------------------
-
-\subsection{The central loop of PyCMDS} % --------------------------------------------------------
-
-\subsection{The data file} % ---------------------------------------------------------------------
-
-Does not have the same dimensionality restrictions as prior acquisition software. %
-
-Self describing (enabled by \python{tidy_headers}).
-
-\subsection{Automatic processing} % --------------------------------------------------------------
-
-For scan module, just
-
\clearpage
\section{Conditional validity} % =================================================================
@@ -785,15 +1052,13 @@ Conceptually, can imagine a 4 quadrant system. %
Thus PyCMDS can be proud to try and generalize the hardware-complex part of acquisition software
because indeed that is all that can be generalized. %
-\begin{figure}
- \caption{
- CAPTION TODO: 4 QUADRANTS OF COMPLEXITY
- }
- \label{aqn:fig:complexity_quandrants}
-\end{figure}
-
+\clearpage
\section{Integrations} % =========================================================================
+[GOOGLE DRIVE]
+
+[SLACK]
+
\begin{figure}
\frame{\includegraphics[width=\textwidth]{"acquisition/slack"}}
\caption[TODO]{
diff --git a/acquisition/quad.png b/acquisition/quad.png
index 3b1c7f6..ea933da 100644
--- a/acquisition/quad.png
+++ b/acquisition/quad.png
Binary files differ
diff --git a/acquisition/quad.py b/acquisition/quad.py
index d6519e5..ee5fab9 100644
--- a/acquisition/quad.py
+++ b/acquisition/quad.py
@@ -21,19 +21,30 @@ here = os.path.abspath(os.path.dirname(__file__))
fig, gs = wt.artists.create_figure(width='double')
ax = plt.subplot(gs[0, 0])
-ax.set_xlim(-1.1, 1.1)
-ax.set_ylim(-1.1, 1.1)
-
-ax.arrow(-1, 0, 2, 0, lw=5, head_width=0.1)
-ax.arrow(0, -1, 0, 2, lw=5, head_width=0.1)
+ax.set_xlim(0, 1.25)
+ax.set_ylim(0, 1.25)
es = {}
-es['MR-CMDS'] = (-0.5, 0.5)
+es['MR-CMDS'] = (1, 0.3)
+es['AFM'] = (0.5, 0.4)
+es['GRAPES'] = (0.1, 1)
+es['FTIR'] = (0.1, 0.1)
+es['z-scan'] = (0.1, 0.2)
+es['UV-VIS'] = (0.1, 0.3)
+es['TRPL'] = (0.1, 0.4)
+es['NMR'] = (0.1, 0.5)
+
+
for label, coordinates in es.items():
ax.text(*coordinates, label, fontsize=20)
+# decoration
+xlabel = r'hardware complexity $\rightarrow$'
+ylabel = r'measurement complexity $\rightarrow$'
+wt.artists.set_ax_labels(xlabel=xlabel, ylabel=ylabel, xticks=False, yticks=False)
+
# save
p = os.path.join(here, 'quad.png')
wt.artists.savefig(p)
diff --git a/acquisition/screenshots/009.PNG b/acquisition/screenshots/009.PNG
new file mode 100644
index 0000000..236acdc
--- /dev/null
+++ b/acquisition/screenshots/009.PNG
Binary files differ