-# Copyright (C) 2006-2010 Alberto Gomez-Casado
+# Copyright (C) 2006-2012 Alberto Gomez-Casado <a.gomezcasado@tnw.utwente.nl>
# Massimo Sandal <devicerandom@gmail.com>
-# W. Trevor King <wking@drexel.edu>
+# W. Trevor King <wking@tremily.us>
#
# This file is part of Hooke.
#
-# Hooke is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
+# Hooke is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
#
-# Hooke 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 Lesser General
-# Public License for more details.
+# Hooke 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 Lesser General Public License for more
+# details.
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with Hooke. If not, see
-# <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU Lesser General Public License
+# along with Hooke. If not, see <http://www.gnu.org/licenses/>.
-"""Driver for Veeco PicoForce force spectroscopy files.
+"""Driver for Bruker PicoForce force spectroscopy files.
"""
+import os.path
import pprint
import re
import time
import numpy
from .. import curve as curve # this module defines data containers.
-from .. import experiment as experiment # this module defines expt. types
from . import Driver as Driver # this is the Driver base class
-__version__='0.0.0.20100516'
+__version__='0.0.0.20110421'
+
class PicoForceDriver (Driver):
- """Handle Veeco Picoforce force spectroscopy files.
+ """Handle Bruker Picoforce force spectroscopy files.
"""
def __init__(self):
super(PicoForceDriver, self).__init__(name='picoforce')
def is_me(self, path):
+ if os.path.isdir(path):
+ return False
f = file(path, 'r')
header = f.read(30)
f.close()
info = self._read_header_path(path)
self._check_version(info)
data = self._read_data_path(path, info)
- info['filetype'] = self.name
- info['experiment'] = experiment.VelocityClamp
return (data, info)
def _read_header_path(self, path):
Otherwise, raise `ValueError`.
"""
version = info['Force file list'].get('Version', None)
- if version not in ['0x06120002', '0x06130001', '0x07200000']:
+ if version not in ['0x05120005', '0x06120002', '0x06130001',
+ '0x07200000']:
raise NotImplementedError(
'%s file version %s not supported (yet!)\n%s'
% (self.name, version,
traces = {}
version = info['Force file list']['Version']
type_re = re.compile('S \[(\w*)\] "([\w\s.]*)"')
+ if isinstance(info['Ciao force image list'], dict):
+ # there was only one image, but convert to list for processing
+ info['Ciao force image list'] = [info['Ciao force image list']]
for image in info['Ciao force image list']:
offset = int(image['Data offset'])
length = int(image['Data length'])
offset=offset,
info=image,
)
- if version in ['0x06120002', '0x06130001']:
+ if version in ['0x05120005', '0x06120002', '0x06130001']:
match = type_re.match(image['@4:Image Data'])
assert match != None, 'Bad regexp for %s, %s' \
% ('@4:Image Data', image['@4:Image Data'])
#d.tofile('%s.dat' % tname, sep='\n')
pass
traces[tname] = d
+ if 'Z sensor' not in traces:
+ # some picoforce files only save deflection
+ assert version == '0x05120005', version
+ force_info = info['Ciao force list']
+ deflection = traces['Deflection']
+ volt_re = re.compile(
+ 'V \[Sens. ([\w\s.]*)\] \(([.0-9]*) V/LSB\) *(-?[.0-9]*) V')
+ match = volt_re.match(force_info['@4:Ramp size Zsweep'])
+ size = float(match.group(3))
+ match = volt_re.match(force_info['@4:Ramp offset Zsweep'])
+ offset = float(match.group(3))
+ match = volt_re.match(force_info['@4:Ramp Begin Zsweep'])
+ begin = float(match.group(3))
+ match = volt_re.match(force_info['@4:Ramp End Zsweep'])
+ end = float(match.group(3))
+ #\@4:Feedback value Zsweep: V [Sens. Zscan] (0.002056286 V/LSB) 0 V
+ #\@4:Z display Zsweep: V [Sens. Zscan] (0.002056286 V/LSB) 18.53100 V
+ assert len(deflection) % 2 == 0, len(deflection)
+ points = len(deflection)/2
+ traces['Z sensor'] = curve.Data(
+ shape=deflection.shape,
+ dtype=numpy.float,
+ info=info['Ciao force image list'][0],
+ )
+ # deflection data seems to be saved as
+ # [final approach, ..., initial approach,
+ # initial retract, ..., final retract]
+ traces['Z sensor'][:points] = numpy.linspace(
+ offset+begin+size, offset+begin, points)
+ traces['Z sensor'][-points:] = numpy.linspace(
+ offset+begin+size, offset+end, points)
return traces
def _validate_traces(self, z_piezo, deflection):
def _translate_block_info(self, info, z_piezo_info, deflection_info, name):
version = info['Force file list']['Version']
+ if version == '0x05120005':
+ k_key = 'Spring constant'
+ else:
+ assert version in [
+ '0x06120002', '0x06130001', '0x07200000'], version
+ k_key = 'Spring Constant'
ret = {
'name': name,
'raw info': info,
'raw z piezo info': z_piezo_info,
'raw deflection info': deflection_info,
- 'spring constant (N/m)': float(z_piezo_info['Spring Constant']),
+ 'spring constant (N/m)': float(z_piezo_info[k_key]),
}
t = info['Force file list']['Date'] # 04:42:34 PM Tue Sep 11 2007
'V \[Sens. ([\w\s.]*)\] \(([.0-9]*) V/LSB\) (-?[.0-9]*) V')
hz_re = re.compile(
'V \[Sens. ([\w\s.]*)\] \(([.0-9]*) kHz/LSB\) (-?[.0-9]*) kHz')
- if version in ['0x06120002', '0x06130001']:
+ if version in ['0x05120005', '0x06120002', '0x06130001']:
match = volt_re.match(z_piezo_info['@4:Z scale'])
assert match != None, 'Bad regexp for %s, %s' \
% ('@4:Z scale', z_piezo_info['@4:Z scale'])
- assert match.group(1) == 'ZSensorSens', z_piezo_info['@4:Z scale']
+ if version == '0x05120005':
+ assert match.group(1) == 'Deflection', (
+ z_piezo_info['@4:Z scale'])
+ else:
+ assert match.group(1) == 'ZSensorSens', (
+ z_piezo_info['@4:Z scale'])
else:
assert version == '0x07200000', version
match = hz_re.match(z_piezo_info['@4:Z scale'])
match = volt_re.match(deflection_info['@4:Z scale'])
assert match != None, 'Bad regexp for %s, %s' \
% ('@4:Z scale', deflection_info['@4:Z scale'])
- assert match.group(1) == 'DeflSens', z_piezo_info['@4:Z scale']
+ if version == '0x05120005':
+ assert match.group(1) == 'Deflection', z_piezo_info['@4:Z scale']
+ else:
+ assert version in [
+ '0x06120002', '0x06130001', '0x07200000'], version
+ assert match.group(1) == 'DeflSens', z_piezo_info['@4:Z scale']
ret['deflection sensitivity (V/bit)'] = float(match.group(2))
ret['deflection range (V)'] = float(match.group(3))
ret['deflection offset (V)'] = 0.0
# offset assumed if raw data is signed...
nm_sens_re = re.compile('V ([.0-9]*) nm/V')
- match = nm_sens_re.match(info['Ciao scan list']['@Sens. ZSensorSens'])
- assert match != None, 'Bad regexp for %s/%s, %s' \
- % ('Ciao scan list', '@Sens. ZSensorSens',
- info['Ciao scan list']['@Sens. ZSensorSens'])
+ if version == '0x05120005':
+ match = nm_sens_re.match(info['Scanner list']['@Sens. Zscan'])
+ assert match != None, 'Bad regexp for %s/%s, %s' \
+ % ('Scanner list', '@Sens. Zscan',
+ info['Scanner list']['@Sens. Zscan'])
+ elif version in ['0x06120002', '0x06130001']:
+ match = nm_sens_re.match(info['Ciao scan list']['@Sens. ZSensorSens'])
+ assert match != None, 'Bad regexp for %s/%s, %s' \
+ % ('Ciao scan list', '@Sens. ZSensorSens',
+ info['Ciao scan list']['@Sens. ZSensorSens'])
+ else:
+ assert version == '0x07200000', version
+ match = nm_sens_re.match(info['Ciao scan list']['@Sens. ZsensSens'])
+ assert match != None, 'Bad regexp for %s/%s, %s' \
+ % ('Ciao scan list', '@Sens. ZsensSens',
+ info['Ciao scan list']['@Sens. ZsensSens'])
ret['z piezo sensitivity (m/V)'] = float(match.group(1))*1e-9
- match = nm_sens_re.match(info['Ciao scan list']['@Sens. DeflSens'])
- assert match != None, 'Bad regexp for %s/%s, %s' \
- % ('Ciao scan list', '@Sens. DeflSens', info['Ciao scan list']['@Sens. DeflSens'])
+ if version == '0x05120005':
+ match = nm_sens_re.match(info['Ciao scan list']['@Sens. Deflection'])
+ assert match != None, 'Bad regexp for %s/%s, %s' \
+ % ('Scanner list', '@Sens. Zscan',
+ info['Ciao scan list']['@Sens. Deflection'])
+ else:
+ assert version in [
+ '0x06120002', '0x06130001', '0x07200000'], version
+ match = nm_sens_re.match(info['Ciao scan list']['@Sens. DeflSens'])
+ assert match != None, 'Bad regexp for %s/%s, %s' \
+ % ('Ciao scan list', '@Sens. DeflSens', info['Ciao scan list']['@Sens. DeflSens'])
ret['deflection sensitivity (m/V)'] = float(match.group(1))*1e-9
match = volt_re.match(info['Ciao force list']['@Z scan start'])
ret['z piezo sensitivity (V/bit)'] = float(match.group(2))
ret['z piezo range (V)'] = float(match.group(3))
else:
- assert version == '0x07200000', version
+ assert version in ['0x05120005', '0x07200000'], version
pass
- match = volt_re.match(z_piezo_info['@4:Ramp size'])
- assert match != None, 'Bad regexp for %s, %s' \
- % ('@4:Ramp size', info['@4:Ramp size'])
- assert match.group(1) == 'Zsens', match.group(1)
- ret['z piezo ramp size (V/bit)'] = float(match.group(2))
- ret['z piezo ramp size (V)'] = float(match.group(3))
+ if version == '0x05120005':
+ # already accounded for when generating 'Z sensor' trace
+ pass
+ else:
+ assert version in [
+ '0x06120002', '0x06130001', '0x07200000'], version
+ match = volt_re.match(z_piezo_info['@4:Ramp size'])
+ assert match != None, 'Bad regexp for %s, %s' \
+ % ('@4:Ramp size', info['@4:Ramp size'])
+ assert match.group(1) == 'Zsens', match.group(1)
+ ret['z piezo ramp size (V/bit)'] = float(match.group(2))
+ ret['z piezo ramp size (V)'] = float(match.group(3))
- match = volt_re.match(z_piezo_info['@4:Ramp offset'])
- assert match != None, 'Bad regexp for %s, %s' \
- % ('@4:Ramp offset', info['@4:Ramp offset'])
- assert match.group(1) == 'Zsens', match.group(1)
- ret['z piezo ramp offset (V/bit)'] = float(match.group(2))
- ret['z piezo ramp offset (V)'] = float(match.group(3))
+ match = volt_re.match(z_piezo_info['@4:Ramp offset'])
+ assert match != None, 'Bad regexp for %s, %s' \
+ % ('@4:Ramp offset', info['@4:Ramp offset'])
+ assert match.group(1) == 'Zsens', match.group(1)
+ ret['z piezo ramp offset (V/bit)'] = float(match.group(2))
+ ret['z piezo ramp offset (V)'] = float(match.group(3))
# Unaccounted for:
# Samps*
z_col = info['columns'].index('z piezo (m)')
d_col = info['columns'].index('deflection (m)')
- # Leading '-' because Veeco's z increases towards the surface
+ # Leading '-' because Bruker's z increases towards the surface
# (positive indentation), but it makes more sense to me to
# have it increase away from the surface (positive
# separation).