diff --git a/README.md b/README.md index 32fec90..303e346 100644 --- a/README.md +++ b/README.md @@ -112,10 +112,10 @@ install as a special kernel when you are the user. found [here](https://janakiev.com/til/jupyter-virtual-envs/). ## Change Log -* 0.6.0dev +* 0.6.0 (Mar. 29, 2023) * Documentation updates including Gutow Lab Standard Operating Procedures (SOPs). - * Refactored everything to underneath the module `Trough`. + * Refactored everything to inside the module `Trough`. * 0.5.2 (Mar. 16, 2023) Now works in Jupyter Lab. * Adjusted widget updating/clearing to work in Jupyter lab. * Added JupyterLab >= 3.6.1 to requirements. @@ -128,6 +128,9 @@ install as a special kernel when you are the user. ## Known issues * 0.5.0 - 0.6.0 The estimated error on values converted to metric units based on calibration fits appears to be too pessimistic. +* Inconsistent rendering of Latex ipywidget labels with ipywidgets >= 8.0. + Until figured out requiring ipywidgets < 8.0. +* Runs don't label graph axes reliably for x-axis units other than cm. ## Development diff --git a/docs/Gutow_Lab_Trough_SOPs.md b/docs/Gutow_Lab_Trough_SOPs.md index a80c155..7a69f06 100644 --- a/docs/Gutow_Lab_Trough_SOPs.md +++ b/docs/Gutow_Lab_Trough_SOPs.md @@ -20,6 +20,7 @@ ## Checking Trough and Subphase Cleanliness **This need to be done before each experiment.** + 1. We usually use high-purity water as the subphase. Primarily this is 18+ MΩ de-ionized water mixed with KMnO4 and redistilled. Depending on the status of the water polishers, it is sometimes possible @@ -100,6 +101,7 @@ ## Handling Spreading Solvent(s) **It is extremely easy to contaminate the solvents with surface active compounds at a level that will ruin experiments** + * Generally HPLC grade solvents are adequately clean. We most commonly use HPLC grade hexanes and absolute ethanol. * All glassware must be carefully cleaned before using to transfer or @@ -137,6 +139,7 @@ compounds at a level that will ruin experiments** For most molecules we want to spread about 3.00 X 10-8 moles of molecules on our trough to get a range of roughly 60 to 15 square Angstroms per molecule during a compression. + 1. The ideal volume to spread is 50 µL of solution. Thus we want a concentration near (3.00 X 10-8 moles)/(50.0 X 10-6 L) = 6 X 10-4 M. It is practical to spread anywhere between 20 @@ -213,6 +216,7 @@ molecule during a compression. ## Calibrating the Wilhelmy Balance **This should be done at the beginning of any day real data is collected** + 1. If it is not already running launch the trough control and calibration tool by running the command `Trough_GUI.Controls(Trough_GUI.calibrations) ` in an empty notebook cell. @@ -222,6 +226,7 @@ molecule during a compression. ## Calibrating Barrier Position and Speed **This only needs to be done if a check of the measured barrier separation is off by more than ±0.03 mm** + 1. If it is not already running launch the trough control and calibration tool by running the command `Trough_GUI.Controls(Trough_GUI.calibrations) ` in an empty notebook cell. @@ -230,6 +235,7 @@ is off by more than ±0.03 mm** ## Calibrating the Temperature Probe. **This is very stable so should not need to be done often** + 1. If it is not already running launch the trough control and calibration tool by running the command `Trough_GUI.Controls(Trough_GUI.calibrations) ` in an empty notebook cell. diff --git a/docs/Trough.html b/docs/Trough.html new file mode 100644 index 0000000..746cdd6 --- /dev/null +++ b/docs/Trough.html @@ -0,0 +1,820 @@ + + + + + + + Trough API documentation + + + + + + + + + + + + + +
+
+

+Trough

+ +

Langmuir Trough

+ +

This software is a custom controller and GUI for the research Langmuir trough +in the Gutow Lab at UW Oshkosh. It is written in Python and expects to run in a +Jupyter notebook environment. However, all of the parts that are not elements +of the user interface should work in a vanilla Python environment.

+ +

Hardware requirements: +Raspberry Pi compatible system with a Pi-Plates +DAQC2 data acquisition plate +and a trough controlled by the DAQC2 plate. This software could be used with +a trough controlled some other way by rewriting the routines in trough_util. +py. The GUI front end would need no rewriting to use with a different +trough if a custom backend controlling the barriers, reading the temperature +and Whilhelmy balance is written. The backend needs to continually monitor +the trough and respond to the following commands: Stop, Send, Start, +Direction, Speed, MoveTo, MotorCal, ConstPi, DataLabels, ShutDown.

+ +

If you do not have compatible hardware the GUI will run with a simulated +trough, allowing you to see how it works.

+ +

Usage

+ +

Once installed:

+ +
    +
  1. Turn on the power supply for the trough.
  2. +
  3. In a terminal navigate to the directory containing the trough software.
  4. +
  5. Start the virtual environment pipenv shell.
  6. +
  7. Launch Jupyter jupyter notebook (jupyter lab also works and is now +more stable).
  8. +
  9. Create a folder for the new day using the New menu near the top right +of the Jupyter browser page. Give it an appropriate name.
  10. +
  11. Switch to that folder by clicking on it.
  12. +
  13. Start a new ipython notebook using the New menu. Give it a +name that describes the experiment.
  14. +
  15. In the first cell initialize the trough by running the command from +Trough import Trough_GUI. This will take a while to run the first time +it is run each day because it needs to check the movement of the barriers.
  16. +
  17. To control and monitor the trough or do calibrations run the command +Trough_GUI.Controls(Trough_GUI.calibrations)
  18. +
  19. Do not do any real runs without making sure the calibrations are correct.
  20. +
  21. To start data collection (a run) run the command +Trough_GUI.Collect_data.Run("name_for_run"), +where you replace name_for_run with the text for the name of the run (no +spaces).
  22. +
  23. Set the run conditions.
  24. +
  25. You can start data collection by clicking the green "Run" button.
  26. +
  27. If you set the speed to zero the data collection will be displayed +versus time and will not stop until you click the red "Stop" button.
  28. +
+ +

Installation

+ +

OS setup - Ubuntu on Pi

+ +

By default in Ubuntu 20.04 for Pis the gpio and spi groups do not exist. +The i2c group does (not always).

+ +
    +
  1. Make sure that the following packages are installed rpi.gpio-common +python3-pigpio python3-gpiozero python3-rpi.gpio.
  2. +
  3. You can avoid having to create a gpio group, by assigning users who need + gpio access to the dialout group. Check that /dev/gpiomem is part of that +group and that the dialout group has rw access. If not you will need to set + it.
  4. +
  5. Users also need to be members of the i2c group. If it does not exist create + it and then make that the group for /dev/i2c-1 with group rw permissions. +THIS MAY NOT BE NECESSARY.
  6. +
  7. The spi group needs to be created (addgroup?).
  8. +
  9. Additionally the spi group needs to be given rw access to the spi devices +at each boot. To do this create a one line rule in a file named +/etc/udev/rules.d/50-spidev.rules containing SUBSYSTEM=="spidev", +GROUP="spi", MODE="0660". The file should have rw permission for root +and read permission for everyone else.
  10. +
  11. Make sure you have pip installed for +python 3: python3 -m pip --version or pip3 --version. If you do not, +install using apt +install python3-pip.
  12. +
+ +

Trough Software Installation

+ +

To avoid library conflicts the software should be installed into a virtual environment. +Instructions for doing this using pipenv +follow.

+ +

Log into your chosen user account:

+ +
    +
  1. Install pipenv: pip3 install +--user pipenv. You may +need to add ~/.local/bin to your PATH to make pipenv +available in your command shell. More discussion: +The Hitchhiker's Guide to +Python.
  2. +
  3. Create a directory for the virtual environment you will be installing +into (example: $ mkdir Trough).
  4. +
  5. Navigate into the directory $ cd Trough.
  6. +
  7. Create the virtual environment and enter it $ pipenv shell. To get out of +the environment you can issue the $ exit command on the command line.
  8. +
  9. While still in the shell install the latest trough software and all its +requirements + $ pip install -U langmuir_trough.
  10. +
  11. Still within the environment shell test +this by starting jupyter $ jupyter notebook. Jupyter should launch in your +browser. +
      +
    1. Open a new notebook using the default (Python 3) kernel.
    2. +
    3. In the first cell import the Trough_GUI: +from Trough import Trough_GUI. + When run this cell sets things up and tries to talk to the trough.
    4. +
  12. +
  13. If you wish, you can make this environment available to an alternate Jupyter +install as a special kernel when you are the user. +
      +
    1. Make sure you are running in your virtual environment $ pipenv shell +in the directory for virtual environment will do that.
    2. +
    3. Issue the command to add this as a kernel to your personal space: +$ python -m ipykernel install --user --name=<name-you-want-for-kernel>.
    4. +
    5. More information is available in the Jupyter/Ipython documentation. +A simple tutorial from Nikolai Jankiev (_Parametric Thoughts_) can be +found here.
    6. +
  14. +
+ +

Change Log

+ +
    +
  • 0.6.0 (Mar. 29, 2023) +
      +
    • Documentation updates including Gutow Lab Standard Operating Procedures +(SOPs).
    • +
    • Refactored everything to inside the module Trough.
    • +
  • +
  • 0.5.2 (Mar. 16, 2023) Now works in Jupyter Lab. +
      +
    • Adjusted widget updating/clearing to work in Jupyter lab.
    • +
    • Added JupyterLab >= 3.6.1 to requirements.
    • +
  • +
  • 0.5.1 (Mar. 9, 2023) +
      +
    • Include spidev package in requirements.
    • +
    • More details reported when unable to "find trough".
    • +
  • +
  • 0.5.0 (Mar. 4, 2023) First version with working GUI
  • +
  • 0.1.0 First pypi compatible package version.
  • +
+ +

Known issues

+ +
    +
  • 0.5.0 - 0.6.0 The estimated error on values converted to metric units +based on calibration fits appears to be too pessimistic.
  • +
  • Inconsistent rendering of Latex ipywidget labels with ipywidgets >= 8.0. +Until figured out requiring ipywidgets < 8.0.
  • +
  • Runs don't label graph axes reliably for x-axis units other than cm.
  • +
+ +

Development

+ +

CodeRepository | Docs

+ +
    +
  1. For development purposes clone the GIT repository.
  2. +
  3. Create the virtual environment to run it in within the development +directory pipenv shell.
  4. +
  5. Within the shell pip install for development pip install -e ..
  6. +
+ +

Constructing the Documentation

+ +
    +
  1. Make sure pdoc is installed and updated in the virtual environment pip +install -U pdoc.
  2. +
  3. Update any .md files included in _init_.py. +
      +
    • Generally URLs should be absolute, not relative.
    • +
  4. +
  5. At the root level run pdoc pdoc --logo-link +https://gutow.github.io/Langmuir_Trough/ --footer-text "Langmuir_Trough vX.X.X" +--math -html -o docs Trough where X.X.X is the version number.
  6. +
  7. Because of the way the document building process works the background tasks +will be started. You will have to stop the document build after the +documentation is done building (watch the doc folder) with a ^C to +terminate it.
  8. +
+ +

Releasing on PyPi

+ +

Proceed only if testing of the build is successful.

+ +
    +
  1. Update packaging software pip install -U setuptools wheel twine
  2. +
  3. Double check the version number in setup.py.
  4. +
  5. Rebuild the release: python -m setup sdist bdist_wheel.
  6. +
  7. Upload it: python -m twine upload dist/*
  8. +
  9. Make sure it works by installing it in a clean virtual environment. pip +install -U .... Copy the actual link from pypi.org. +`. If it does not work, pull the release.
  10. +
+ +

Ideas/Things to do

+ +
    +
  • Make more robust by wrapping data collection in try ... so that it can +exit more gracefully and give up barrier monitoring?
  • +
  • Add explanation of how to use the barrier watch deamon to prevent barrier +crashing if software fails.
  • +
+ +

Langmuir Trough Standard Operating Procedures for the Gutow Lab

+ +

Initialization

+ +
    +
  1. Check that recirculating temperature controller is connected to the +trough. Then turn it on and verify that the temperature is set to what +you want. Stabilization time is about 20 minutes for temperatures near +room temperature.
  2. +
  3. Turn on power to the trough.
  4. +
  5. Open a terminal and navigate to the Trough directory of the user +Trough.
  6. +
  7. Activate the trough python environment pipenv shell
  8. +
  9. Launch Jupyter Lab jupyter lab.
  10. +
  11. Within Jupyter Lab create a new folder for the Day. Name it something +like "DescriptiveWord_MMM_DD_YYYY", where MMM = three letter month +abbreviation, DD = day of the month and YYYY = the year.
  12. +
  13. Open the folder by clicking on it.
  14. +
  15. Open a new Notebook. Give it a descriptive name.
  16. +
  17. In the first cell run the command from Trough import Trough_GUI. If the +trough has not been started in the last 12 hours this will take a while +as it checks the motor calibration for moving the barriers.
  18. +
+ +

Checking Trough and Subphase Cleanliness

+ +

This need to be done before each experiment.

+ +
    +
  1. We usually use high-purity water as the subphase. Primarily this is +18+ MΩ de-ionized water mixed with KMnO4 and redistilled. +Depending on the status of the water polishers, it is sometimes possible +to use 18+ MΩ water from these directly.
  2. +
  3. If the trough is already filled with subphase (1 - 1.5 mm above trough +edges) and the Wilhelmy plate is installed skip steps 3 - 6.
  4. +
  5. Calibrate the Wilhelmy balance +if necessary.
  6. +
  7. Hang a clean filter paper Wilhelmy plate from a fine wire on the balance. +Make sure that you know the circumference of the plate in mm. This should be +recorded in the Jupyter Notebook you are running. Our default +circumference is 21.5 mm.
  8. +
  9. The subphase should fill the trough so that it rises 1 - 1.5 mm above the +edges of the trough. To add subphase use the clean glass funnel in the trough +isolation box to pour through (pouring directly from a bottle splashes). +The funnel makes it much easier to add subphase when the polycarbonate lid +with just a small opening is in use. Always add subphase between the +barriers to trap any surface active species between them for easier removal.
  10. +
  11. Adjust the height of the Wilhelmy balance so the plate is partially +submerged in the subphase. The balance settling time is long. You will +have to wait at least 1 minute before any measurements will be valid. +With a reasonably clean trough and subphase the unzeroed balance should +settle to a surface pressure < 10 mN/m. If it does not or shows no noise, +there may be a problem.
  12. +
  13. If necessary initialize the trough then start the +trough control and calibration tool by running the command +Trough_GUI.Controls(Trough_GUI.calibrations) in an empty cell of the +notebook.
  14. +
  15. Expand the "Manual Barrier Control" accordian. Set the direction to +"open". Set the speed to maximum (~10 cm/min). Click the start button. +Watch the surface pressure indicator. When the barriers stop (~12.7 cm +separation), wait to make sure the surface pressure has stabilized.
  16. +
  17. Switch the direction to "close". Set the speed to the maximum closing +speed (~6.8 cm/min). Click the start button. Watch the surface pressure +indicator.
  18. +
  19. Once the barriers are fully closed (~2.8 cm separation), check the +surface pressure. If it is greater than it was when fully open carefully +aspirate the surface between the barriers without catching the Wilhelmy +plate until the surface pressure is slightly less than observed for the +open barriers.
  20. +
  21. Repeat steps 8 - 10 up to 4X to get the surface clean. If it is still +not clean: +
      +
    1. Raise the Wilhelmy balance carefully and rotate it aside. Make +sure to lock it in place.
    2. +
    3. Remove the polycarbonate lid if it is in place. Store it so that it +does not get contaminated.
    4. +
    5. Aspirate all the subphase out of the trough and try again.
    6. +
  22. +
  23. If after a second try the trough and subphase are still not clean the +trough probably needs to be cleaned.
  24. +
  25. When it appears clean test: +
      +
    1. Manually open the barriers all the way.
    2. +
    3. Set up a run by executing the command +Trough_GUI.Collect_Data.Run("XXX"), where XXX is replaced with a +name for the run (e.g. "clean_test_MMM_DD_YYYYa") in an empty cell.
    4. +
    5. Set the units to cm separation. Set the speed to 1 cm/min. Set the +final separation to the minimum for the trough (~2.86 cm).
    6. +
    7. When the surface pressure is stable click on the "zero pressure" +button to tare the Wilhelmy balance.
    8. +
    9. Click start. The run will stop when the barriers reach the target +separation. You can also stop the collection by clicking the "stop" +button.
    10. +
    11. If the surface pressure stays between -0.2 and +0.2 mN/m the trough +is adequately clean.
    12. +
  26. +
+ +

Storage of Trough Between Runs

+ +
    +
  • If the trough is being used regularly (1X/week or more): store the trough +with clean subphase in it. If the subphase is water make sure that the +humidification beaker in the isolation box is kept about 50% full.
  • +
  • If the trough will be unused for a significant time: +
      +
    1. After verifying the trough and subphase cleanliness +aspirate off all the subphase.
    2. +
    3. Empty the humidification beaker.
    4. +
    5. Cover the trough with the polycarbonate lid.
    6. +
    7. Make sure the isolation box is closed.
    8. +
    9. Make sure the power supply is off.
    10. +
    11. Shut down the computer.
    12. +
  • +
+ +

Handling Spreading Solvent(s)

+ +

It is extremely easy to contaminate the solvents with surface active +compounds at a level that will ruin experiments

+ +
    +
  • Generally HPLC grade solvents are adequately clean. We most commonly use +HPLC grade hexanes and absolute ethanol.
  • +
  • All glassware must be carefully cleaned before using to transfer or +contain spreading solvents. +
      +
    1. If unsure of basic cleanliness wash well with soap and water. Rinse +five (5) times with warm tap water. Rinse three (3) times with +de-ionized water.
    2. +
    3. Rinse two (2) times with absolute ethanol (10% - 20% container volume per +rinse).
    4. +
    5. Rinse six (6) times with the spreading solvent (10% - 20% container volume +per rinse).
    6. +
  • +
  • Do not stick anything into the clean spreading solvent stock bottle. Get +samples to work with by pouring into properly cleaned intermediate containers.
  • +
+ +

Checking Spreading Solvent Cleanliness

+ +
    +
  1. Transfer < 1 mL of spreading solvent to a +properly cleaned vial.
  2. +
  3. Initialize the trough and +verify that the subphase is clean.
  4. +
  5. Using the "Manual Barrier Controls" open the barriers all the way.
  6. +
  7. Rinse the positive displacement microdispenser 3X with absolute ethanol +from a TFE squeeze bottle and then 3X with HPLC grade hexanes from a TFE +squeeze bottle.
  8. +
  9. Rinse with the solvent sample being tested 6X by sucking up 90 µL +of the solvent sample and dispensing it into a waste beaker.
  10. +
  11. Dispense 90 µL of the solvent sample onto the surface between the +barriers.
  12. +
  13. Allow to evaporate (15 min is adequate for hexanes).
  14. +
  15. Perform a compression at 1 cm/min from fully +open to fully closed.
  16. +
  17. The solvent is clean if the surface pressure stays between -0.2 and +0.2 +mN/m.
  18. +
+ +

Making a Spreading Solution

+ +

For most molecules we want to spread about 3.00 X 10-8 moles of +molecules on our trough to get a range of roughly 60 to 15 square Angstroms per +molecule during a compression.

+ +
    +
  1. The ideal volume to spread is 50 µL of solution. Thus we want a +concentration near (3.00 X 10-8 moles)/(50.0 X 10-6 L) += 6 X 10-4 M. It is practical to spread anywhere between 20 +and 90 µL. So, you can adapt to concentrations that vary between 1.00 +x 10-3 M and 3.3 X 10-4 M.
  2. +
  3. Ideally your molecule will dissolve in pure hexanes at a concentration of +6 X 10-4 M. If it is not soluble you can put a few percent (up +to 5% v/v) of ethanol in with the hexanes. This solvent mixture works for +many surfactants, without significantly impacting the surface tension of +a water subphase.
  4. +
  5. Experiments take very little solution, so make as small volumes of +solution as possible. Note that you should not try to measure out +surfactant in amounts that produce less than three significant figures on +a standard analytical balance (e.g. at least 10 mg, preferably 50 mg or +more.) This may mean that you will have to make a stock solution and +dilute it to get in the correct concentration range.
  6. +
  7. All solutions must be made using +properly cleaned glassware and spreading +solvents that have been +verified to be clean. Use +volumetric flasks with ground glass stoppers to avoid contamination by +the plasticizers found in most polymer caps.
  8. +
  9. Because the solvents are very volatile the solutions will not keep long +in the volumetric flasks with ground glass stoppers. They can be +transferred for somewhat longer term storage to sealed brown bottles +if the bottles are +properly washed +and you have verified that a little solvent stored in the bottle +overnight and shaken stays clean.
  10. +
+ +

Spreading a Sample

+ +
    +
  1. Rinse a small vial 2X with absolute ethanol from a TFE squeeze bottle +then 3X with hexanes from a TFE squeeze bottle.
  2. +
  3. If you need to use a pipette or funnel (the funnel is a better choice as +you are less likely to contaminate the stock spreading solution) to transfer +the spreading solution to the vial rinse the pipette or funnel 2X with +absolute ethanol from a TFE squeeze bottle and then 3X with hexanes from +a TFE squeeze bottle.
  4. +
  5. Rinse the transfer tool with the spreading solution 6X.
  6. +
  7. Rinse the vial 6X (10-20% of vial volume) with the spreading solution.
  8. +
  9. Use the transfer tool to transfer about 1 mL of the spreading solution to +the small vial.
  10. +
  11. Set the positive displacement dispenser to the volume you will be +dispensing.
  12. +
  13. Rinse the dispenser 2X with absolute ethanol from a TFE squeeze bottle +then 3X with hexanes from a TFE squeeze bottle. Make sure you move the +plunger through its dispensing motion while doing this.
  14. +
  15. When the dispenser is dry, rinse 6X with the spreading solution making +sure to take up the full amount to be dispensed on each rinse.
  16. +
  17. With the barriers fully open dispense the spreading solution drop wise +onto the surface between the barriers. Avoid the Wilhelmy plate.
  18. +
  19. Allow time for the solvent to evaporate (~ 15 minutes for hexanes) +before doing a compression.
  20. +
+ +

Running a Compression

+ +
    +
  1. Trough must first be +verified to be clean.
  2. +
  3. Spread the surfactant solution on the trough with the barriers open. +Allow sufficient time for the solvent to evaporate (~15 min for hexanes). +The amount to spread will depend on your target range for area per +molecule and the concentration of your solution (10-4 - +10-3 M is typical).
  4. +
  5. In a new notebook cell execute the command +Trough_GUI.Collect_Data.Run("XXX"), where XXX is replaced with a + name for the run (e.g. "CompoundName_MMM_DD_YYYYa")
  6. +
  7. Adjust the moles of molecules to the moles of surfactant you spread. +Adjust the units to Angstroms squared per molecule. Choose your desired +final target area and compression speed.
  8. +
  9. When the solvent is fully evaporated zero the balance.
  10. +
  11. Store the settings.
  12. +
  13. When ready click the "Start" button. The collection will stop when the +desired area is reached. You can also stop the run by clicking the "Stop" +button.
  14. +
+ +

Calibrating the Wilhelmy Balance

+ +

This should be done at the beginning of any day real data is collected

+ +
    +
  1. If it is not already running launch the trough control and calibration +tool by running the command Trough_GUI.Controls(Trough_GUI.calibrations) + in an empty notebook cell.
  2. +
  3. Expand the "Calibrate Balance" accordian and follow the on screen +instructions.
  4. +
+ +

Calibrating Barrier Position and Speed

+ +

This only needs to be done if a check of the measured barrier separation +is off by more than ±0.03 mm

+ +
    +
  1. If it is not already running launch the trough control and calibration +tool by running the command Trough_GUI.Controls(Trough_GUI.calibrations) + in an empty notebook cell.
  2. +
  3. Expand the "Calibrate Barriers" accordian and follow the on screen +instructions.
  4. +
+ +

Calibrating the Temperature Probe.

+ +

This is very stable so should not need to be done often

+ +
    +
  1. If it is not already running launch the trough control and calibration +tool by running the command Trough_GUI.Controls(Trough_GUI.calibrations) + in an empty notebook cell.
  2. +
  3. Expand the "Calibrate Temperature" accordian and follow the on screen +instructions.
  4. +
  5. A good source of known temperatures is the thermostat recirculator.
  6. +
+ +

Cleaning the Trough

+ +
    +
  1. The cleaning solution 1:1 concentrated nitric acid:concentrated sulfuric +acid is extremely dangerous and also has potential to damage parts of the +trough. Do not perform this cleaning procedure until Dr. Guto has +certified you for the process.
  2. +
  3. The trough can be powered down during this procedure.
  4. +
  5. The Wilhelmy balance should be locked in position out of the way.
  6. +
  7. The polycarbonate lid should be removed (store it so that does not get +contaminated).
  8. +
  9. Fill the trough with the 1:1 concentrated nitric:sulfuric acid solution. +Allow to sit 10 + minutes.
  10. +
  11. While the cleaning solution sits in the trough make sure the aspirator +trap is dry.
  12. +
  13. Aspirate off the cleaning solution. +
      +
    • Unless the trough is extremely dirty the collected cleaning +solution may be returned to the cleaning solution storage bottle.
    • +
    • If disposing of the cleaning solution treat it as strong acid waste and +neutralize properly.
    • +
  14. +
  15. Rinse the trough twice with clean water subphase.
  16. +
  17. Check the cleanliness of the trough
  18. +
+
+ + + + + +
1"""
+2.. include:: ../README.md
+3.. include:: ../docs/Gutow_Lab_Trough_SOPs.md
+4"""
+5__docformat__ = "numpy"
+
+ + +
+
+ + \ No newline at end of file diff --git a/docs/Trough/Trough_Control.html b/docs/Trough/Trough_Control.html new file mode 100644 index 0000000..e56001d --- /dev/null +++ b/docs/Trough/Trough_Control.html @@ -0,0 +1,276 @@ + + + + + + + Trough.Trough_Control API documentation + + + + + + + + + + + + + +
+
+

+Trough.Trough_Control

+ + + + + + +
1from Trough.Trough_Control import trough_util, message_utils
+2from threading import Lock
+3trough_lock = Lock()
+4TROUGH = None
+5cmdsend = None
+6datarcv = None
+
+ + +
+
+ + \ No newline at end of file diff --git a/docs/Trough/Trough_GUI.html b/docs/Trough/Trough_GUI.html new file mode 100644 index 0000000..48ada34 --- /dev/null +++ b/docs/Trough/Trough_GUI.html @@ -0,0 +1,311 @@ + + + + + + + Trough.Trough_GUI API documentation + + + + + + + + + + + + + +
+
+

+Trough.Trough_GUI

+ + + + + + +
 1# Start up the trough if necessary
+ 2from Trough import Trough_Control
+ 3from IPython import get_ipython
+ 4# Allow building of documentation by not loading if not in IPython
+ 5if get_ipython():
+ 6    user_ns = get_ipython().user_ns
+ 7    user_ns["Trough_Control"] = Trough_Control
+ 8if not Trough_Control.trough_util.is_trough_initialized():
+ 9    Trough_Control.cmdsend, Trough_Control.datarcv, \
+10    Trough_Control.TROUGH = Trough_Control.trough_util.init_trough()
+11
+12# Place to store runs
+13runs = []
+14
+15from multiprocessing import Value
+16from ctypes import c_bool
+17#  last direction barriers moved -1 closing, 0 unknown, 1 opening
+18lastdirection = Value('i', 0)
+19run_updater = Value(c_bool, True)
+20updater_running = Value(c_bool, False)
+21
+22from . import status_widgets, calibration_utils, Collect_data
+23
+24calibrations = calibration_utils.Calibrations()
+25
+26# Now we should be able to import Monitor_Calibrate
+27from .Monitor_Calibrate import Monitor_Setup_Trough as Controls
+28from .status_widgets import start_status_updater
+29from threading import Thread
+30status_update_thread = Thread(target=status_widgets.status_updater,
+31                              args=(Trough_Control.trough_lock,
+32                                    Trough_Control.cmdsend,
+33                                    Trough_Control.datarcv,
+34                                    calibrations,
+35                                    lastdirection,
+36                                    run_updater,
+37                                    updater_running))
+38status_update_thread.start()
+
+ + +
+
+ + \ No newline at end of file diff --git a/docs/search.js b/docs/search.js index c812290..44600f6 100644 --- a/docs/search.js +++ b/docs/search.js @@ -1,6 +1,6 @@ window.pdocSearch = (function(){ /** elasticlunr - http://weixsong.github.io * Copyright (C) 2017 Oliver Nightingale * Copyright (C) 2017 Wei Song * MIT Licensed */!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();oLangmuir Trough\n\n

This software is a custom controller and GUI for the research Langmuir trough \nin the Gutow Lab at UW Oshkosh. It is written in Python and expects to run in a\nJupyter notebook environment. However, all of the parts that are not elements\nof the user interface should work in a vanilla Python environment.

\n\n

Hardware requirements:\nRaspberry Pi compatible system with a Pi-Plates \nDAQC2 data acquisition plate \nand a trough controlled by the DAQC2 plate. This software could be used with \na trough controlled some other way by rewriting the routines in trough_util.\npy. The GUI front end would need no rewriting to use with a different \ntrough if a custom backend controlling the barriers, reading the temperature \nand Whilhelmy balance is written. The backend needs to continually monitor \nthe trough and respond to the following commands: Stop, Send, Start, \nDirection, Speed, MoveTo, MotorCal, ConstPi, DataLabels, ShutDown.

\n\n

If you do not have compatible hardware the GUI will run with a simulated \ntrough, allowing you to see how it works.

\n\n

Usage

\n\n

Once installed:

\n\n
    \n
  1. Turn on the power supply for the trough.
  2. \n
  3. In a terminal navigate to the directory containing the trough software.
  4. \n
  5. Start the virtual environment pipenv shell.
  6. \n
  7. Launch Jupyter jupyter notebook (jupyter lab also works and is now \nmore stable).
  8. \n
  9. Create a folder for the new day using the New menu near the top right \nof the Jupyter browser page. Give it an appropriate name.
  10. \n
  11. Switch to that folder by clicking on it.
  12. \n
  13. Start a new ipython notebook using the New menu. Give it a\nname that describes the experiment.
  14. \n
  15. In the first cell initialize the trough by running the command from \nTrough import Trough_GUI. This will take a while to run the first time \nit is run each day because it needs to check the movement of the barriers.
  16. \n
  17. To control and monitor the trough or do calibrations run the command \nTrough_GUI.Controls(Trough_GUI.calibrations)
  18. \n
  19. Do not do any real runs without making sure the calibrations are correct.
  20. \n
  21. To start data collection (a run) run the command \nTrough_GUI.Collect_data.Run(\"name_for_run\"), \nwhere you replace name_for_run with the text for the name of the run (no \nspaces).
  22. \n
  23. Set the run conditions.
  24. \n
  25. You can start data collection by clicking the green \"Run\" button.
  26. \n
  27. If you set the speed to zero the data collection will be displayed \nversus time and will not stop until you click the red \"Stop\" button.
  28. \n
\n\n

Installation

\n\n

OS setup - Ubuntu on Pi

\n\n

By default in Ubuntu 20.04 for Pis the gpio and spi groups do not exist.\nThe i2c group does (not always).

\n\n
    \n
  1. Make sure that the following packages are installed rpi.gpio-common \npython3-pigpio python3-gpiozero python3-rpi.gpio.
  2. \n
  3. You can avoid having to create a gpio group, by assigning users who need\n gpio access to the dialout group. Check that /dev/gpiomem is part of that \ngroup and that the dialout group has rw access. If not you will need to set\n it.
  4. \n
  5. Users also need to be members of the i2c group. If it does not exist create \n it and then make that the group for /dev/i2c-1 with group rw permissions. \nTHIS MAY NOT BE NECESSARY.
  6. \n
  7. The spi group needs to be created (addgroup?).
  8. \n
  9. Additionally the spi group needs to be given rw access to the spi devices\nat each boot. To do this create a one line rule in a file named \n/etc/udev/rules.d/50-spidev.rules containing SUBSYSTEM==\"spidev\", \nGROUP=\"spi\", MODE=\"0660\". The file should have rw permission for root \nand read permission for everyone else.
  10. \n
  11. Make sure you have pip installed for \npython 3: python3 -m pip --version or pip3 --version. If you do not, \ninstall using apt \ninstall python3-pip.
  12. \n
\n\n

Trough Software Installation

\n\n

To avoid library conflicts the software should be installed into a virtual environment.\nInstructions for doing this using pipenv\nfollow.

\n\n

Log into your chosen user account:

\n\n
    \n
  1. Install pipenv: pip3 install \n--user pipenv. You may\nneed to add ~/.local/bin to your PATH to make pipenv\navailable in your command shell. More discussion: \nThe Hitchhiker's Guide to\nPython.
  2. \n
  3. Create a directory for the virtual environment you will be installing\ninto (example: $ mkdir Trough).
  4. \n
  5. Navigate into the directory $ cd Trough.
  6. \n
  7. Create the virtual environment and enter it $ pipenv shell. To get out of\nthe environment you can issue the $ exit command on the command line.
  8. \n
  9. While still in the shell install the latest trough software and all its\nrequirements\n $ pip install -U langmuir_trough.
  10. \n
  11. Still within the environment shell test\nthis by starting jupyter $ jupyter notebook. Jupyter should launch in your \nbrowser.\n
      \n
    1. Open a new notebook using the default (Python 3) kernel.
    2. \n
    3. In the first cell import the Trough_GUI: \nfrom Trough import Trough_GUI.\n When run this cell sets things up and tries to talk to the trough.
    4. \n
  12. \n
  13. If you wish, you can make this environment available to an alternate Jupyter\ninstall as a special kernel when you are the user.\n
      \n
    1. Make sure you are running in your virtual environment $ pipenv shell \nin the directory for virtual environment will do that.
    2. \n
    3. Issue the command to add this as a kernel to your personal space: \n$ python -m ipykernel install --user --name=<name-you-want-for-kernel>.
    4. \n
    5. More information is available in the Jupyter/Ipython documentation. \nA simple tutorial from Nikolai Jankiev (_Parametric Thoughts_) can be\nfound here.
    6. \n
  14. \n
\n\n

Change Log

\n\n
    \n
  • 0.6.0dev\n
      \n
    • Documentation updates including Gutow Lab Standard Operating Procedures \n(SOPs).
    • \n
    • Refactored everything to underneath the module Trough.
    • \n
  • \n
  • 0.5.2 (Mar. 16, 2023) Now works in Jupyter Lab.\n
      \n
    • Adjusted widget updating/clearing to work in Jupyter lab.
    • \n
    • Added JupyterLab >= 3.6.1 to requirements.
    • \n
  • \n
  • 0.5.1 (Mar. 9, 2023) \n
      \n
    • Include spidev package in requirements.
    • \n
    • More details reported when unable to \"find trough\".
    • \n
  • \n
  • 0.5.0 (Mar. 4, 2023) First version with working GUI
  • \n
  • 0.1.0 First pypi compatible package version.
  • \n
\n\n

Known issues

\n\n
    \n
  • 0.5.0 - 0.5.2 The estimated error on values converted to metric units \nbased on calibration fits appears to be too pessimistic.
  • \n
\n\n

Development

\n\n

CodeRepository | Docs

\n\n
    \n
  1. For development purposes clone the GIT repository.
  2. \n
  3. Create the virtual environment to run it in within the development \ndirectory pipenv shell.
  4. \n
  5. Within the shell pip install for development pip install -e ..
  6. \n
\n\n

Constructing the Documentation

\n\n
    \n
  1. Make sure pdoc is installed and updated in the virtual environment pip \ninstall -U pdoc.
  2. \n
  3. Update any .md files included in _init_.py.\n
      \n
    • Generally URLs should be absolute, not relative.
    • \n
  4. \n
  5. At the root level run pdoc pdoc --logo-link\nhttps://gutow.github.io/Langmuir_Trough/ --footer-text \"Langmuir_Trough vX.X.X\" \n--math -html -o docs Trough where X.X.X is the version number.
  6. \n
  7. Because of the way the document building process works the background tasks \nwill be started. You will have to stop the document build after the \ndocumentation is done building (watch the doc folder) with a ^C to \nterminate it.
  8. \n
\n\n

Releasing on PyPi

\n\n

Proceed only if testing of the build is successful.

\n\n
    \n
  1. Update packaging software pip install -U setuptools wheel twine
  2. \n
  3. Double check the version number in setup.py.
  4. \n
  5. Rebuild the release: python -m setup sdist bdist_wheel.
  6. \n
  7. Upload it: python -m twine upload dist/*
  8. \n
  9. Make sure it works by installing it in a clean virtual environment. pip \ninstall -U .... Copy the actual link from pypi.org.\n`. If it does not work, pull the release.
  10. \n
\n\n

Ideas/Things to do

\n\n
    \n
  • Make more robust by wrapping data collection in try ... so that it can \nexit more gracefully and give up barrier monitoring?
  • \n
  • Add explanation of how to use the barrier watch deamon to prevent barrier \ncrashing if software fails.
  • \n
\n\n

Langmuir Trough Standard Operating Procedures for the Gutow Lab

\n\n

Initialization

\n\n
    \n
  1. Check that recirculating temperature controller is connected to the \ntrough. Then turn it on and verify that the temperature is set to what \nyou want. Stabilization time is about 20 minutes for temperatures near \nroom temperature.
  2. \n
  3. Turn on power to the trough.
  4. \n
  5. Open a terminal and navigate to the Trough directory of the user \nTrough.
  6. \n
  7. Activate the trough python environment pipenv shell
  8. \n
  9. Launch Jupyter Lab jupyter lab.
  10. \n
  11. Within Jupyter Lab create a new folder for the Day. Name it something \nlike \"DescriptiveWord_MMM_DD_YYYY\", where MMM = three letter month \nabbreviation, DD = day of the month and YYYY = the year.
  12. \n
  13. Open the folder by clicking on it.
  14. \n
  15. Open a new Notebook. Give it a descriptive name.
  16. \n
  17. In the first cell run the command from Trough import Trough_GUI. If the \ntrough has not been started in the last 12 hours this will take a while \nas it checks the motor calibration for moving the barriers.
  18. \n
\n\n

Checking Trough and Subphase Cleanliness

\n\n

This need to be done before each experiment.

\n\n
    \n
  1. We usually use high-purity water as the subphase. Primarily this is \n18+ MΩ de-ionized water mixed with KMnO4 and redistilled.\nDepending on the status of the water polishers, it is sometimes possible \nto use 18+ MΩ water from these directly.
  2. \n
  3. If the trough is already filled with subphase (1 - 1.5 mm above trough \nedges) and the Wilhelmy plate is installed skip steps 3 - 6.
  4. \n
  5. Calibrate the Wilhelmy balance\nif necessary.
  6. \n
  7. Hang a clean filter paper Wilhelmy plate from a fine wire on the balance. \nMake sure that you know the circumference of the plate in mm. This should be \nrecorded in the Jupyter Notebook you are running. Our default \ncircumference is 21.5 mm.
  8. \n
  9. The subphase should fill the trough so that it rises 1 - 1.5 mm above the \nedges of the trough. To add subphase use the clean glass funnel in the trough \nisolation box to pour through (pouring directly from a bottle splashes). \nThe funnel makes it much easier to add subphase when the polycarbonate lid \nwith just a small opening is in use. Always add subphase between the \nbarriers to trap any surface active species between them for easier removal.
  10. \n
  11. Adjust the height of the Wilhelmy balance so the plate is partially \nsubmerged in the subphase. The balance settling time is long. You will \nhave to wait at least 1 minute before any measurements will be valid. \nWith a reasonably clean trough and subphase the unzeroed balance should \nsettle to a surface pressure < 10 mN/m. If it does not or shows no noise, \nthere may be a problem.
  12. \n
  13. If necessary initialize the trough then start the \ntrough control and calibration tool by running the command \nTrough_GUI.Controls(Trough_GUI.calibrations) in an empty cell of the \nnotebook.
  14. \n
  15. Expand the \"Manual Barrier Control\" accordian. Set the direction to \n\"open\". Set the speed to maximum (~10 cm/min). Click the start button. \nWatch the surface pressure indicator. When the barriers stop (~12.7 cm \nseparation), wait to make sure the surface pressure has stabilized.
  16. \n
  17. Switch the direction to \"close\". Set the speed to the maximum closing \nspeed (~6.8 cm/min). Click the start button. Watch the surface pressure \nindicator.
  18. \n
  19. Once the barriers are fully closed (~2.8 cm separation), check the \nsurface pressure. If it is greater than it was when fully open carefully \naspirate the surface between the barriers without catching the Wilhelmy \nplate until the surface pressure is slightly less than observed for the \nopen barriers.
  20. \n
  21. Repeat steps 8 - 10 up to 4X to get the surface clean. If it is still \nnot clean:\n
      \n
    1. Raise the Wilhelmy balance carefully and rotate it aside. Make \nsure to lock it in place.
    2. \n
    3. Remove the polycarbonate lid if it is in place. Store it so that it \ndoes not get contaminated.
    4. \n
    5. Aspirate all the subphase out of the trough and try again.
    6. \n
  22. \n
  23. If after a second try the trough and subphase are still not clean the \ntrough probably needs to be cleaned.
  24. \n
  25. When it appears clean test:\n
      \n
    1. Manually open the barriers all the way.
    2. \n
    3. Set up a run by executing the command \nTrough_GUI.Collect_Data.Run(\"XXX\"), where XXX is replaced with a \nname for the run (e.g. \"clean_test_MMM_DD_YYYYa\") in an empty cell.
    4. \n
    5. Set the units to cm separation. Set the speed to 1 cm/min. Set the \nfinal separation to the minimum for the trough (~2.86 cm).
    6. \n
    7. When the surface pressure is stable click on the \"zero pressure\" \nbutton to tare the Wilhelmy balance.
    8. \n
    9. Click start. The run will stop when the barriers reach the target \nseparation. You can also stop the collection by clicking the \"stop\" \nbutton.
    10. \n
    11. If the surface pressure stays between -0.2 and +0.2 mN/m the trough \nis adequately clean.
    12. \n
  26. \n
\n\n

Storage of Trough Between Runs

\n\n
    \n
  • If the trough is being used regularly (1X/week or more): store the trough \nwith clean subphase in it. If the subphase is water make sure that the \nhumidification beaker in the isolation box is kept about 50% full.
  • \n
  • If the trough will be unused for a significant time:\n
      \n
    1. After verifying the trough and subphase cleanliness\naspirate off all the subphase.
    2. \n
    3. Empty the humidification beaker.
    4. \n
    5. Cover the trough with the polycarbonate lid.
    6. \n
    7. Make sure the isolation box is closed.
    8. \n
    9. Make sure the power supply is off.
    10. \n
    11. Shut down the computer.
    12. \n
  • \n
\n\n

Handling Spreading Solvent(s)

\n\n

It is extremely easy to contaminate the solvents with surface active \ncompounds at a level that will ruin experiments

\n\n
    \n
  • Generally HPLC grade solvents are adequately clean. We most commonly use \nHPLC grade hexanes and absolute ethanol.
  • \n
  • All glassware must be carefully cleaned before using to transfer or \ncontain spreading solvents.\n
      \n
    1. If unsure of basic cleanliness wash well with soap and water. Rinse \nfive (5) times with warm tap water. Rinse three (3) times with \nde-ionized water.
    2. \n
    3. Rinse two (2) times with absolute ethanol (10% - 20% container volume per \nrinse).
    4. \n
    5. Rinse six (6) times with the spreading solvent (10% - 20% container volume \nper rinse).
    6. \n
  • \n
  • Do not stick anything into the clean spreading solvent stock bottle. Get \nsamples to work with by pouring into properly cleaned intermediate containers.
  • \n
\n\n

Checking Spreading Solvent Cleanliness

\n\n
    \n
  1. Transfer < 1 mL of spreading solvent to a\nproperly cleaned vial.
  2. \n
  3. Initialize the trough and \nverify that the subphase is clean.
  4. \n
  5. Using the \"Manual Barrier Controls\" open the barriers all the way.
  6. \n
  7. Rinse the positive displacement microdispenser 3X with absolute ethanol \nfrom a TFE squeeze bottle and then 3X with HPLC grade hexanes from a TFE \nsqueeze bottle.
  8. \n
  9. Rinse with the solvent sample being tested 6X by sucking up 90 µL \nof the solvent sample and dispensing it into a waste beaker.
  10. \n
  11. Dispense 90 µL of the solvent sample onto the surface between the \nbarriers.
  12. \n
  13. Allow to evaporate (15 min is adequate for hexanes).
  14. \n
  15. Perform a compression at 1 cm/min from fully \nopen to fully closed.
  16. \n
  17. The solvent is clean if the surface pressure stays between -0.2 and +0.2 \nmN/m.
  18. \n
\n\n

Making a Spreading Solution

\n\n

For most molecules we want to spread about 3.00 X 10-8 moles of \nmolecules on our trough to get a range of roughly 60 to 15 square Angstroms per \nmolecule during a compression.

\n\n
    \n
  1. The ideal volume to spread is 50 µL of solution. Thus we want a \nconcentration near (3.00 X 10-8 moles)/(50.0 X 10-6 L)\n= 6 X 10-4 M. It is practical to spread anywhere between 20 \nand 90 µL. So, you can adapt to concentrations that vary between 1.00 \nx 10-3 M and 3.3 X 10-4 M.
  2. \n
  3. Ideally your molecule will dissolve in pure hexanes at a concentration of \n6 X 10-4 M. If it is not soluble you can put a few percent (up \nto 5% v/v) of ethanol in with the hexanes. This solvent mixture works for \nmany surfactants, without significantly impacting the surface tension of \na water subphase.
  4. \n
  5. Experiments take very little solution, so make as small volumes of \nsolution as possible. Note that you should not try to measure out \nsurfactant in amounts that produce less than three significant figures on \na standard analytical balance (e.g. at least 10 mg, preferably 50 mg or \nmore.) This may mean that you will have to make a stock solution and \ndilute it to get in the correct concentration range.
  6. \n
  7. All solutions must be made using \nproperly cleaned glassware and spreading \nsolvents that have been\nverified to be clean. Use \nvolumetric flasks with ground glass stoppers to avoid contamination by \nthe plasticizers found in most polymer caps.
  8. \n
  9. Because the solvents are very volatile the solutions will not keep long \nin the volumetric flasks with ground glass stoppers. They can be \ntransferred for somewhat longer term storage to sealed brown bottles \nif the bottles are \nproperly washed \nand you have verified that a little solvent stored in the bottle \novernight and shaken stays clean.
  10. \n
\n\n

Spreading a Sample

\n\n
    \n
  1. Rinse a small vial 2X with absolute ethanol from a TFE squeeze bottle \nthen 3X with hexanes from a TFE squeeze bottle.
  2. \n
  3. If you need to use a pipette or funnel (the funnel is a better choice as \nyou are less likely to contaminate the stock spreading solution) to transfer \nthe spreading solution to the vial rinse the pipette or funnel 2X with \nabsolute ethanol from a TFE squeeze bottle and then 3X with hexanes from \na TFE squeeze bottle.
  4. \n
  5. Rinse the transfer tool with the spreading solution 6X.
  6. \n
  7. Rinse the vial 6X (10-20% of vial volume) with the spreading solution.
  8. \n
  9. Use the transfer tool to transfer about 1 mL of the spreading solution to \nthe small vial.
  10. \n
  11. Set the positive displacement dispenser to the volume you will be \ndispensing.
  12. \n
  13. Rinse the dispenser 2X with absolute ethanol from a TFE squeeze bottle \nthen 3X with hexanes from a TFE squeeze bottle. Make sure you move the \nplunger through its dispensing motion while doing this.
  14. \n
  15. When the dispenser is dry, rinse 6X with the spreading solution making \nsure to take up the full amount to be dispensed on each rinse.
  16. \n
  17. With the barriers fully open dispense the spreading solution drop wise \nonto the surface between the barriers. Avoid the Wilhelmy plate.
  18. \n
  19. Allow time for the solvent to evaporate (~ 15 minutes for hexanes) \nbefore doing a compression.
  20. \n
\n\n

Running a Compression

\n\n
    \n
  1. Trough must first be\nverified to be clean.
  2. \n
  3. Spread the surfactant solution on the trough with the barriers open. \nAllow sufficient time for the solvent to evaporate (~15 min for hexanes). \nThe amount to spread will depend on your target range for area per \nmolecule and the concentration of your solution (10-4 - \n10-3 M is typical).
  4. \n
  5. In a new notebook cell execute the command \nTrough_GUI.Collect_Data.Run(\"XXX\"), where XXX is replaced with a \n name for the run (e.g. \"CompoundName_MMM_DD_YYYYa\")
  6. \n
  7. Adjust the moles of molecules to the moles of surfactant you spread. \nAdjust the units to Angstroms squared per molecule. Choose your desired \nfinal target area and compression speed.
  8. \n
  9. When the solvent is fully evaporated zero the balance.
  10. \n
  11. Store the settings.
  12. \n
  13. When ready click the \"Start\" button. The collection will stop when the \ndesired area is reached. You can also stop the run by clicking the \"Stop\" \nbutton.
  14. \n
\n\n

Calibrating the Wilhelmy Balance

\n\n

This should be done at the beginning of any day real data is collected

\n\n
    \n
  1. If it is not already running launch the trough control and calibration \ntool by running the command Trough_GUI.Controls(Trough_GUI.calibrations)\n in an empty notebook cell.
  2. \n
  3. Expand the \"Calibrate Balance\" accordian and follow the on screen \ninstructions.
  4. \n
\n\n

Calibrating Barrier Position and Speed

\n\n

This only needs to be done if a check of the measured barrier separation \nis off by more than \u00b10.03 mm

\n\n
    \n
  1. If it is not already running launch the trough control and calibration \ntool by running the command Trough_GUI.Controls(Trough_GUI.calibrations)\n in an empty notebook cell.
  2. \n
  3. Expand the \"Calibrate Barriers\" accordian and follow the on screen \ninstructions.
  4. \n
\n\n

Calibrating the Temperature Probe.

\n\n

This is very stable so should not need to be done often

\n\n
    \n
  1. If it is not already running launch the trough control and calibration \ntool by running the command Trough_GUI.Controls(Trough_GUI.calibrations)\n in an empty notebook cell.
  2. \n
  3. Expand the \"Calibrate Temperature\" accordian and follow the on screen \ninstructions.
  4. \n
  5. A good source of known temperatures is the thermostat recirculator.
  6. \n
\n\n

Cleaning the Trough

\n\n
    \n
  1. The cleaning solution 1:1 concentrated nitric acid:concentrated sulfuric \nacid is extremely dangerous and also has potential to damage parts of the \ntrough. Do not perform this cleaning procedure until Dr. Guto has \ncertified you for the process.
  2. \n
  3. The trough can be powered down during this procedure.
  4. \n
  5. The Wilhelmy balance should be locked in position out of the way.
  6. \n
  7. The polycarbonate lid should be removed (store it so that does not get \ncontaminated).
  8. \n
  9. Fill the trough with the 1:1 concentrated nitric:sulfuric acid solution. \nAllow to sit 10 + minutes.
  10. \n
  11. While the cleaning solution sits in the trough make sure the aspirator \ntrap is dry.
  12. \n
  13. Aspirate off the cleaning solution. \n
      \n
    • Unless the trough is extremely dirty the collected cleaning \nsolution may be returned to the cleaning solution storage bottle.
    • \n
    • If disposing of the cleaning solution treat it as strong acid waste and \nneutralize properly.
    • \n
  14. \n
  15. Rinse the trough twice with clean water subphase.
  16. \n
  17. Check the cleanliness of the trough
  18. \n
\n"}, {"fullname": "Trough.Trough_Control", "modulename": "Trough.Trough_Control", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_Control.message_utils", "modulename": "Trough.Trough_Control.message_utils", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_Control.message_utils.extract_messages", "modulename": "Trough.Trough_Control.message_utils", "qualname": "extract_messages", "kind": "function", "doc": "

Parameters

\n\n

datapkg: list\nlist of lists containing trough data bundle, messages in the last list.

\n\n

Returns

\n\n

list\nlist of strings consisting of the messages.

\n", "signature": "(datapkg):", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.simulation", "modulename": "Trough.Trough_Control.simulation", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_Control.simulation.simulated_troughctl", "modulename": "Trough.Trough_Control.simulation", "qualname": "simulated_troughctl", "kind": "function", "doc": "

Will run as separate process taking in commands through a pipe and\nreturning data on demand through a second pipe.

\n\n

Parameters

\n\n

CTLPipe: Pipe\n commands come in on and messages go out on.

\n\n

DATAPipe: Pipe\n data is sent out on

\n", "signature": "(CTLPipe, DATAPipe):", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util", "modulename": "Trough.Trough_Control.trough_util", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_Control.trough_util.isnumber", "modulename": "Trough.Trough_Control.trough_util", "qualname": "isnumber", "kind": "function", "doc": "
Parameters
\n\n
    \n
  • obj: object to be tested
  • \n
\n\n
Returns
\n\n
\n

True is a number.

\n
\n", "signature": "(obj):", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util.etol_call", "modulename": "Trough.Trough_Control.trough_util", "qualname": "etol_call", "kind": "function", "doc": "

Wrapping a callable object in this function will cause it to be called until\nit either returns without an error or the maximum recursion depth is reached.\nThis should only be used on calls that occasionally return errors because they\nare reading sensors or something like that.

\n\n

Parameters

\n\n

obj: callable

\n\n

param: list\n a list containing the parameters in the function call

\n\n

Returns

\n\n

result: any\n result of function call

\n", "signature": "(obj, param):", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util.is_trough_initialized", "modulename": "Trough.Trough_Control.trough_util", "qualname": "is_trough_initialized", "kind": "function", "doc": "

Checks for a running Trough process and good connections to it.

\n\n

Returns

\n\n

bool\nTRUE if initialized

\n", "signature": "():", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util.init_trough", "modulename": "Trough.Trough_Control.trough_util", "qualname": "init_trough", "kind": "function", "doc": "

This initializes the trough control subprocess and creates the pipes to communicate\nwith it.

\n\n

Returns

\n\n

pipe\ncmdsend: the end of the pipe to sent commands to the trough.

\n\n

pipe\ndatarcv: the end of the pipe the trough uses to send back data and messages.

\n\n

Process\nTROUGH: the process handle for the trough.

\n", "signature": "():", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util.troughctl", "modulename": "Trough.Trough_Control.trough_util", "qualname": "troughctl", "kind": "function", "doc": "

Will run as separate process taking in commands through a pipe and\nreturning data on demand through a second pipe.\nIteration 1, collects data into a fifo and watches barrier position.

\n\n
Parameters
\n\n
    \n
  • Pipe CTLPipe: pipe commands come in on and messages go out on.
  • \n
  • Pipe DATAPipe: pipe data is sent out on
  • \n
\n", "signature": "(CTLPipe, DATAPipe):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI", "modulename": "Trough.Trough_GUI", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.Collect_data", "modulename": "Trough.Trough_GUI.Collect_data", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run", "kind": "class", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.__init__", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.__init__", "kind": "function", "doc": "

Create a new run object

\n\n

Parameters

\n\n

id: int\n 0 based index of run in current notebook\nfilename: str\n String representation of the filename used to store the data,\n with not type extension. This probably should not contain a path.\ntitle: str\n User friendly title (suggested default is same as filename).\nunits: str\n Units for the displayed barrier positions (cm, cm^2 or Ang^2/molec).\ntarget: float\n Numerical value in units for the targeted final trough area.\nspeed: float\n Numerical value in units for the speed to move the barriers.\nmoles: float\n moles of molecules initially spread in the trough.\nplate_circ: float\n circumference of the Whilhelmy plate in mm.\ndataframe: DataFrame or None\ntimestamp: float or None

\n", "signature": "(\tid,\tfilename,\ttitle,\tunits,\ttarget,\tspeed,\tmoles,\tplate_circ,\tdataframe=None,\ttimestamp=None)"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.from_html", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.from_html", "kind": "function", "doc": "

Create a run from an html representation

\n\n

Parameters

\n\n

html: str\n The html to be parsed to create the run object

\n\n

Returns

\n\n

trough_run: trough_run\n A trough_run object

\n", "signature": "(self, html):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.run_caption", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.run_caption", "kind": "function", "doc": "

Returns an html table with info about the run to use as a caption

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.init_collect_control", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.init_collect_control", "kind": "function", "doc": "

This initializes the collection control widgets and VBox that\ncontains them. The VBox may be accessed as self.collect_control

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.close_collect_control", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.close_collect_control", "kind": "function", "doc": "

This closes self.collect_control which also minimizes\nthe objects maintained on the Python side.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.to_html", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.to_html", "kind": "function", "doc": "

Create an html string representing a run

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.write_run", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.write_run", "kind": "function", "doc": "

Writes a run file with the base filename run.filename into the\ndirectory specified. If a file with the current name exists\nattempts to make the name unique by appending self.timestamp\nto the filename. Currently only produces\nan html file that is also human-readable. Other file formats may be\navailable in the future through the use of key word arguments.

\n\n

Parameters

\n\n

dirpath:\n pathlike object or string. Empty string means the current working\n directory.

\n\n

kwargs:\n optional key word arguments for future adaptability

\n", "signature": "(self, dirpath, **kwargs):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.Run", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "Run", "kind": "function", "doc": "

This routine creates a GUI for initializing, starting, collecting and\ncompleting a run. If the run has been completed it will simply reload it\nfrom the local datafile.

\n\n

Parameters

\n\n

run_name: str or Path\nThis should generally be the name for the file the data will be stored in\nwithout a file type extension. Recommend a naming scheme that produces\nUnique filenames, such as Trough_run_<username>_<timestamp>. The file\nname will be run_name.trh.run.html.

\n", "signature": "(run_name):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.collect_data_updater", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "collect_data_updater", "kind": "function", "doc": "

This is run in a separate thread and will update the figure and\nall status widgets at an interval of 2 seconds or a little longer. While\nthis is running nothing else will be able to talk to the trough.

\n\n

Parameters

\n\n

trough_lock: threading.lock\n When acquired this routine will talk to the trough. It is not\n released until the routine exits to avoid any data loss. It does\n call the status_widgets updater as often as it can while collecting\n the data.

\n\n

cmdsend: Pipe\n End of Pipe to send commands to the Trough.

\n\n

datarcv: Pipe\n End of Pipe to receive data from the Trough.

\n\n

cals: Trough_GUI.calibrations\n Used to convert the data to user units.

\n\n

lastdirection: multiprocessing.Value\n Of type 'i' to indicate last direction the barriers moved.

\n\n

run_updater: multiprocessing.Value\n Of type 'c_bool'. True if this updater should keep running.

\n\n

updater_running: multiprocessing.Value\n Of type 'c_bool'. Set to True by this process when it starts\n and set to False before exiting.

\n\n

run: trough_run\n This object contains the live figure and the place to store the data.

\n", "signature": "(\ttrough_lock,\tcmdsend,\tdatarcv,\tcals,\tlastdirection,\trun_updater,\tupdater_running,\trun):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.update_collection", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "update_collection", "kind": "function", "doc": "

Updates the graph and the data storage

\n", "signature": "(datapkg, cals, lastdirection, run_updater, updater_running, run):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Monitor_Calibrate", "modulename": "Trough.Trough_GUI.Monitor_Calibrate", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.Monitor_Calibrate.Monitor_Setup_Trough", "modulename": "Trough.Trough_GUI.Monitor_Calibrate", "qualname": "Monitor_Setup_Trough", "kind": "function", "doc": "

This produces a user interface in jupyter notebooks using ipywidgets. The\ninterface allows monitoring of the trough barrier positions, balance\nsignal, and temperature signal. The barrier positions can be\nadjusted using this interface. Calibrations of all the signals are\nperformed using this interface.

\n\n

Calibrations are stored in the calibration files in the .Trough/calibrations\ndirectory of the current user. The latest file is used. If none exists\none is created using default parameters. Users should calibrate all\nsignals before using the trough.

\n\n

NOTE: some objects used here are global and created by importing from\nstatus_widgets.py and command_widgets.py.

\n\n

Parameters

\n\n

calibrations: Calibrations\n The object containing the calibrations be used and modified. See\n Trough_GUI.calibration_utils.

\n", "signature": "(calibrations):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils", "modulename": "Trough.Trough_GUI.calibration_utils", "kind": "module", "doc": "

Utilities for:

\n\n
    \n
  • writing and reading calibration files stored in the local\nuser directory .Trough/calibrations.
  • \n
  • fitting calibration data to generate calibration parameters.
  • \n
  • converting between raw signal and user-friendly values.
  • \n
\n"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration", "kind": "class", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.__init__", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.__init__", "kind": "function", "doc": "

Defines a calibration of type name.

\n\n

Parameters

\n\n

name: str\n calibration name.

\n\n

units: str\n string representation of the units the calibration yields.

\n\n

timestamp: float\n Unix floating point timestamp.

\n\n

param:list\n list of the numerical parameters for the fit yielding the\n calibration.

\n\n

param_stdev: list\n list of the numerical values for the estimated standard\n deviation of the parameters from the fit.\nparam_inv: list\n list of the numerical values for the fit (or equation) yielding the\n inverse of the calibration (return to the raw value).\nparam_inv_stdev: list\n list of the numerical values for the estimated standard deviation of\n the parameters for the inversion.\ncal_data_x: list\n x-data used for the calibration fit.

\n\n

cal_data_y: list\n y-data used for the calibration fit.

\n\n

fit_type: str\n string name for the fit type. Defaults to \"polynomial\"

\n\n

fit_eqn_str: str\n string representation of the fit equation. Defaults to\n \"y = C0 + C1x + C2xx + C3xxx + ...\"

\n\n

fit_ceof_lbls: list\n list of string labels for the coefficients, which should\n correlate to symbols in the fit_eqn_str. Defaults to [\"C0\", \"C1\",\n ...]. Automatically, truncated to the actual number of\n coefficients determined by the order of the polynomial.

\n\n

additional_data:dict\n a dictionary of key:value pairs where the keys are a short\n descriptive string. They can contain any additional data\n necessary for doing calculations on the data.

\n", "signature": "(\tname,\tunits,\ttimestamp,\tparam,\tparam_stdev,\tparam_inv,\tparam_inv_stdev,\tcal_data_x,\tcal_data_y,\tfit_type='polynomial',\tfit_eqn_str='y = C0 + C1*x + C2*x*x + C3*x*x*x + ...',\tfit_ceof_lbls=['C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7'],\tadditional_data={})"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.cal_from_html", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.cal_from_html", "kind": "function", "doc": "

This takes in an html str, parses it and returns a new\ncalibration.

\n\n

Parameters

\n\n

html: str\n The html to be parsed to create the calibration object

\n\n

Returns

\n\n

calibration: calibration\n a calibration object.

\n", "signature": "(cls, html):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.cal_to_html", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.cal_to_html", "kind": "function", "doc": "

This routine creates an html str that would be human-readable in a\nbrowser detailing the calibration. This can be written to a file to\nstore the calibration.

\n\n

Returns

\n\n

calib_div: str\n string containing the html detailing the calibration.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.cal_apply", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.cal_apply", "kind": "function", "doc": "

\n", "signature": "(self, data, stdev):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.cal_inv", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.cal_inv", "kind": "function", "doc": "

\n", "signature": "(self, data, stdev):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibrations", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibrations", "kind": "class", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibrations.read_cal", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibrations.read_cal", "kind": "function", "doc": "

This routine reads in a calibration file. If it is the standard\nhtml file it uses calibration.cal_from_html() operation to convert\nit to a calibration.

\n\n

Parameters

\n\n

name: str\n either the basename (current options: 'balance', 'barriers_open',\n 'barriers_close', 'speed_open', 'speed_close' or\n 'temperature') or a string representation of the path to the\n calibration file to be read. If one of the basenames is used\n this code will look for the most recent calibration of that type\n in the directory '~.Trough\\calibrations'.

\n\n

Returns

\n\n

Calibration

\n", "signature": "(self, name):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibrations.write_cal", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibrations.write_cal", "kind": "function", "doc": "

Writes a calibration file with the base filename cal.name + int(\ncal.timestamp) into the directory specified. Currently only produces\nan html file that is also human-readable. Other file formats may be\navailable in the future through the use of key word arguments.

\n\n

Parameters

\n\n

dirpath:\n pathlike object or string

\n\n

cal: Calibration\n a calibration object containing the information about the\n calibration to write to the file.

\n\n

kwargs:\n optional key word arguments for future adaptability

\n", "signature": "(self, dirpath, cal, **kwargs):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibrations.poly_fit", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibrations.poly_fit", "kind": "function", "doc": "

Does a polynomial fit of the specified order using the x and y\nvalues provided.

\n\n

Parameters

\n\n

data_x: list\n of numerical x values.

\n\n

data_y: list\n of numerical y values.

\n\n

order: int\n the order of the polynomical used for fitting.

\n\n

yerr: float or iterable of float\n absolute error(s) in the y-value. Used to weight the fit. If no\n values are provided the assumption is equal weighting.

\n\n

Returns

\n\n

param: list\n of fitted parameters.

\n\n

param_stdev: list\n of estimated standard deviation in the parameters.

\n", "signature": "(self, data_x, data_y, order, yerr=None):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets", "modulename": "Trough.Trough_GUI.command_widgets", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_change_Barr_Units", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_change_Barr_Units", "kind": "function", "doc": "

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_change_Barr_Direction", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_change_Barr_Direction", "kind": "function", "doc": "

\n", "signature": "(changed):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_Barr_Target_change", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_Barr_Target_change", "kind": "function", "doc": "

Updates the speed settings since open and close are different.

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_click_Start", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_click_Start", "kind": "function", "doc": "

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_click_Stop", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_click_Stop", "kind": "function", "doc": "

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions", "modulename": "Trough.Trough_GUI.conversions", "kind": "module", "doc": "

This file contains unit conversion utility functions for use in the GUI

\n\n
    \n
  • To nest these functions replace the value, err part of the call with\n*func(...). For example sqcm_to_angpermolec(*cm_to_sqcm(9.2, 0.1, cals),\ncals)
  • \n
\n"}, {"fullname": "Trough.Trough_GUI.conversions.cm_to_sqcm", "modulename": "Trough.Trough_GUI.conversions", "qualname": "cm_to_sqcm", "kind": "function", "doc": "

convert barrier separation in cm to trough area in sqcm

\n", "signature": "(value, err, cals):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.sqcm_to_cm", "modulename": "Trough.Trough_GUI.conversions", "qualname": "sqcm_to_cm", "kind": "function", "doc": "

convert trough area in sqcm to barrier separation in cm

\n", "signature": "(value, err, cals):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.sqcm_to_angpermolec", "modulename": "Trough.Trough_GUI.conversions", "qualname": "sqcm_to_angpermolec", "kind": "function", "doc": "

convert trough area in sqcm to square angstroms per molecules

\n", "signature": "(value, err, moles):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.angpermolec_to_sqcm", "modulename": "Trough.Trough_GUI.conversions", "qualname": "angpermolec_to_sqcm", "kind": "function", "doc": "

convert trough area in sqcm to square angstroms per molecules

\n", "signature": "(value, err, moles):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.mg_to_mNperm", "modulename": "Trough.Trough_GUI.conversions", "qualname": "mg_to_mNperm", "kind": "function", "doc": "

convert balance measurement in mg to milliNewtons per meter

\n", "signature": "(value, err, pi_tare, plate_circ):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.nNperm_to_mg", "modulename": "Trough.Trough_GUI.conversions", "qualname": "nNperm_to_mg", "kind": "function", "doc": "

convert surface pressure in milliNewtons per meter to mg

\n", "signature": "(value, err, pi_tare, plate_circ):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.status_widgets", "modulename": "Trough.Trough_GUI.status_widgets", "kind": "module", "doc": "

This file contains widgets that display updating trough information and\ncan be used in multiple ipywidget panels within the same notebook.

\n"}, {"fullname": "Trough.Trough_GUI.status_widgets.set_zero_pressure", "modulename": "Trough.Trough_GUI.status_widgets", "qualname": "set_zero_pressure", "kind": "function", "doc": "

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.status_widgets.update_status", "modulename": "Trough.Trough_GUI.status_widgets", "qualname": "update_status", "kind": "function", "doc": "

Call this routine to update the contents of all the status widgets.

\n\n

Parameters

\n\n

raw_data: dict\n dictionary of latest raw data values for each\n sensor and their standard deviation\n (e.g. {'bal_raw':3.20,'bal_dev':0.005,'barr_raw':0.5,'barr_dev':0.002,\n 'temp_raw':2.24, 'temp_dev':0.01, 'messages':''})

\n\n

calibrations: Calibrations\n Object containing the calibrations for the trough (currently\n .balance, .barriers and .temperature). A call to\n .balance.cal_apply(raw_data['bal_raw'],raw_data['bal_dev'])\n will return the balance reading in the calibration units (.balance.units).

\n", "signature": "(raw_data: dict, calibrations, lastdirection):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.status_widgets.status_updater", "modulename": "Trough.Trough_GUI.status_widgets", "qualname": "status_updater", "kind": "function", "doc": "

This is run in a separate thread and will update the status widgets\nevery 2 seconds or when it can get access to the pipes to talk to the\ntrough.

\n\n

Parameters

\n\n

trough_lock: threading.lock\n When acquired this routine will talk to the trough. Releases it for\n other processes after every update.

\n\n

cmdsend: Pipe\n End of Pipe to send commands to the Trough.

\n\n

datarcv: Pipe\n End of Pipe to receive data from the Trough.

\n\n

cals: Trough_GUI.calibrations\n Used to convert the data to user units.

\n\n

lastdirection: multiprocessing.Value\n Of type 'i' to indicate last direction the barriers moved.

\n\n

run_updater: multiprocessing.Value\n Of type 'c_bool'. True if this updater should keep running.

\n\n

updater_running: multiprocessing.Value\n Of type 'c_bool'. Set to True by this process when it starts\n and set to False before exiting.

\n", "signature": "(\ttrough_lock,\tcmdsend,\tdatarcv,\tcals,\tlastdirection,\trun_updater,\tupdater_running):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.status_widgets.start_status_updater", "modulename": "Trough.Trough_GUI.status_widgets", "qualname": "start_status_updater", "kind": "function", "doc": "

\n", "signature": "():", "funcdef": "def"}]; + /** pdoc search index */const docs = [{"fullname": "Trough", "modulename": "Trough", "kind": "module", "doc": "

Langmuir Trough

\n\n

This software is a custom controller and GUI for the research Langmuir trough \nin the Gutow Lab at UW Oshkosh. It is written in Python and expects to run in a\nJupyter notebook environment. However, all of the parts that are not elements\nof the user interface should work in a vanilla Python environment.

\n\n

Hardware requirements:\nRaspberry Pi compatible system with a Pi-Plates \nDAQC2 data acquisition plate \nand a trough controlled by the DAQC2 plate. This software could be used with \na trough controlled some other way by rewriting the routines in trough_util.\npy. The GUI front end would need no rewriting to use with a different \ntrough if a custom backend controlling the barriers, reading the temperature \nand Whilhelmy balance is written. The backend needs to continually monitor \nthe trough and respond to the following commands: Stop, Send, Start, \nDirection, Speed, MoveTo, MotorCal, ConstPi, DataLabels, ShutDown.

\n\n

If you do not have compatible hardware the GUI will run with a simulated \ntrough, allowing you to see how it works.

\n\n

Usage

\n\n

Once installed:

\n\n
    \n
  1. Turn on the power supply for the trough.
  2. \n
  3. In a terminal navigate to the directory containing the trough software.
  4. \n
  5. Start the virtual environment pipenv shell.
  6. \n
  7. Launch Jupyter jupyter notebook (jupyter lab also works and is now \nmore stable).
  8. \n
  9. Create a folder for the new day using the New menu near the top right \nof the Jupyter browser page. Give it an appropriate name.
  10. \n
  11. Switch to that folder by clicking on it.
  12. \n
  13. Start a new ipython notebook using the New menu. Give it a\nname that describes the experiment.
  14. \n
  15. In the first cell initialize the trough by running the command from \nTrough import Trough_GUI. This will take a while to run the first time \nit is run each day because it needs to check the movement of the barriers.
  16. \n
  17. To control and monitor the trough or do calibrations run the command \nTrough_GUI.Controls(Trough_GUI.calibrations)
  18. \n
  19. Do not do any real runs without making sure the calibrations are correct.
  20. \n
  21. To start data collection (a run) run the command \nTrough_GUI.Collect_data.Run(\"name_for_run\"), \nwhere you replace name_for_run with the text for the name of the run (no \nspaces).
  22. \n
  23. Set the run conditions.
  24. \n
  25. You can start data collection by clicking the green \"Run\" button.
  26. \n
  27. If you set the speed to zero the data collection will be displayed \nversus time and will not stop until you click the red \"Stop\" button.
  28. \n
\n\n

Installation

\n\n

OS setup - Ubuntu on Pi

\n\n

By default in Ubuntu 20.04 for Pis the gpio and spi groups do not exist.\nThe i2c group does (not always).

\n\n
    \n
  1. Make sure that the following packages are installed rpi.gpio-common \npython3-pigpio python3-gpiozero python3-rpi.gpio.
  2. \n
  3. You can avoid having to create a gpio group, by assigning users who need\n gpio access to the dialout group. Check that /dev/gpiomem is part of that \ngroup and that the dialout group has rw access. If not you will need to set\n it.
  4. \n
  5. Users also need to be members of the i2c group. If it does not exist create \n it and then make that the group for /dev/i2c-1 with group rw permissions. \nTHIS MAY NOT BE NECESSARY.
  6. \n
  7. The spi group needs to be created (addgroup?).
  8. \n
  9. Additionally the spi group needs to be given rw access to the spi devices\nat each boot. To do this create a one line rule in a file named \n/etc/udev/rules.d/50-spidev.rules containing SUBSYSTEM==\"spidev\", \nGROUP=\"spi\", MODE=\"0660\". The file should have rw permission for root \nand read permission for everyone else.
  10. \n
  11. Make sure you have pip installed for \npython 3: python3 -m pip --version or pip3 --version. If you do not, \ninstall using apt \ninstall python3-pip.
  12. \n
\n\n

Trough Software Installation

\n\n

To avoid library conflicts the software should be installed into a virtual environment.\nInstructions for doing this using pipenv\nfollow.

\n\n

Log into your chosen user account:

\n\n
    \n
  1. Install pipenv: pip3 install \n--user pipenv. You may\nneed to add ~/.local/bin to your PATH to make pipenv\navailable in your command shell. More discussion: \nThe Hitchhiker's Guide to\nPython.
  2. \n
  3. Create a directory for the virtual environment you will be installing\ninto (example: $ mkdir Trough).
  4. \n
  5. Navigate into the directory $ cd Trough.
  6. \n
  7. Create the virtual environment and enter it $ pipenv shell. To get out of\nthe environment you can issue the $ exit command on the command line.
  8. \n
  9. While still in the shell install the latest trough software and all its\nrequirements\n $ pip install -U langmuir_trough.
  10. \n
  11. Still within the environment shell test\nthis by starting jupyter $ jupyter notebook. Jupyter should launch in your \nbrowser.\n
      \n
    1. Open a new notebook using the default (Python 3) kernel.
    2. \n
    3. In the first cell import the Trough_GUI: \nfrom Trough import Trough_GUI.\n When run this cell sets things up and tries to talk to the trough.
    4. \n
  12. \n
  13. If you wish, you can make this environment available to an alternate Jupyter\ninstall as a special kernel when you are the user.\n
      \n
    1. Make sure you are running in your virtual environment $ pipenv shell \nin the directory for virtual environment will do that.
    2. \n
    3. Issue the command to add this as a kernel to your personal space: \n$ python -m ipykernel install --user --name=<name-you-want-for-kernel>.
    4. \n
    5. More information is available in the Jupyter/Ipython documentation. \nA simple tutorial from Nikolai Jankiev (_Parametric Thoughts_) can be\nfound here.
    6. \n
  14. \n
\n\n

Change Log

\n\n
    \n
  • 0.6.0 (Mar. 29, 2023)\n
      \n
    • Documentation updates including Gutow Lab Standard Operating Procedures \n(SOPs).
    • \n
    • Refactored everything to inside the module Trough.
    • \n
  • \n
  • 0.5.2 (Mar. 16, 2023) Now works in Jupyter Lab.\n
      \n
    • Adjusted widget updating/clearing to work in Jupyter lab.
    • \n
    • Added JupyterLab >= 3.6.1 to requirements.
    • \n
  • \n
  • 0.5.1 (Mar. 9, 2023) \n
      \n
    • Include spidev package in requirements.
    • \n
    • More details reported when unable to \"find trough\".
    • \n
  • \n
  • 0.5.0 (Mar. 4, 2023) First version with working GUI
  • \n
  • 0.1.0 First pypi compatible package version.
  • \n
\n\n

Known issues

\n\n
    \n
  • 0.5.0 - 0.6.0 The estimated error on values converted to metric units \nbased on calibration fits appears to be too pessimistic.
  • \n
  • Inconsistent rendering of Latex ipywidget labels with ipywidgets >= 8.0. \nUntil figured out requiring ipywidgets < 8.0.
  • \n
  • Runs don't label graph axes reliably for x-axis units other than cm.
  • \n
\n\n

Development

\n\n

CodeRepository | Docs

\n\n
    \n
  1. For development purposes clone the GIT repository.
  2. \n
  3. Create the virtual environment to run it in within the development \ndirectory pipenv shell.
  4. \n
  5. Within the shell pip install for development pip install -e ..
  6. \n
\n\n

Constructing the Documentation

\n\n
    \n
  1. Make sure pdoc is installed and updated in the virtual environment pip \ninstall -U pdoc.
  2. \n
  3. Update any .md files included in _init_.py.\n
      \n
    • Generally URLs should be absolute, not relative.
    • \n
  4. \n
  5. At the root level run pdoc pdoc --logo-link\nhttps://gutow.github.io/Langmuir_Trough/ --footer-text \"Langmuir_Trough vX.X.X\" \n--math -html -o docs Trough where X.X.X is the version number.
  6. \n
  7. Because of the way the document building process works the background tasks \nwill be started. You will have to stop the document build after the \ndocumentation is done building (watch the doc folder) with a ^C to \nterminate it.
  8. \n
\n\n

Releasing on PyPi

\n\n

Proceed only if testing of the build is successful.

\n\n
    \n
  1. Update packaging software pip install -U setuptools wheel twine
  2. \n
  3. Double check the version number in setup.py.
  4. \n
  5. Rebuild the release: python -m setup sdist bdist_wheel.
  6. \n
  7. Upload it: python -m twine upload dist/*
  8. \n
  9. Make sure it works by installing it in a clean virtual environment. pip \ninstall -U .... Copy the actual link from pypi.org.\n`. If it does not work, pull the release.
  10. \n
\n\n

Ideas/Things to do

\n\n
    \n
  • Make more robust by wrapping data collection in try ... so that it can \nexit more gracefully and give up barrier monitoring?
  • \n
  • Add explanation of how to use the barrier watch deamon to prevent barrier \ncrashing if software fails.
  • \n
\n\n

Langmuir Trough Standard Operating Procedures for the Gutow Lab

\n\n

Initialization

\n\n
    \n
  1. Check that recirculating temperature controller is connected to the \ntrough. Then turn it on and verify that the temperature is set to what \nyou want. Stabilization time is about 20 minutes for temperatures near \nroom temperature.
  2. \n
  3. Turn on power to the trough.
  4. \n
  5. Open a terminal and navigate to the Trough directory of the user \nTrough.
  6. \n
  7. Activate the trough python environment pipenv shell
  8. \n
  9. Launch Jupyter Lab jupyter lab.
  10. \n
  11. Within Jupyter Lab create a new folder for the Day. Name it something \nlike \"DescriptiveWord_MMM_DD_YYYY\", where MMM = three letter month \nabbreviation, DD = day of the month and YYYY = the year.
  12. \n
  13. Open the folder by clicking on it.
  14. \n
  15. Open a new Notebook. Give it a descriptive name.
  16. \n
  17. In the first cell run the command from Trough import Trough_GUI. If the \ntrough has not been started in the last 12 hours this will take a while \nas it checks the motor calibration for moving the barriers.
  18. \n
\n\n

Checking Trough and Subphase Cleanliness

\n\n

This need to be done before each experiment.

\n\n
    \n
  1. We usually use high-purity water as the subphase. Primarily this is \n18+ MΩ de-ionized water mixed with KMnO4 and redistilled.\nDepending on the status of the water polishers, it is sometimes possible \nto use 18+ MΩ water from these directly.
  2. \n
  3. If the trough is already filled with subphase (1 - 1.5 mm above trough \nedges) and the Wilhelmy plate is installed skip steps 3 - 6.
  4. \n
  5. Calibrate the Wilhelmy balance\nif necessary.
  6. \n
  7. Hang a clean filter paper Wilhelmy plate from a fine wire on the balance. \nMake sure that you know the circumference of the plate in mm. This should be \nrecorded in the Jupyter Notebook you are running. Our default \ncircumference is 21.5 mm.
  8. \n
  9. The subphase should fill the trough so that it rises 1 - 1.5 mm above the \nedges of the trough. To add subphase use the clean glass funnel in the trough \nisolation box to pour through (pouring directly from a bottle splashes). \nThe funnel makes it much easier to add subphase when the polycarbonate lid \nwith just a small opening is in use. Always add subphase between the \nbarriers to trap any surface active species between them for easier removal.
  10. \n
  11. Adjust the height of the Wilhelmy balance so the plate is partially \nsubmerged in the subphase. The balance settling time is long. You will \nhave to wait at least 1 minute before any measurements will be valid. \nWith a reasonably clean trough and subphase the unzeroed balance should \nsettle to a surface pressure < 10 mN/m. If it does not or shows no noise, \nthere may be a problem.
  12. \n
  13. If necessary initialize the trough then start the \ntrough control and calibration tool by running the command \nTrough_GUI.Controls(Trough_GUI.calibrations) in an empty cell of the \nnotebook.
  14. \n
  15. Expand the \"Manual Barrier Control\" accordian. Set the direction to \n\"open\". Set the speed to maximum (~10 cm/min). Click the start button. \nWatch the surface pressure indicator. When the barriers stop (~12.7 cm \nseparation), wait to make sure the surface pressure has stabilized.
  16. \n
  17. Switch the direction to \"close\". Set the speed to the maximum closing \nspeed (~6.8 cm/min). Click the start button. Watch the surface pressure \nindicator.
  18. \n
  19. Once the barriers are fully closed (~2.8 cm separation), check the \nsurface pressure. If it is greater than it was when fully open carefully \naspirate the surface between the barriers without catching the Wilhelmy \nplate until the surface pressure is slightly less than observed for the \nopen barriers.
  20. \n
  21. Repeat steps 8 - 10 up to 4X to get the surface clean. If it is still \nnot clean:\n
      \n
    1. Raise the Wilhelmy balance carefully and rotate it aside. Make \nsure to lock it in place.
    2. \n
    3. Remove the polycarbonate lid if it is in place. Store it so that it \ndoes not get contaminated.
    4. \n
    5. Aspirate all the subphase out of the trough and try again.
    6. \n
  22. \n
  23. If after a second try the trough and subphase are still not clean the \ntrough probably needs to be cleaned.
  24. \n
  25. When it appears clean test:\n
      \n
    1. Manually open the barriers all the way.
    2. \n
    3. Set up a run by executing the command \nTrough_GUI.Collect_Data.Run(\"XXX\"), where XXX is replaced with a \nname for the run (e.g. \"clean_test_MMM_DD_YYYYa\") in an empty cell.
    4. \n
    5. Set the units to cm separation. Set the speed to 1 cm/min. Set the \nfinal separation to the minimum for the trough (~2.86 cm).
    6. \n
    7. When the surface pressure is stable click on the \"zero pressure\" \nbutton to tare the Wilhelmy balance.
    8. \n
    9. Click start. The run will stop when the barriers reach the target \nseparation. You can also stop the collection by clicking the \"stop\" \nbutton.
    10. \n
    11. If the surface pressure stays between -0.2 and +0.2 mN/m the trough \nis adequately clean.
    12. \n
  26. \n
\n\n

Storage of Trough Between Runs

\n\n
    \n
  • If the trough is being used regularly (1X/week or more): store the trough \nwith clean subphase in it. If the subphase is water make sure that the \nhumidification beaker in the isolation box is kept about 50% full.
  • \n
  • If the trough will be unused for a significant time:\n
      \n
    1. After verifying the trough and subphase cleanliness\naspirate off all the subphase.
    2. \n
    3. Empty the humidification beaker.
    4. \n
    5. Cover the trough with the polycarbonate lid.
    6. \n
    7. Make sure the isolation box is closed.
    8. \n
    9. Make sure the power supply is off.
    10. \n
    11. Shut down the computer.
    12. \n
  • \n
\n\n

Handling Spreading Solvent(s)

\n\n

It is extremely easy to contaminate the solvents with surface active \ncompounds at a level that will ruin experiments

\n\n
    \n
  • Generally HPLC grade solvents are adequately clean. We most commonly use \nHPLC grade hexanes and absolute ethanol.
  • \n
  • All glassware must be carefully cleaned before using to transfer or \ncontain spreading solvents.\n
      \n
    1. If unsure of basic cleanliness wash well with soap and water. Rinse \nfive (5) times with warm tap water. Rinse three (3) times with \nde-ionized water.
    2. \n
    3. Rinse two (2) times with absolute ethanol (10% - 20% container volume per \nrinse).
    4. \n
    5. Rinse six (6) times with the spreading solvent (10% - 20% container volume \nper rinse).
    6. \n
  • \n
  • Do not stick anything into the clean spreading solvent stock bottle. Get \nsamples to work with by pouring into properly cleaned intermediate containers.
  • \n
\n\n

Checking Spreading Solvent Cleanliness

\n\n
    \n
  1. Transfer < 1 mL of spreading solvent to a\nproperly cleaned vial.
  2. \n
  3. Initialize the trough and \nverify that the subphase is clean.
  4. \n
  5. Using the \"Manual Barrier Controls\" open the barriers all the way.
  6. \n
  7. Rinse the positive displacement microdispenser 3X with absolute ethanol \nfrom a TFE squeeze bottle and then 3X with HPLC grade hexanes from a TFE \nsqueeze bottle.
  8. \n
  9. Rinse with the solvent sample being tested 6X by sucking up 90 µL \nof the solvent sample and dispensing it into a waste beaker.
  10. \n
  11. Dispense 90 µL of the solvent sample onto the surface between the \nbarriers.
  12. \n
  13. Allow to evaporate (15 min is adequate for hexanes).
  14. \n
  15. Perform a compression at 1 cm/min from fully \nopen to fully closed.
  16. \n
  17. The solvent is clean if the surface pressure stays between -0.2 and +0.2 \nmN/m.
  18. \n
\n\n

Making a Spreading Solution

\n\n

For most molecules we want to spread about 3.00 X 10-8 moles of \nmolecules on our trough to get a range of roughly 60 to 15 square Angstroms per \nmolecule during a compression.

\n\n
    \n
  1. The ideal volume to spread is 50 µL of solution. Thus we want a \nconcentration near (3.00 X 10-8 moles)/(50.0 X 10-6 L)\n= 6 X 10-4 M. It is practical to spread anywhere between 20 \nand 90 µL. So, you can adapt to concentrations that vary between 1.00 \nx 10-3 M and 3.3 X 10-4 M.
  2. \n
  3. Ideally your molecule will dissolve in pure hexanes at a concentration of \n6 X 10-4 M. If it is not soluble you can put a few percent (up \nto 5% v/v) of ethanol in with the hexanes. This solvent mixture works for \nmany surfactants, without significantly impacting the surface tension of \na water subphase.
  4. \n
  5. Experiments take very little solution, so make as small volumes of \nsolution as possible. Note that you should not try to measure out \nsurfactant in amounts that produce less than three significant figures on \na standard analytical balance (e.g. at least 10 mg, preferably 50 mg or \nmore.) This may mean that you will have to make a stock solution and \ndilute it to get in the correct concentration range.
  6. \n
  7. All solutions must be made using \nproperly cleaned glassware and spreading \nsolvents that have been\nverified to be clean. Use \nvolumetric flasks with ground glass stoppers to avoid contamination by \nthe plasticizers found in most polymer caps.
  8. \n
  9. Because the solvents are very volatile the solutions will not keep long \nin the volumetric flasks with ground glass stoppers. They can be \ntransferred for somewhat longer term storage to sealed brown bottles \nif the bottles are \nproperly washed \nand you have verified that a little solvent stored in the bottle \novernight and shaken stays clean.
  10. \n
\n\n

Spreading a Sample

\n\n
    \n
  1. Rinse a small vial 2X with absolute ethanol from a TFE squeeze bottle \nthen 3X with hexanes from a TFE squeeze bottle.
  2. \n
  3. If you need to use a pipette or funnel (the funnel is a better choice as \nyou are less likely to contaminate the stock spreading solution) to transfer \nthe spreading solution to the vial rinse the pipette or funnel 2X with \nabsolute ethanol from a TFE squeeze bottle and then 3X with hexanes from \na TFE squeeze bottle.
  4. \n
  5. Rinse the transfer tool with the spreading solution 6X.
  6. \n
  7. Rinse the vial 6X (10-20% of vial volume) with the spreading solution.
  8. \n
  9. Use the transfer tool to transfer about 1 mL of the spreading solution to \nthe small vial.
  10. \n
  11. Set the positive displacement dispenser to the volume you will be \ndispensing.
  12. \n
  13. Rinse the dispenser 2X with absolute ethanol from a TFE squeeze bottle \nthen 3X with hexanes from a TFE squeeze bottle. Make sure you move the \nplunger through its dispensing motion while doing this.
  14. \n
  15. When the dispenser is dry, rinse 6X with the spreading solution making \nsure to take up the full amount to be dispensed on each rinse.
  16. \n
  17. With the barriers fully open dispense the spreading solution drop wise \nonto the surface between the barriers. Avoid the Wilhelmy plate.
  18. \n
  19. Allow time for the solvent to evaporate (~ 15 minutes for hexanes) \nbefore doing a compression.
  20. \n
\n\n

Running a Compression

\n\n
    \n
  1. Trough must first be\nverified to be clean.
  2. \n
  3. Spread the surfactant solution on the trough with the barriers open. \nAllow sufficient time for the solvent to evaporate (~15 min for hexanes). \nThe amount to spread will depend on your target range for area per \nmolecule and the concentration of your solution (10-4 - \n10-3 M is typical).
  4. \n
  5. In a new notebook cell execute the command \nTrough_GUI.Collect_Data.Run(\"XXX\"), where XXX is replaced with a \n name for the run (e.g. \"CompoundName_MMM_DD_YYYYa\")
  6. \n
  7. Adjust the moles of molecules to the moles of surfactant you spread. \nAdjust the units to Angstroms squared per molecule. Choose your desired \nfinal target area and compression speed.
  8. \n
  9. When the solvent is fully evaporated zero the balance.
  10. \n
  11. Store the settings.
  12. \n
  13. When ready click the \"Start\" button. The collection will stop when the \ndesired area is reached. You can also stop the run by clicking the \"Stop\" \nbutton.
  14. \n
\n\n

Calibrating the Wilhelmy Balance

\n\n

This should be done at the beginning of any day real data is collected

\n\n
    \n
  1. If it is not already running launch the trough control and calibration \ntool by running the command Trough_GUI.Controls(Trough_GUI.calibrations)\n in an empty notebook cell.
  2. \n
  3. Expand the \"Calibrate Balance\" accordian and follow the on screen \ninstructions.
  4. \n
\n\n

Calibrating Barrier Position and Speed

\n\n

This only needs to be done if a check of the measured barrier separation \nis off by more than \u00b10.03 mm

\n\n
    \n
  1. If it is not already running launch the trough control and calibration \ntool by running the command Trough_GUI.Controls(Trough_GUI.calibrations)\n in an empty notebook cell.
  2. \n
  3. Expand the \"Calibrate Barriers\" accordian and follow the on screen \ninstructions.
  4. \n
\n\n

Calibrating the Temperature Probe.

\n\n

This is very stable so should not need to be done often

\n\n
    \n
  1. If it is not already running launch the trough control and calibration \ntool by running the command Trough_GUI.Controls(Trough_GUI.calibrations)\n in an empty notebook cell.
  2. \n
  3. Expand the \"Calibrate Temperature\" accordian and follow the on screen \ninstructions.
  4. \n
  5. A good source of known temperatures is the thermostat recirculator.
  6. \n
\n\n

Cleaning the Trough

\n\n
    \n
  1. The cleaning solution 1:1 concentrated nitric acid:concentrated sulfuric \nacid is extremely dangerous and also has potential to damage parts of the \ntrough. Do not perform this cleaning procedure until Dr. Guto has \ncertified you for the process.
  2. \n
  3. The trough can be powered down during this procedure.
  4. \n
  5. The Wilhelmy balance should be locked in position out of the way.
  6. \n
  7. The polycarbonate lid should be removed (store it so that does not get \ncontaminated).
  8. \n
  9. Fill the trough with the 1:1 concentrated nitric:sulfuric acid solution. \nAllow to sit 10 + minutes.
  10. \n
  11. While the cleaning solution sits in the trough make sure the aspirator \ntrap is dry.
  12. \n
  13. Aspirate off the cleaning solution. \n
      \n
    • Unless the trough is extremely dirty the collected cleaning \nsolution may be returned to the cleaning solution storage bottle.
    • \n
    • If disposing of the cleaning solution treat it as strong acid waste and \nneutralize properly.
    • \n
  14. \n
  15. Rinse the trough twice with clean water subphase.
  16. \n
  17. Check the cleanliness of the trough
  18. \n
\n"}, {"fullname": "Trough.Trough_Control", "modulename": "Trough.Trough_Control", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_Control.message_utils", "modulename": "Trough.Trough_Control.message_utils", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_Control.message_utils.extract_messages", "modulename": "Trough.Trough_Control.message_utils", "qualname": "extract_messages", "kind": "function", "doc": "

Parameters

\n\n

datapkg: list\nlist of lists containing trough data bundle, messages in the last list.

\n\n

Returns

\n\n

list\nlist of strings consisting of the messages.

\n", "signature": "(datapkg):", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.simulation", "modulename": "Trough.Trough_Control.simulation", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_Control.simulation.simulated_troughctl", "modulename": "Trough.Trough_Control.simulation", "qualname": "simulated_troughctl", "kind": "function", "doc": "

Will run as separate process taking in commands through a pipe and\nreturning data on demand through a second pipe.

\n\n

Parameters

\n\n

CTLPipe: Pipe\n commands come in on and messages go out on.

\n\n

DATAPipe: Pipe\n data is sent out on

\n", "signature": "(CTLPipe, DATAPipe):", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util", "modulename": "Trough.Trough_Control.trough_util", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_Control.trough_util.isnumber", "modulename": "Trough.Trough_Control.trough_util", "qualname": "isnumber", "kind": "function", "doc": "
Parameters
\n\n
    \n
  • obj: object to be tested
  • \n
\n\n
Returns
\n\n
\n

True is a number.

\n
\n", "signature": "(obj):", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util.etol_call", "modulename": "Trough.Trough_Control.trough_util", "qualname": "etol_call", "kind": "function", "doc": "

Wrapping a callable object in this function will cause it to be called until\nit either returns without an error or the maximum recursion depth is reached.\nThis should only be used on calls that occasionally return errors because they\nare reading sensors or something like that.

\n\n

Parameters

\n\n

obj: callable

\n\n

param: list\n a list containing the parameters in the function call

\n\n

Returns

\n\n

result: any\n result of function call

\n", "signature": "(obj, param):", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util.is_trough_initialized", "modulename": "Trough.Trough_Control.trough_util", "qualname": "is_trough_initialized", "kind": "function", "doc": "

Checks for a running Trough process and good connections to it.

\n\n

Returns

\n\n

bool\nTRUE if initialized

\n", "signature": "():", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util.init_trough", "modulename": "Trough.Trough_Control.trough_util", "qualname": "init_trough", "kind": "function", "doc": "

This initializes the trough control subprocess and creates the pipes to communicate\nwith it.

\n\n

Returns

\n\n

pipe\ncmdsend: the end of the pipe to sent commands to the trough.

\n\n

pipe\ndatarcv: the end of the pipe the trough uses to send back data and messages.

\n\n

Process\nTROUGH: the process handle for the trough.

\n", "signature": "():", "funcdef": "def"}, {"fullname": "Trough.Trough_Control.trough_util.troughctl", "modulename": "Trough.Trough_Control.trough_util", "qualname": "troughctl", "kind": "function", "doc": "

Will run as separate process taking in commands through a pipe and\nreturning data on demand through a second pipe.\nIteration 1, collects data into a fifo and watches barrier position.

\n\n
Parameters
\n\n
    \n
  • Pipe CTLPipe: pipe commands come in on and messages go out on.
  • \n
  • Pipe DATAPipe: pipe data is sent out on
  • \n
\n", "signature": "(CTLPipe, DATAPipe):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI", "modulename": "Trough.Trough_GUI", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.Collect_data", "modulename": "Trough.Trough_GUI.Collect_data", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run", "kind": "class", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.__init__", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.__init__", "kind": "function", "doc": "

Create a new run object

\n\n

Parameters

\n\n

id: int\n 0 based index of run in current notebook\nfilename: str\n String representation of the filename used to store the data,\n with not type extension. This probably should not contain a path.\ntitle: str\n User friendly title (suggested default is same as filename).\nunits: str\n Units for the displayed barrier positions (cm, cm^2 or Ang^2/molec).\ntarget: float\n Numerical value in units for the targeted final trough area.\nspeed: float\n Numerical value in units for the speed to move the barriers.\nmoles: float\n moles of molecules initially spread in the trough.\nplate_circ: float\n circumference of the Whilhelmy plate in mm.\ndataframe: DataFrame or None\ntimestamp: float or None

\n", "signature": "(\tid,\tfilename,\ttitle,\tunits,\ttarget,\tspeed,\tmoles,\tplate_circ,\tdataframe=None,\ttimestamp=None)"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.from_html", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.from_html", "kind": "function", "doc": "

Create a run from an html representation

\n\n

Parameters

\n\n

html: str\n The html to be parsed to create the run object

\n\n

Returns

\n\n

trough_run: trough_run\n A trough_run object

\n", "signature": "(self, html):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.run_caption", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.run_caption", "kind": "function", "doc": "

Returns an html table with info about the run to use as a caption

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.init_collect_control", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.init_collect_control", "kind": "function", "doc": "

This initializes the collection control widgets and VBox that\ncontains them. The VBox may be accessed as self.collect_control

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.close_collect_control", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.close_collect_control", "kind": "function", "doc": "

This closes self.collect_control which also minimizes\nthe objects maintained on the Python side.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.to_html", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.to_html", "kind": "function", "doc": "

Create an html string representing a run

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.trough_run.write_run", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "trough_run.write_run", "kind": "function", "doc": "

Writes a run file with the base filename run.filename into the\ndirectory specified. If a file with the current name exists\nattempts to make the name unique by appending self.timestamp\nto the filename. Currently only produces\nan html file that is also human-readable. Other file formats may be\navailable in the future through the use of key word arguments.

\n\n

Parameters

\n\n

dirpath:\n pathlike object or string. Empty string means the current working\n directory.

\n\n

kwargs:\n optional key word arguments for future adaptability

\n", "signature": "(self, dirpath, **kwargs):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.Run", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "Run", "kind": "function", "doc": "

This routine creates a GUI for initializing, starting, collecting and\ncompleting a run. If the run has been completed it will simply reload it\nfrom the local datafile.

\n\n

Parameters

\n\n

run_name: str or Path\nThis should generally be the name for the file the data will be stored in\nwithout a file type extension. Recommend a naming scheme that produces\nUnique filenames, such as Trough_run_<username>_<timestamp>. The file\nname will be run_name.trh.run.html.

\n", "signature": "(run_name):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.collect_data_updater", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "collect_data_updater", "kind": "function", "doc": "

This is run in a separate thread and will update the figure and\nall status widgets at an interval of 2 seconds or a little longer. While\nthis is running nothing else will be able to talk to the trough.

\n\n

Parameters

\n\n

trough_lock: threading.lock\n When acquired this routine will talk to the trough. It is not\n released until the routine exits to avoid any data loss. It does\n call the status_widgets updater as often as it can while collecting\n the data.

\n\n

cmdsend: Pipe\n End of Pipe to send commands to the Trough.

\n\n

datarcv: Pipe\n End of Pipe to receive data from the Trough.

\n\n

cals: Trough_GUI.calibrations\n Used to convert the data to user units.

\n\n

lastdirection: multiprocessing.Value\n Of type 'i' to indicate last direction the barriers moved.

\n\n

run_updater: multiprocessing.Value\n Of type 'c_bool'. True if this updater should keep running.

\n\n

updater_running: multiprocessing.Value\n Of type 'c_bool'. Set to True by this process when it starts\n and set to False before exiting.

\n\n

run: trough_run\n This object contains the live figure and the place to store the data.

\n", "signature": "(\ttrough_lock,\tcmdsend,\tdatarcv,\tcals,\tlastdirection,\trun_updater,\tupdater_running,\trun):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Collect_data.update_collection", "modulename": "Trough.Trough_GUI.Collect_data", "qualname": "update_collection", "kind": "function", "doc": "

Updates the graph and the data storage

\n", "signature": "(datapkg, cals, lastdirection, run_updater, updater_running, run):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.Monitor_Calibrate", "modulename": "Trough.Trough_GUI.Monitor_Calibrate", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.Monitor_Calibrate.Monitor_Setup_Trough", "modulename": "Trough.Trough_GUI.Monitor_Calibrate", "qualname": "Monitor_Setup_Trough", "kind": "function", "doc": "

This produces a user interface in jupyter notebooks using ipywidgets. The\ninterface allows monitoring of the trough barrier positions, balance\nsignal, and temperature signal. The barrier positions can be\nadjusted using this interface. Calibrations of all the signals are\nperformed using this interface.

\n\n

Calibrations are stored in the calibration files in the .Trough/calibrations\ndirectory of the current user. The latest file is used. If none exists\none is created using default parameters. Users should calibrate all\nsignals before using the trough.

\n\n

NOTE: some objects used here are global and created by importing from\nstatus_widgets.py and command_widgets.py.

\n\n

Parameters

\n\n

calibrations: Calibrations\n The object containing the calibrations be used and modified. See\n Trough_GUI.calibration_utils.

\n", "signature": "(calibrations):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils", "modulename": "Trough.Trough_GUI.calibration_utils", "kind": "module", "doc": "

Utilities for:

\n\n
    \n
  • writing and reading calibration files stored in the local\nuser directory .Trough/calibrations.
  • \n
  • fitting calibration data to generate calibration parameters.
  • \n
  • converting between raw signal and user-friendly values.
  • \n
\n"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration", "kind": "class", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.__init__", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.__init__", "kind": "function", "doc": "

Defines a calibration of type name.

\n\n

Parameters

\n\n

name: str\n calibration name.

\n\n

units: str\n string representation of the units the calibration yields.

\n\n

timestamp: float\n Unix floating point timestamp.

\n\n

param:list\n list of the numerical parameters for the fit yielding the\n calibration.

\n\n

param_stdev: list\n list of the numerical values for the estimated standard\n deviation of the parameters from the fit.\nparam_inv: list\n list of the numerical values for the fit (or equation) yielding the\n inverse of the calibration (return to the raw value).\nparam_inv_stdev: list\n list of the numerical values for the estimated standard deviation of\n the parameters for the inversion.\ncal_data_x: list\n x-data used for the calibration fit.

\n\n

cal_data_y: list\n y-data used for the calibration fit.

\n\n

fit_type: str\n string name for the fit type. Defaults to \"polynomial\"

\n\n

fit_eqn_str: str\n string representation of the fit equation. Defaults to\n \"y = C0 + C1x + C2xx + C3xxx + ...\"

\n\n

fit_ceof_lbls: list\n list of string labels for the coefficients, which should\n correlate to symbols in the fit_eqn_str. Defaults to [\"C0\", \"C1\",\n ...]. Automatically, truncated to the actual number of\n coefficients determined by the order of the polynomial.

\n\n

additional_data:dict\n a dictionary of key:value pairs where the keys are a short\n descriptive string. They can contain any additional data\n necessary for doing calculations on the data.

\n", "signature": "(\tname,\tunits,\ttimestamp,\tparam,\tparam_stdev,\tparam_inv,\tparam_inv_stdev,\tcal_data_x,\tcal_data_y,\tfit_type='polynomial',\tfit_eqn_str='y = C0 + C1*x + C2*x*x + C3*x*x*x + ...',\tfit_ceof_lbls=['C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7'],\tadditional_data={})"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.cal_from_html", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.cal_from_html", "kind": "function", "doc": "

This takes in an html str, parses it and returns a new\ncalibration.

\n\n

Parameters

\n\n

html: str\n The html to be parsed to create the calibration object

\n\n

Returns

\n\n

calibration: calibration\n a calibration object.

\n", "signature": "(cls, html):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.cal_to_html", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.cal_to_html", "kind": "function", "doc": "

This routine creates an html str that would be human-readable in a\nbrowser detailing the calibration. This can be written to a file to\nstore the calibration.

\n\n

Returns

\n\n

calib_div: str\n string containing the html detailing the calibration.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.cal_apply", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.cal_apply", "kind": "function", "doc": "

\n", "signature": "(self, data, stdev):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibration.cal_inv", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibration.cal_inv", "kind": "function", "doc": "

\n", "signature": "(self, data, stdev):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibrations", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibrations", "kind": "class", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibrations.read_cal", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibrations.read_cal", "kind": "function", "doc": "

This routine reads in a calibration file. If it is the standard\nhtml file it uses calibration.cal_from_html() operation to convert\nit to a calibration.

\n\n

Parameters

\n\n

name: str\n either the basename (current options: 'balance', 'barriers_open',\n 'barriers_close', 'speed_open', 'speed_close' or\n 'temperature') or a string representation of the path to the\n calibration file to be read. If one of the basenames is used\n this code will look for the most recent calibration of that type\n in the directory '~.Trough\\calibrations'.

\n\n

Returns

\n\n

Calibration

\n", "signature": "(self, name):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibrations.write_cal", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibrations.write_cal", "kind": "function", "doc": "

Writes a calibration file with the base filename cal.name + int(\ncal.timestamp) into the directory specified. Currently only produces\nan html file that is also human-readable. Other file formats may be\navailable in the future through the use of key word arguments.

\n\n

Parameters

\n\n

dirpath:\n pathlike object or string

\n\n

cal: Calibration\n a calibration object containing the information about the\n calibration to write to the file.

\n\n

kwargs:\n optional key word arguments for future adaptability

\n", "signature": "(self, dirpath, cal, **kwargs):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.calibration_utils.Calibrations.poly_fit", "modulename": "Trough.Trough_GUI.calibration_utils", "qualname": "Calibrations.poly_fit", "kind": "function", "doc": "

Does a polynomial fit of the specified order using the x and y\nvalues provided.

\n\n

Parameters

\n\n

data_x: list\n of numerical x values.

\n\n

data_y: list\n of numerical y values.

\n\n

order: int\n the order of the polynomical used for fitting.

\n\n

yerr: float or iterable of float\n absolute error(s) in the y-value. Used to weight the fit. If no\n values are provided the assumption is equal weighting.

\n\n

Returns

\n\n

param: list\n of fitted parameters.

\n\n

param_stdev: list\n of estimated standard deviation in the parameters.

\n", "signature": "(self, data_x, data_y, order, yerr=None):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets", "modulename": "Trough.Trough_GUI.command_widgets", "kind": "module", "doc": "

\n"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_change_Barr_Units", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_change_Barr_Units", "kind": "function", "doc": "

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_change_Barr_Direction", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_change_Barr_Direction", "kind": "function", "doc": "

\n", "signature": "(changed):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_Barr_Target_change", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_Barr_Target_change", "kind": "function", "doc": "

Updates the speed settings since open and close are different.

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_click_Start", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_click_Start", "kind": "function", "doc": "

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.command_widgets.on_click_Stop", "modulename": "Trough.Trough_GUI.command_widgets", "qualname": "on_click_Stop", "kind": "function", "doc": "

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions", "modulename": "Trough.Trough_GUI.conversions", "kind": "module", "doc": "

This file contains unit conversion utility functions for use in the GUI

\n\n
    \n
  • To nest these functions replace the value, err part of the call with\n*func(...). For example sqcm_to_angpermolec(*cm_to_sqcm(9.2, 0.1, cals),\ncals)
  • \n
\n"}, {"fullname": "Trough.Trough_GUI.conversions.cm_to_sqcm", "modulename": "Trough.Trough_GUI.conversions", "qualname": "cm_to_sqcm", "kind": "function", "doc": "

convert barrier separation in cm to trough area in sqcm

\n", "signature": "(value, err, cals):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.sqcm_to_cm", "modulename": "Trough.Trough_GUI.conversions", "qualname": "sqcm_to_cm", "kind": "function", "doc": "

convert trough area in sqcm to barrier separation in cm

\n", "signature": "(value, err, cals):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.sqcm_to_angpermolec", "modulename": "Trough.Trough_GUI.conversions", "qualname": "sqcm_to_angpermolec", "kind": "function", "doc": "

convert trough area in sqcm to square angstroms per molecules

\n", "signature": "(value, err, moles):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.angpermolec_to_sqcm", "modulename": "Trough.Trough_GUI.conversions", "qualname": "angpermolec_to_sqcm", "kind": "function", "doc": "

convert trough area in sqcm to square angstroms per molecules

\n", "signature": "(value, err, moles):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.mg_to_mNperm", "modulename": "Trough.Trough_GUI.conversions", "qualname": "mg_to_mNperm", "kind": "function", "doc": "

convert balance measurement in mg to milliNewtons per meter

\n", "signature": "(value, err, pi_tare, plate_circ):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.conversions.nNperm_to_mg", "modulename": "Trough.Trough_GUI.conversions", "qualname": "nNperm_to_mg", "kind": "function", "doc": "

convert surface pressure in milliNewtons per meter to mg

\n", "signature": "(value, err, pi_tare, plate_circ):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.status_widgets", "modulename": "Trough.Trough_GUI.status_widgets", "kind": "module", "doc": "

This file contains widgets that display updating trough information and\ncan be used in multiple ipywidget panels within the same notebook.

\n"}, {"fullname": "Trough.Trough_GUI.status_widgets.set_zero_pressure", "modulename": "Trough.Trough_GUI.status_widgets", "qualname": "set_zero_pressure", "kind": "function", "doc": "

\n", "signature": "(change):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.status_widgets.update_status", "modulename": "Trough.Trough_GUI.status_widgets", "qualname": "update_status", "kind": "function", "doc": "

Call this routine to update the contents of all the status widgets.

\n\n

Parameters

\n\n

raw_data: dict\n dictionary of latest raw data values for each\n sensor and their standard deviation\n (e.g. {'bal_raw':3.20,'bal_dev':0.005,'barr_raw':0.5,'barr_dev':0.002,\n 'temp_raw':2.24, 'temp_dev':0.01, 'messages':''})

\n\n

calibrations: Calibrations\n Object containing the calibrations for the trough (currently\n .balance, .barriers and .temperature). A call to\n .balance.cal_apply(raw_data['bal_raw'],raw_data['bal_dev'])\n will return the balance reading in the calibration units (.balance.units).

\n", "signature": "(raw_data: dict, calibrations, lastdirection):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.status_widgets.status_updater", "modulename": "Trough.Trough_GUI.status_widgets", "qualname": "status_updater", "kind": "function", "doc": "

This is run in a separate thread and will update the status widgets\nevery 2 seconds or when it can get access to the pipes to talk to the\ntrough.

\n\n

Parameters

\n\n

trough_lock: threading.lock\n When acquired this routine will talk to the trough. Releases it for\n other processes after every update.

\n\n

cmdsend: Pipe\n End of Pipe to send commands to the Trough.

\n\n

datarcv: Pipe\n End of Pipe to receive data from the Trough.

\n\n

cals: Trough_GUI.calibrations\n Used to convert the data to user units.

\n\n

lastdirection: multiprocessing.Value\n Of type 'i' to indicate last direction the barriers moved.

\n\n

run_updater: multiprocessing.Value\n Of type 'c_bool'. True if this updater should keep running.

\n\n

updater_running: multiprocessing.Value\n Of type 'c_bool'. Set to True by this process when it starts\n and set to False before exiting.

\n", "signature": "(\ttrough_lock,\tcmdsend,\tdatarcv,\tcals,\tlastdirection,\trun_updater,\tupdater_running):", "funcdef": "def"}, {"fullname": "Trough.Trough_GUI.status_widgets.start_status_updater", "modulename": "Trough.Trough_GUI.status_widgets", "qualname": "start_status_updater", "kind": "function", "doc": "

\n", "signature": "():", "funcdef": "def"}]; // mirrored in build-search-index.js (part 1) // Also split on html tags. this is a cheap heuristic, but good enough. diff --git a/setup.py b/setup.py index 3b9fc11..c88860d 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="langmuir_trough", - version="0.6.0dev", + version="0.6.0", description="Controls and collects data from Gutow Lab Langmuir Trough.", long_description=long_description, long_description_content_type="text/markdown",