Add --num-* arguments to calibcant-calibrate.py.
[calibcant.git] / bin / calibcant-calibrate.py
1 #!/usr/bin/env python
2 # calibcant - tools for thermally calibrating AFM cantilevers
3 #
4 # Copyright
5
6 """Run a cantilever calibration using the default AFM
7 (``pyafm.storage.load_afm()``).
8 """
9
10 import argparse as _argparse
11 import time as _time
12
13 from calibcant.calibrate import Calibrator as _Calibrator
14 from pyafm.storage import load_afm as _load_afm
15 import calibcant.config as _config
16
17
18 _module_doc = __doc__
19
20 def main(args):
21     parser = _argparse.ArgumentParser(description=_module_doc)
22     parser.add_argument(
23         '--num-bumps', type=int,
24         help='Number of surface bumps')
25     parser.add_argument(
26         '--num-temperatures', type=int,
27         help='Number of temperature measurements')
28     parser.add_argument(
29         '--num-vibrations', type=int,
30         help='Number of thermal vibration measurements')
31
32     args = parser.parse_args(args)
33
34     timestamp = '{0}-{1:02d}-{2:02d}T{3:02d}-{4:02d}-{5:02d}'.format(
35         *_time.localtime())
36     filename = '{}-calibcant-data.h5'.format(timestamp)
37     config = _config.CalibrateConfig()
38     config['bump'] = _config.BumpConfig()
39     config['bump'].update(
40         {'model':_config.Linear, 'initial-position':-150e-9})
41     config['temperature'] = _config.TemperatureConfig()
42     config['vibration'] = _config.VibrationConfig()
43     if args.num_bumps is None:
44         args.num_bumps = config['num-bumps']
45     else:
46         config['num-bumps'] = args.num_bumps
47     if args.num_temperatures is None:
48         args.num_temperatures = config['num-temperatures']
49     else:
50         config['num-temperatures'] = args.num_temperatures
51     if args.num_vibrations is None:
52         args.num_vibrations = config['num-vibrations']
53     else:
54         config['num-vibrations'] = args.num_vibrations
55     insufficient_calibration_data = 0 in [
56         args.num_bumps, args.num_temperatures, args.num_vibrations]
57     devices = []
58     try:
59         afm = _load_afm()
60         afm.load_from_config(devices=devices)
61         calibrator = _Calibrator(config=config, afm=afm)
62         calibrator.setup_config()
63         deflection = afm.piezo.read_deflection()
64         try:
65             afm.stepper_approach(target_deflection=deflection + 1e3)
66             if insufficient_calibration_data:
67                 data = calibrator.acquire(filename=filename)
68             else:
69                 k,k_s,data = calibrator.calibrate(filename=filename)
70         except:
71             afm.move_away_from_surface()
72             afm.piezo.zero()
73             raise
74     finally:
75         for device in devices:
76             device.close()
77     if insufficient_calibration_data:
78         for count,field,label in [
79             (args.num_bumps, 'bump', 'photodiode sensitivity (V/m)'),
80             (args.num_temperatures, 'temperature', 'temperature (K)'),
81             (args.num_vibrations, 'vibration', 'variance (V**2)')]:
82             if count:
83                 d = data[field]
84                 print('{}: {:g} +/- {:g}'.format(label, d.mean(), d.std()))
85     else:
86         print('k: {:g} +/- {:g}'.format(k, k_s))
87     return 0
88
89 if __name__ == '__main__':
90     import sys
91
92     sys.exit(main(sys.argv[1:]))