Add pyafm.storage module with save_afm and load_afm.
authorW. Trevor King <wking@drexel.edu>
Thu, 15 Mar 2012 20:44:30 +0000 (16:44 -0400)
committerW. Trevor King <wking@drexel.edu>
Thu, 15 Mar 2012 20:52:44 +0000 (16:52 -0400)
Also remove some underscore prefixes from the AFM doctests.  I'm too
used to trying to keep the modules themselves clean, but that's no
reason to go confusing newbies ;).

pyafm/afm.py
pyafm/storage.py [new file with mode: 0644]

index 2681b56f0ee1d0f3b095ebb75ff192bd61c1f470..a68b77219334a72345209796b1211139353f50fd 100644 (file)
@@ -50,30 +50,37 @@ class AFM (object):
     temperature | temperature.Controller instance or None
         Optional temperature monitoring and control.
 
+    >>> import os
+    >>> import tempfile
     >>> from pycomedi.device import Device
-    >>> from pycomedi import constant as _constant
-    >>> import pypiezo.config as _pypiezo_config
-    >>> import pyafm.config as _config
+    >>> from pycomedi import constant
+    >>> import pypiezo.config
+    >>> import pyafm.config
+    >>> import pyafm.storage
+    >>> from h5config.storage.hdf5 import pprint_HDF5
+
+    >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='pyafm-')
+    >>> os.close(fd)
 
     >>> device = Device('/dev/comedi0')
     >>> device.open()
 
-    >>> config = _config.AFMConfig()
-    >>> config['piezo'] = _pypiezo_config.PiezoConfig()
+    >>> config = pyafm.config.AFMConfig()
+    >>> config['piezo'] = pypiezo.config.PiezoConfig()
     >>> config['piezo']['name'] = 'test piezo'
-    >>> config['piezo']['axes'] = [_pypiezo_config.AxisConfig()]
+    >>> config['piezo']['axes'] = [pypiezo.config.AxisConfig()]
     >>> config['piezo']['axes'][0]['channel'] = (
-    ...     _pypiezo_config.OutputChannelConfig())
+    ...     pypiezo.config.OutputChannelConfig())
     >>> config['piezo']['axes'][0]['channel']['name'] = 'z'
-    >>> config['piezo']['inputs'] = [_pypiezo_config.InputChannelConfig()]
+    >>> config['piezo']['inputs'] = [pypiezo.config.InputChannelConfig()]
     >>> config['piezo']['inputs'][0]['name'] = 'deflection'
-    >>> config['stepper'] = _config.StepperConfig()
-    >>> config['stepper']['port'] = _config.DigitalPortConfig()
+    >>> config['stepper'] = pyafm.config.StepperConfig()
+    >>> config['stepper']['port'] = pyafm.config.DigitalPortConfig()
     >>> config['stepper']['port']['channels'] = [1, 2, 3, 4]
-    >>> config['stepper']['port']['direction'] = _constant.IO_DIRECTION.output
+    >>> config['stepper']['port']['direction'] = constant.IO_DIRECTION.output
     >>> config['stepper']['port']['name'] = 'stepper port'
     >>> config['stepper']['name'] = 'test stepper'
-    >>> config['temperature'] = _config.TemperatureConfig()
+    >>> config['temperature'] = pyafm.config.TemperatureConfig()
     >>> config['temperature']['name'] = 'test temperature'
 
     >>> afm = AFM(config=config, devices=[device])
@@ -142,9 +149,128 @@ class AFM (object):
       max-current: 0.0
     far: 3e-05
 
