1cca2c9e66bf5bb0d63477e9d8d293d851b10d42
[calibcant.git] / calibcant / temperature_analyze.py
1 # calibcant - tools for thermally calibrating AFM cantilevers
2 #
3 # Copyright (C) 2008-2012 W. Trevor King <wking@drexel.edu>
4 #
5 # This file is part of calibcant.
6 #
7 # calibcant is free software: you can redistribute it and/or modify it under
8 # the terms of the GNU General Public License as published by the Free Software
9 # Foundation, either version 3 of the License, or (at your option) any later
10 # version.
11 #
12 # calibcant is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # calibcant.  If not, see <http://www.gnu.org/licenses/>.
18
19 """Temperature analysis.
20
21 Separate the more general `temperature.analyze()` from the other
22 `temperature.*()` functions in calibcant.
23
24 The relevant physical quantities are:
25
26 * `T` Temperature at which thermal vibration measurements were acquired
27
28 >>> import os
29 >>> from pprint import pprint
30 >>> import tempfile
31 >>> import numpy
32 >>> from .config import TemperatureConfig
33 >>> from h5config.storage.hdf5 import pprint_HDF5, HDF5_Storage
34
35 >>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-')
36 >>> os.close(fd)
37
38 >>> config = TemperatureConfig()
39
40 >>> raw = 296.5
41 >>> processed = analyze(config=config, temperature=raw)
42 >>> plot(raw=raw, processed=processed)
43 >>> save(filename=filename, group='/',
44 ...     config=config, raw=raw, processed=processed)
45
46 >>> pprint_HDF5(filename)  # doctest: +REPORT_UDIFF
47 /
48   /config
49     /config/temperature
50       <HDF5 dataset "sleep": shape (), type "<i4">
51         1
52   /processed
53     <HDF5 dataset "data": shape (), type "<f8">
54       296.5
55     <HDF5 dataset "units": shape (), type "|S1">
56       K
57   /raw
58     <HDF5 dataset "data": shape (), type "<f8">
59       296.5
60     <HDF5 dataset "units": shape (), type "|S1">
61       K
62
63 >>> data = load(filename=filename, group='/')
64
65 >>> pprint(data)  # doctest: +ELLIPSIS
66 {'config': {'temperature': <TemperatureConfig ...>},
67  'processed': 296.5,
68  'raw': 296.5}
69
70 >>> print(data['config']['temperature'].dump())
71 sleep: 1.0
72 >>> data['raw']
73 296.5
74 >>> type(data['raw'])
75 <type 'float'>
76 >>> data['processed']
77 296.5
78
79 >>> os.remove(filename)
80 """
81
82 import h5py as _h5py
83
84 try:
85     import matplotlib as _matplotlib
86     import matplotlib.pyplot as _matplotlib_pyplot
87     import time as _time  # for timestamping lines on plots
88 except (ImportError, RuntimeError), e:
89     _matplotlib = None
90     _matplotlib_import_error = e
91
92 from h5config.storage.hdf5 import HDF5_Storage as _HDF5_Storage
93 from h5config.storage.hdf5 import h5_create_group as _h5_create_group
94
95 from . import LOG as _LOG
96 from . import package_config as _package_config
97 from .config import TemperatureConfig as _TemperatureConfig
98 from .util import SaveSpec as _SaveSpec
99 from .util import save as _save
100 from .util import load as _load
101
102
103 def analyze(config, temperature, units='Kelvin'):
104     """Convert measured temperature to Kelvin.
105
106     `temperature` should be a numpy ndarray or scalar.  `config`
107     should be a `config._temperatureemperatureConfig` instance.
108
109     The `units` option is just for fun.  The AFM's `get_temperature`
110     method always returns temperatures in Kelvin.
111     """
112     if units == 'Kelvin':
113         return temperature
114     elif units == 'Celsius':
115         return _C2K(temperature)
116     else:
117         raise NotImplementedError()
118
119
120 def save(filename, group='/', config=None, raw=None, processed=None):
121     specs = [
122         _SaveSpec(item=config, relpath='config/temperature',
123                   config=_TemperatureConfig),
124         _SaveSpec(item=raw, relpath='raw', units='K'),
125         _SaveSpec(item=processed, relpath='processed', units='K'),
126         ]
127     _save(filename=filename, group=group, specs=specs)
128
129 def load(filename=None, group='/'):
130     specs = [
131         _SaveSpec(key=('config', 'temperature',), relpath='config/temperature',
132                   config=_TemperatureConfig),
133         _SaveSpec(key=('processed',), relpath='processed', units='K'),
134         _SaveSpec(key=('raw',), relpath='raw', units='K'),
135         ]
136     return _load(filename=filename, group=group, specs=specs)
137
138 def plot(raw=None, processed=None):
139     if not _matplotlib:
140         raise _matplotlib_import_error
141     figure = _matplotlib_pyplot.figure()
142     timestamp = _time.strftime('%H%M%S')
143     if raw is None:
144         if processed is None:
145             return  # nothing to plot
146         axes1 = None
147         axes2 = figure.add_subplot(1, 1, 1)
148     elif processed is None:
149         axes1 = figure.add_subplot(1, 1, 1)
150         axes2 = None
151     else:
152         axes1 = figure.add_subplot(2, 1, 1)
153         axes2 = figure.add_subplot(2, 1, 2)
154     if axes1:
155         axes1.set_title('Raw Temperatures %s' % timestamp)
156         axes1.plot(raw, label='raw')
157     if axes2:
158         axes2.set_title('Processed Temperatures %s' % timestamp)
159         axes2.plot(processed, label='processed')
160     if hasattr(figure, 'show'):
161         figure.show()