1
2
3 """
4 Support for rarely varying instrument configuration parameters.
5
6 Instrument configuration parameters will change throughout the
7 lifetime of an instrument. For example, the properties of the
8 beam such as wavelength and wavelength divergence will change
9 when a new monochromator is installed on the instrument. Ideally,
10 all such parameters would be encoded in the data file (this is
11 one goal of the NeXus file format), but this is not the case for
12 all instrument formats available today.
13
14 We cannot simply hard code the current value of the instrument
15 parameters in the file reader for the data file format. Such a
16 reader will give bad values for old data files and for new data
17 files after the format has changed. Nor should we burden the user
18 with knowing and entering values for such parameters on their own.
19
20 Instead, we provide support for dated values. Each instrument has
21 a table of values and the date the values come into effect. When
22 a file is loaded, the software scans the list of values, extracting
23 all that are in effect on the file date.
24
25 As instrument parameters change add additional lines to the configuration
26 file indicating the new value and the date of the change. The order of
27 # the entries does not matter. The timestamp on the file will
28 determine which value will be used.
29
30 The format of the entries should be::
31 default.NAME = (VALUE, 'YYYY-MM-DD') # value after MM/DD/YYYY
32 default.NAME = (VALUE, '') # value at commissioning
33
34 [Not implemented] Each data reader has an associated URL which
35 contains the configuration file for the instrument. On file
36 load, the program will fetch dated values from the URL and use
37 them to populate the configuration data for the instrument. This
38 gives control of the instrument parameters to the instrument
39 scientist where it belongs.
40
41 Example
42 =======
43
44 The following parameters are needed for the NG71reflectometer::
45
46 config = properties.DatedValues()
47 config.wavelength = (4.76,'') # in case ICP records the wrong value
48
49 # Detector response is uniform below 15000 counts/s. The efficiency
50 # curve above 15000 has not been measured.
51 config.saturation = (numpy.array([[1,15000,0]]),'')
52
53 config.detector_distance = (36*25.4, '') # mm
54 config.psd_width = (20, '') # mm
55 config.slit1_distance = (-75*25.4, '') # mm
56 config.slit2_distance = (-14*25.4, '') # mm
57 config.slit3_distance = (9*25.4, '') # mm
58 config.slit4_distance = (42*25.4, '') # mm
59 config.detector_distance = (48*25.4, '2004-02-15')
60
61 The defaults are used as follows::
62
63 class Data:
64 def load(filename):
65 data = readheaders(filename)
66 self.config = config(str(data.date))
67 self.detector.distance = self.config.detector_distance
68 ...
69
70 """
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 import re
104 datepattern = re.compile(r'^(19|20)\d\d-\d\d-\d\d$')
108 self.__dict__['_parameters'] = {}
109
111 """
112 Record the parameter value and the date it was set. The pair should
113 contain the value and the date. The assignment will look like:
114 datedvalue.name = (value, 'yyyy-mm-dd')
115 """
116
117 value,date = pair
118 assert date == "" or datepattern.match(date), \
119 "Expected default.%s = (value,'YYYYMMDD')"%(name)
120
121
122 if name not in self._parameters:
123 self._parameters[name] = []
124 self._parameters[name].append(pair)
125
127 """
128 Recover the parameter value for a specific date.
129 """
130 instance = DatedValuesInstance()
131 for name,values in self._parameters.iteritems():
132
133 values.sort(lambda a,b: cmp(a[0],b[0]))
134 for v,d in values:
135 if d <= date: setattr(instance,name,v)
136 else: break
137 return instance
138
149
150 if __name__ == "__main__": test()
151