X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;ds=sidebyside;f=calibcant%2FT_analyze.py;h=3635e2d52c362e4be10aa7cb98d202b177862b8d;hb=607535583cd8f3f4315cda669114e759e5b269ec;hp=6f0a8a12795dac041b2ba2108e1b9b0383adc479;hpb=c6c3e6cec609e7309276fae149e9088bebdc5d0f;p=calibcant.git diff --git a/calibcant/T_analyze.py b/calibcant/T_analyze.py old mode 100755 new mode 100644 index 6f0a8a1..3635e2d --- a/calibcant/T_analyze.py +++ b/calibcant/T_analyze.py @@ -1,199 +1,167 @@ -#!/usr/bin/python -# # calibcant - tools for thermally calibrating AFM cantilevers # -# Copyright (C) 2007,2008, William Trevor King +# Copyright (C) 2008-2012 W. Trevor King # -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 3 of the -# License, or (at your option) any later version. +# This file is part of calibcant. # -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the GNU General Public License for more details. +# calibcant is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -# 02111-1307, USA. +# calibcant is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. # -# The author may be contacted at on the Internet, or -# write to Trevor King, Drexel University, Physics Dept., 3141 Chestnut St., -# Philadelphia PA 19104, USA. +# You should have received a copy of the GNU General Public License along with +# calibcant. If not, see . -""" -Separate the more general T_analyze() from the other T_*() -functions in calibcant. Also provide a command line interface -for analyzing data acquired through other workflows. +"""Temperature analysis. + +Separate the more general `T_analyze()` from the other `T_*()` +functions in calibcant. + +The relevant physical quantities are: + +* `T` Temperature at which thermal vibration measurements were acquired + +>>> import os +>>> import tempfile +>>> import numpy +>>> from .config import TemperatureConfig +>>> from h5config.storage.hdf5 import pprint_HDF5, HDF5_Storage -The relevant physical quantities are : - T Temperature at which thermal vibration measurements were aquired +>>> fd,filename = tempfile.mkstemp(suffix='.h5', prefix='calibcant-') +>>> os.close(fd) + +>>> temperature_config = TemperatureConfig(storage=HDF5_Storage( +... filename=filename, group='/T/config/')) + +>>> raw_T = numpy.array([22, 23.5, 24]) +>>> processed_T = T_analyze(raw_T, temperature_config) +>>> T_plot(raw_T=raw_T, processed_T=processed_T) +>>> T_save(filename=filename, group='/T/', raw_T=raw_T, +... temperature_config=temperature_config, processed_T=processed_T) + +>>> pprint_HDF5(filename) # doctest: +REPORT_UDIFF +/ + /T + /T/config + + True + + Celsius + + [ 295.15 296.65 297.15] + + [ 22. 23.5 24. ] + +>>> raw_T,temperature_config,processed_T = T_load( +... filename=filename, group='/T/') +>>> print temperature_config.dump() +units: Celsius +default: yes +>>> raw_T +array([ 22. , 23.5, 24. ]) +>>> type(raw_T) + +>>> processed_T +array([ 295.15, 296.65, 297.15]) + +>>> os.remove(filename) """ -import numpy -import common # common module for the calibcant package -import config # config module for the calibcant package -import data_logger -import linfit -from splittable_kwargs import splittableKwargsFunction, \ - make_splittable_kwargs_function +import h5py as _h5py +from scipy.constants import C2K as _C2K -def C_to_K(celsius) : - "Convert Celsius -> Kelvin." - return celsius + 273.15 +try: + import matplotlib as _matplotlib + import matplotlib.pyplot as _matplotlib_pyplot + import time as _time # for timestamping lines on plots +except (ImportError, RuntimeError), e: + _matplotlib = None + _matplotlib_import_error = e -def K_to_K(kelvin) : - "Convert Kelvin -> Kelvin." - return kelvin +from h5config.storage.hdf5 import HDF5_Storage as _HDF5_Storage +from h5config.storage.hdf5 import h5_create_group as _h5_create_group -@splittableKwargsFunction() -def T_analyze(T, convert_to_K=C_to_K) : - """ - Not much to do here, just convert to Kelvin. - Uses C_to_K (defined above) by default. - """ - try : # if T is an array, convert element by element - for i in range(len(T)) : - T[i] = convert_to_K(T[i]) - except TypeError : # otherwise, make an array from a single T - T = [convert_to_K(T)] - return T - -@splittableKwargsFunction() -def T_save(T, log_dir=None) : - """ - Save either a single T (if you are crazy :p), - or an array of them (more reasonable) - """ - T = numpy.array(T, dtype=numpy.float) - if log_dir != None : - log = data_logger.data_log(log_dir, noclobber_logsubdir=False, - log_name="T_float") - log.write_binary(T.tostring()) - if config.LOG_DATA != None : - log = data_logger.data_log(config.LOG_DIR, noclobber_logsubdir=False, - log_name="T_float") - log.write_binary(T.tostring()) - -def T_load(datafile=None) : - """ - Load the saved T array (possibly of length 1), and return it. If - datafile == None, return an array of one config.DEFAULT_TEMP - instead. - """ - if datafile == None : - return numpy.array([config.DEFAULT_TEMP], dtype=numpy.float) - else : - dl = data_logger.data_load() - return dl.read_binary(datafile) - -@splittableKwargsFunction() -def T_plot(T, plotVerbose=False) : - """ - Umm, just print the temperature? +from . import LOG as _LOG +from . import package_config as _package_config +from .config import Celsius as _Celsius +from .config import Kelvin as _Kelvin +from .config import TemperatureConfig as _TemperatureConfig + + +def T_analyze(T, temperature_config): + """Convert measured temperature to Kelvin. + + `T` should be a numpy ndarray or scalar. `temperature_config` + should be a `config._TemperatureConfig` instance. """ - if plotVerbose or config.PYLAB_VERBOSE or config.TEXT_VERBOSE : - print "Temperature ", T - -@splittableKwargsFunction((T_analyze, 'T', 'convert_to_K'), - (T_plot, 'T')) -def T_load_analyze_tweaked(tweak_file, convert_to_K=C_to_K, textVerboseFile=None, **kwargs) : - "Load all the T array files from a tweak file and return a single array" - T_analyze_kwargs,T_plot_kwargs = \ - T_load_analyze_tweaked._splitargs(T_load_analyze_tweaked, kwargs) - Ts = [] - for line in file(tweak_file, 'r') : - parsed = line.split() - path = parsed[0].split('\n')[0] - if textVerboseFile != None : - print >> textVerboseFile, "Reading data from %s" % (path) - # read the data - data = T_load(path) - Ts.extend(data) - T_analyze(Ts, convert_to_K=convert_to_K) - return numpy.array(Ts, dtype=numpy.float) - -# commandline interface functions -import scipy.io, sys - -def read_data(ifile): - "ifile can be a filename string or open (seekable) file object" - if ifile == None : ifile = sys.stdin - unlabeled_data=scipy.io.read_array(ifile) - return unlabeled_data - -if __name__ == '__main__' : - # command line interface - from optparse import OptionParser - - usage_string = ('%prog \n' - '2008, W. Trevor King.\n' - '\n' - 'There are two operation modes, one to analyze a single T (temperature) file,\n' - 'and one to analyze tweak files.\n' - '\n' - 'Single file mode (the default) :\n' - 'Reads in single column ASCII file of temperatures and... prints them back out.\n' - 'No need to do this, but the option is available for consistency with the other\n' - 'calibcant modules.\n' - '\n' - 'Tweak file mode:\n' - 'Runs the same analysis as in single file mode for each T file in\n' - 'a tweak file. Each line in the tweak file specifies a single T file.\n' - 'A T file contains a sequence of 32 bit floats representing temperature in K.\n' - ) - parser = OptionParser(usage=usage_string, version='%prog 0.1') - parser.add_option('-C', '--celsius', dest='celsius', - help='Use Celsius input temperatures instead of Kelvin (default %default)\n', - action='store_true', default=False) - parser.add_option('-o', '--output-file', dest='ofilename', - help='write output to FILE (default stdout)', - type='string', metavar='FILE') - parser.add_option('-c', '--comma-out', dest='comma_out', action='store_true', - help='Output comma-seperated values (default %default)', - default=False) - parser.add_option('-t', '--tweak-mode', dest='tweakmode', action='store_true', - help='Run in tweak-file mode', - default=False) - parser.add_option('-v', '--verbose', dest='verbose', action='store_true', - help='Print lots of debugging information', - default=False) - - options,args = parser.parse_args() - parser.destroy() - assert len(args) >= 1, "Need an input file" - - ifilename = args[0] - - if options.ofilename != None : - ofile = file(options.ofilename, 'w') - else : - ofile = sys.stdout - if options.verbose == True : - vfile = sys.stderr - else : - vfile = None - config.TEXT_VERBOSE = options.verbose - config.PYLAB_VERBOSE = False - config.GNUPLOT_VERBOSE = False - if options.celsius : - convert_to_K = C_to_K - else : - convert_to_K = K_to_K - - if options.tweakmode == False : - data = read_data(ifilename) - Ts = T_analyze(data, convert_to_K) - else : # tweak file mode - Ts = T_load_analyze_tweaked(ifilename, convert_to_K, textVerboseFile=vfile) - - if options.comma_out : - sep = ',' - else : - sep = '\n' - common.write_array(ofile, Ts, sep) - - if options.ofilename != None : - ofile.close() + if temperature_config['units'] == _Celsius: + return _C2K(T) + else: + return T + +def T_save(filename, group='/', raw_T=None, temperature_config=None, + processed_T=None): + with _h5py.File(filename, 'a') as f: + cwg = _h5_create_group(f, group) + if raw_T is not None: + try: + del cwg['raw'] + except KeyError: + pass + cwg['raw'] = raw_T + if temperature_config is not None: + config_cwg = _h5_create_group(cwg, 'config') + storage = _HDF5_Storage() + storage.save(config=temperature_config, group=config_cwg) + if processed_T is not None: + try: + del cwg['processed'] + except KeyError: + pass + cwg['processed'] = processed_T + +def T_load(filename, group='/'): + assert group.endswith('/') + raw_T = processed_T = None + with _h5py.File(filename, 'a') as f: + try: + raw_T = f[group+'raw'][...] + except KeyError: + pass + temperature_config = _TemperatureConfig(storage=_HDF5_Storage( + filename=filename, group=group+'config/')) + try: + processed_T = f[group+'processed'][...] + except KeyError: + pass + temperature_config.load() + return (raw_T, temperature_config, processed_T) + +def T_plot(raw_T=None, processed_T=None): + if not _matplotlib: + raise _matplotlib_import_error + figure = _matplotlib_pyplot.figure() + timestamp = _time.strftime('%H%M%S') + if raw_T is None: + if processed_T is None: + return # nothing to plot + axes1 = None + axes2 = figure.add_subplot(1, 1, 1) + elif processed_T is None: + axes1 = figure.add_subplot(1, 1, 1) + axes2 = None + else: + axes1 = figure.add_subplot(2, 1, 1) + axes2 = figure.add_subplot(2, 1, 2) + if axes1: + axes1.set_title('Raw Temperatures %s' % timestamp) + axes1.plot(raw_T, label='raw') + if axes2: + axes2.set_title('Processed Temperatures %s' % timestamp) + axes2.plot(processed_T, label='processed') + if hasattr(figure, 'show'): + figure.show()