+    >>> pyafm.storage.save_afm(afm=afm, filename=filename)
+    >>> pprint_HDF5(filename=filename)  # doctest: +REPORT_UDIFF
+    /
+      <HDF5 dataset "far": shape (), type "<f8">
+        3e-05
+      <HDF5 dataset "main-axis": shape (), type "|S1">
+    <BLANKLINE>
+      <HDF5 dataset "name": shape (), type "|S1">
+    <BLANKLINE>
+      /piezo
+        /piezo/axes
+          /piezo/axes/0
+            /piezo/axes/0/channel
+              <HDF5 dataset "analog-reference": shape (), type "|S6">
+                ground
+              <HDF5 dataset "channel": shape (), type "<i4">
+                0
+              <HDF5 dataset "conversion-coefficients": shape (2,), type "<f8">
+                [ -1.00000000e+01   3.05180438e-04]
+              <HDF5 dataset "conversion-origin": shape (), type "<f8">
+                0.0
+              <HDF5 dataset "device": shape (), type "|S12">
+                /dev/comedi0
+              <HDF5 dataset "inverse-conversion-coefficients": shape (2,), type "<f8">
+                [    0.    3276.75]
+              <HDF5 dataset "inverse-conversion-origin": shape (), type "<f8">
+                -10.0
+              <HDF5 dataset "maxdata": shape (), type "<i8">
+                65535
+              <HDF5 dataset "name": shape (), type "|S1">
+                z
+              <HDF5 dataset "range": shape (), type "<i4">
+                0
+              <HDF5 dataset "subdevice": shape (), type "<i4">
+                1
+            <HDF5 dataset "gain": shape (), type "<f8">
+              1.0
+            <HDF5 dataset "maximum": shape (), type "<f8">
+              10.0
+            <HDF5 dataset "minimum": shape (), type "<f8">
+              -10.0
+            <HDF5 dataset "monitor": shape (), type "|S1">
+    <BLANKLINE>
+            <HDF5 dataset "sensitivity": shape (), type "<f8">
+              1.0
+        /piezo/inputs
+          /piezo/inputs/0
+            <HDF5 dataset "analog-reference": shape (), type "|S6">
+              ground
+            <HDF5 dataset "channel": shape (), type "<i4">
+              0
+            <HDF5 dataset "conversion-coefficients": shape (2,), type "<f8">
+              [ -1.00000000e+01   3.05180438e-04]
+            <HDF5 dataset "conversion-origin": shape (), type "<f8">
+              0.0
+            <HDF5 dataset "device": shape (), type "|S12">
+              /dev/comedi0
+            <HDF5 dataset "inverse-conversion-coefficients": shape (2,), type "<f8">
+              [    0.    3276.75]
+            <HDF5 dataset "inverse-conversion-origin": shape (), type "<f8">
+              -10.0
+            <HDF5 dataset "maxdata": shape (), type "<i8">
+              65535
+            <HDF5 dataset "name": shape (), type "|S10">
+              deflection
+            <HDF5 dataset "range": shape (), type "<i4">
+              0
+            <HDF5 dataset "subdevice": shape (), type "<i4">
+              0
+        <HDF5 dataset "name": shape (), type "|S10">
+          test piezo
+      /stepper
+        <HDF5 dataset "backlash": shape (), type "<i4">
+          100
+        <HDF5 dataset "delay": shape (), type "<f8">
+          0.01
+        <HDF5 dataset "full-step": shape (), type "|b1">
+          True
+        <HDF5 dataset "logic": shape (), type "|b1">
+          True
+        <HDF5 dataset "name": shape (), type "|S12">
+          test stepper
+        /stepper/port
+          <HDF5 dataset "channels": shape (4,), type "<i4">
+            [1 2 3 4]
+          <HDF5 dataset "device": shape (), type "|S12">
+            /dev/comedi0
+          <HDF5 dataset "direction": shape (), type "|S6">
+            output
+          <HDF5 dataset "name": shape (), type "|S12">
+            stepper port
+          <HDF5 dataset "subdevice": shape (), type "<i4">
+            2
+          <HDF5 dataset "subdevice-type": shape (), type "|S3">
+            dio
+        <HDF5 dataset "step-size": shape (), type "<f8">
+          1.7e-07
+      /temperature
+        <HDF5 dataset "baudrate": shape (), type "<i4">
+          9600
+        <HDF5 dataset "controller": shape (), type "<i4">
+          1
+        <HDF5 dataset "device": shape (), type "|S10">
+          /dev/ttyS0
+        <HDF5 dataset "max-current": shape (), type "<f8">
+          0.0
+        <HDF5 dataset "name": shape (), type "|S16">
+          test temperature
+        <HDF5 dataset "units": shape (), type "|S7">
+          Celsius
+    >>> afm2 = pyafm.storage.load_afm(filename=filename, devices=[device])
+
+    >>> afm2.get_temperature()  # doctest: +SKIP
+    297.37
+
     It's hard to test anything else without pugging into an actual AFM.
 
     >>> device.close()
+
+    Cleanup our temporary config file.
+
+    >>> os.remove(filename)
     """
     def __init__(self, config, piezo=None, stepper=None, temperature=None,
                  devices=None):
diff --git a/pyafm/storage.py b/pyafm/storage.py
new file mode 100644 (file)
index 0000000..562df94
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright
+
+import os.path as _os_path
+
+import h5py as _h5py
+from h5config.storage.hdf5 import HDF5_Storage as _HDF5_Storage
+
+from . import LOG as _LOG
+from .afm import AFM as AFM
+from .config import AFMConfig as _AFMConfig
+
+
+DEFAULT_FILENAME = _os_path.expanduser(_os_path.join(
+        '~', '.config', 'pyafm-default.h5'))
+DEFAULT_GROUP = '/'
+
+
+def save_afm(afm, filename=None, group=None):
+    if filename is None:
+        filename = DEFAULT_FILENAME
+    if group is None:
+        group = DEFAULT_GROUP
+    assert group.endswith('/'), group
+    _LOG.info('saving AFM config to {} {}'.format(filename, group))
+    storage = _HDF5_Storage(filename=filename, group=group)
+    storage.save(config=afm.config)
+    
+def load_afm(filename=None, group=None, devices=None):
+    if filename is None:
+        filename = DEFAULT_FILENAME
+    if group is None:
+        group = DEFAULT_GROUP
+    assert group.endswith('/'), group
+    _LOG.info('loading AFM config from {} {}'.format(filename, group))
+    config = _AFMConfig(storage=_HDF5_Storage(filename=filename, group=group))
+    _LOG.debug(
+        'constructing AFM from configuration:\n{}'.format(config.dump()))
+    return AFM(config=config, devices=devices)