-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParameters.py
302 lines (274 loc) · 11.5 KB
/
Parameters.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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
"""
Module for parameter container and associated methods
#author: Daniel Polasky
#date: 10/16/2018
"""
import numpy as np
from decimal import Decimal
g1_ms_basefile = '_MS_G1_basefile.exp'
g1_msms_basefile = '_MSMS_G1_basefile.exp'
g1neg_ms_basefile = '_MS_G1neg_basefile.exp'
g1neg_msms_basefile = '_MSMS_G1neg_basefile.exp'
g2_ms_basefile = '_MS_G2_basefile.exp'
g2_msms_basefile = '_MSMS_G2_BASEFILE.exp'
g2si_ms_basefile = '_MS_G2si_basefile.exp'
g2si_msms_basefile = '_MSMS_G2si_basefile.exp'
class MethodParams(object):
"""
Container for all parameters associated with a method
"""
def __init__(self, params_dict):
self.combine_all_bool = None
self.msms_bool = None
self.cal_file = None
self.optic_mode = None
self.tune_file = None
self.output_dir = None
self.save_to_masslynx = None
self.masslynx_dir = None
self.functions_per_file = None
self.save_dt = None
self.delay_time_init = None
self.date = None
self.mz = None
self.sample_name = None
self.cv_step = None
self.cv_start = None
self.cv_end = None
self.ms_start = None
self.ms_end = None
self.collect_time = None
self.scan_time = None
self.instrument_type = None
self.base_file_path = None
self.params_dict = params_dict
self.set_params(params_dict)
if self.instrument_type.lower() == 'g1':
if self.msms_bool:
self.base_file_path = g1_msms_basefile
else:
self.base_file_path = g1_ms_basefile
elif self.instrument_type.lower() == 'g1neg':
if self.msms_bool:
self.base_file_path = g1neg_msms_basefile
else:
self.base_file_path = g1neg_ms_basefile
elif self.instrument_type.lower() == 'g2':
if self.msms_bool:
self.base_file_path = g2_msms_basefile
else:
self.base_file_path = g2_ms_basefile
elif self.instrument_type.lower() == 'g2si' or self.instrument_type.lower() == 'g2-si':
if self.msms_bool:
self.base_file_path = g2si_msms_basefile
else:
self.base_file_path = g2si_ms_basefile
else:
print('ERROR: UNSUPPORTED INSTRUMENT TYPE: {}. The template will not be processed.'.format(self.instrument_type))
def set_params(self, params_dict):
"""
Set a series of parameters given a dictionary of (parameter name, value) pairs
:param params_dict: Dictionary, key=param name, value=param value
:return: void
"""
for name, value in params_dict.items():
try:
# only set the attribute if it is present in the object - otherwise, raise attribute error
self.__getattribute__(name)
self.__setattr__(name, value)
except AttributeError:
# no such parameter
print('No parameter name for param: ' + name)
continue
# self.update_dict()
def update_dict(self):
"""
Build (or rebuild) a dictionary of all attributes contained in this object
:return: void
"""
for field in vars(self):
value = self.__getattribute__(field)
self.params_dict[field] = value
def parse_params_template_csv(params_file, descripts_file):
"""
Parse a template CSV file containing one or several method editor runs. Generates a new
MethodParams container for each analysis requested
:param params_file: File to parse (.txt), headers = '#'
:param descripts_file: Descriptions file with parameter descriptions and key names
:return: list of param containers, combine all bool
"""
# col_locations, codenames, names, reqs, descripts
col_locations, codenames, names, descriptions, reqs = parse_param_descriptions(descripts_file)
param_obj_list = []
# initialize header information for later retrieval
base_param_dict = {}
# Read the template file
done_with_headers = False
header_index = 0
with open(params_file, 'r') as parfile:
for line in list(parfile):
# check if we've reached the individual section yet
if line.startswith('# INDIVIDUAL'):
done_with_headers = True
# skip headers and blank lines
if line.startswith('#') or line.startswith('\n') or line.startswith(','):
continue
# read headers
if not done_with_headers:
splits = line.rstrip('\n').split(',')
# for index, split in enumerate(splits):
if splits[1] is not '':
key = col_locations[header_index + 20] # +20 to distinguish header columns from lower columns
base_param_dict[key] = parse_value(splits[1].strip())
header_index += 1
else:
# read individual parameter lines and make a container for each
current_param_dict = {}
current_param_dict.update(base_param_dict)
splits = line.rstrip('\n').split(',')
for index, split in enumerate(splits):
if split is not '':
key = col_locations[index]
parsed_value = parse_value(split.strip())
current_param_dict[key] = parsed_value
# initialize a parameter container
param_obj_list.append(MethodParams(current_param_dict))
return param_obj_list, reqs, names
def parse_value(value):
"""
convert a string value into appropriate type
:param value: string
:return: various types
"""
# Convert value from string to appropriate type
if value == 'None':
output_val = None
else:
# try parsing numbers
try:
try:
if '_' in value:
# don't treat the date as an integer (pass it down to string)
raise ValueError
output_val = int(value)
except ValueError:
if '_' in value:
raise ValueError
float(value) # test first with float because Decimal throws a weird error
output_val = Decimal(value) # represent floats with Decimal, since exact values can be important for MassLynx
except ValueError:
# string value - try parsing booleans or leave as a string
if value.lower() in ['true', 't', 'yes', 'y']:
output_val = True
elif value.lower() in ['false', 'f', 'no', 'n']:
output_val = False
else:
output_val = value
return output_val
def parse_params_file_oldtxt(params_file, descripts_file):
"""
Parse a text file for all parameters. Returns a params_dict that can be used to
set_params on a Parameters object
:param params_file: File to parse (.txt), headers = '#'
:param descripts_file: Descriptions file with parameter descriptions and key names
:return: params_dict: Dictionary, key=param name, value=param value
"""
col_locations, codenames, names, reqs, descripts = parse_param_descriptions(descripts_file)
param_dict = {}
try:
with open(params_file, 'r') as pfile:
lines = list(pfile)
for line in lines:
# skip headers and blank lines
if line.startswith('#') or line.startswith('\n'):
continue
splits = line.rstrip('\n').split('=')
try:
key = codenames[splits[0].strip()]
except KeyError:
print('Error: invalid parameter name: {}'.format(splits[0].strip()))
continue
value = splits[1].strip()
# catch 'None' values and convert to None
if value == 'None':
param_dict[key] = None
else:
# try parsing numbers
try:
try:
param_dict[key] = int(value)
except ValueError:
param_dict[key] = float(value)
except ValueError:
# string value - try parsing booleans or leave as a string
if value.lower() in ['true', 't', 'yes', 'y']:
param_dict[key] = True
elif value.lower() in ['false', 'f', 'no', 'n']:
param_dict[key] = False
else:
param_dict[key] = value
return param_dict
except FileNotFoundError:
print('params file not found!')
def parse_param_descriptions(param_file):
"""
Read in parameter descriptions and requirements from text (csv) file
:param param_file: file to read (full system path)
:return: dictionaries of 1) parameter display names, 2) parameter descriptions, 3) parameter
requirements. All dicts will have keys corresponding to attributes of the Parameters object
"""
names = {}
descriptions = {}
reqs = {}
codenames = {}
col_locations = {}
with open(param_file) as p_file:
lines = list(p_file)
for line in lines:
# skip header
if line.startswith('#'):
continue
line = line.rstrip('\n')
# parse a parameter name and description from the line
splits = line.split(',')
key = splits[0].strip()
names[key] = splits[2].strip()
descriptions[key] = splits[7].strip()
codenames[splits[8].strip()] = key
col_locations[int(splits[9].strip())] = key
# parse parameter requirements
param_type = splits[3].strip()
if param_type == 'int':
# parse lower and upper bounds
if splits[4].strip() == 'ninf':
lower_bound = -np.inf
else:
lower_bound = int(splits[4].strip())
if splits[5].strip() == 'inf':
upper_bound = np.inf
else:
upper_bound = int(splits[5].strip())
reqs[key] = (param_type, [lower_bound, upper_bound])
elif param_type == 'float':
# parse lower and upper bounds
if splits[4].strip() == 'ninf':
lower_bound = -np.inf
else:
lower_bound = float(splits[4].strip())
if splits[5].strip() == 'inf':
upper_bound = np.inf
else:
upper_bound = float(splits[5].strip())
reqs[key] = (param_type, [lower_bound, upper_bound])
elif param_type == 'string' or param_type == 'bool':
req_vals = [x.strip() for x in splits[6].strip().split(';')]
# convert 'none' strings to actual Nonetype
# for index, value in enumerate(req_vals):
# if value == 'none':
# req_vals[index] = None
reqs[key] = (param_type, req_vals)
elif param_type == 'anystring':
reqs[key] = (param_type, [])
else:
print('invalid type, parsing failed for line: {}'.format(line))
return col_locations, codenames, names, descriptions, reqs