forked from mantidproject/mantid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreducer_singleton.py
227 lines (192 loc) · 7.29 KB
/
reducer_singleton.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# pylint: disable=invalid-name
from __future__ import (absolute_import, division, print_function)
import random
import string
import os
import mantid
import time
from isis_instrument import BaseInstrument
class ReductionStep(object):
"""
Base class for reduction steps
"""
@classmethod
def delete_workspaces(cls, workspace):
"""
Delete all workspace created by this reduction step related
to the given workspace
@param workspace: workspace to delete
"""
return
@classmethod
def _create_unique_name(cls, filepath, descriptor):
"""
Generate a unique name for an internal workspace
"""
random_str = ''.join(
random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for x in range(5))
return "__" + descriptor + "_" + os.path.basename(filepath) + "_" + random_str
def execute(self, reducer, inputworkspace=None, outputworkspace=None):
"""
Implemented the reduction step.
@param reducer: Reducer object for which the step is executed
@param inputworkspace: Name of the workspace to apply this step to
@param outputworkspace: Name of the workspace to have as an output. If this is None it will be set to inputworkspace
"""
raise NotImplementedError
def run_consistency_check(self):
'''
Run a consistency check of the settings of the ReuctionStep
'''
return
class Reducer(object):
"""
Base reducer class. Instrument-specific reduction processes should be
implemented in a child of this class.
"""
## Instrument configuration object
instrument = None
## Path for data files
_data_path = '.'
## Path for output files
_output_path = None
## List of reduction steps
_reduction_steps = []
## Log
log_text = ''
## Output workspaces
output_workspaces = []
def __init__(self):
self.UID = ''.join(
random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for x in range(5))
self._reduction_steps = []
def set_instrument(self, configuration):
if issubclass(configuration.__class__, BaseInstrument):
self.instrument = configuration
else:
raise RuntimeError(
"Reducer.set_instrument expects an %s object, found %s" % (BaseInstrument, configuration.__class__))
def set_data_path(self, path):
"""
Set the path for data files
@param path: data file path
"""
path = os.path.normcase(path)
if os.path.isdir(path):
self._data_path = path
mantid.config.appendDataSearchDir(path)
else:
raise RuntimeError("Reducer.set_data_path: provided path is not a directory (%s)" % path)
def set_output_path(self, path):
"""
Set the path for output files
@param path: output file path
"""
path = os.path.normcase(path)
if os.path.isdir(path):
self._output_path = path
else:
raise RuntimeError("Reducer.set_output_path: provided path is not a directory (%s)" % path)
def pre_process(self):
"""
Reduction steps that are meant to be executed only once per set
of data files. After this is executed, all files will go through
the list of reduction steps.
"""
pass
def post_process(self):
"""
Reduction steps to be executed after all data files have been
processed.
"""
pass
def reduce(self):
"""
Go through the list of reduction steps
"""
# should we use it?
t_0 = time.time()
instrument_name = ''
self.output_workspaces = []
# Check that an instrument was specified
if self.instrument is not None:
instrument_name = self.instrument.name()
# Log text
self.log_text = "%s reduction - %s\n" % (instrument_name, time.ctime())
# Go through the list of steps that are common to all data files
self.pre_process()
# Go through the list of files to be reduced
# for file_ws in self._data_files:
# for item in self._reduction_steps:
# try:
# result = item.execute(self, file_ws)
# if result is not None and len(str(result))>0:
# self.log_text += "%s\n" % str(result)
# except:
# self.log_text += "\n%s\n" % sys.exc_value
# raise
# any clean up, possibly removing workspaces
self.post_process()
# Determine which directory to use
output_dir = self._data_path
if self._output_path is not None:
if os.path.isdir(self._output_path):
output_dir = self._output_path
else:
output_dir = os.path.expanduser('~')
self.log_text += "Reduction completed in %g sec\n" % (time.time() - t_0)
log_path = os.path.join(output_dir, "%s_reduction.log" % instrument_name)
self.log_text += "Log saved to %s" % log_path
# Write the log to file
f = open(log_path, 'a')
f.write("\n-------------------------------------------\n")
f.write(self.log_text)
f.close()
return self.log_text
class ReductionSingleton(object):
""" Singleton reduction class """
## storage for the instance reference
__instance = None
def __init__(self):
""" Create singleton instance """
# Check whether we already have an instance
if ReductionSingleton.__instance is None:
# Create and remember instance
ReductionSingleton.__instance = Reducer()
# Store instance reference as the only member in the handle
self.__dict__['_ReductionSingleton__instance'] = ReductionSingleton.__instance
@classmethod
def clean(cls, reducer_cls=None):
if reducer_cls is None:
ReductionSingleton.__instance = Reducer()
else:
ReductionSingleton.__instance = reducer_cls()
@classmethod
def replace(cls, red):
"""
Set the object pointed to by the singleton with
the one passed
@param red: reducer object
"""
if issubclass(red.__class__, Reducer):
ReductionSingleton.__instance = red
else:
raise RuntimeError('The object passed to ReductionSingleton.replace() must be of type Reducer')
@classmethod
def run(cls):
"""
Execute the reducer and then clean it (regardless of
if it throws) to ensure that a partially run reducer is
not left behind
"""
try:
if ReductionSingleton.__instance is not None:
return ReductionSingleton.__instance._reduce()
finally:
ReductionSingleton.clean(ReductionSingleton.__instance.__class__)
def __getattr__(self, attr):
""" Delegate access to implementation """
return getattr(self.__instance, attr)
def __setattr__(self, attr, value):
""" Delegate access to implementation """
return setattr(self.__instance, attr, value)