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 """Module for the manipulation of parameter and constant values."""
26
27
28 from numpy import ndarray
29 import sys
30
31
32 from lib.check_types import is_num
33 from lib.errors import RelaxError, RelaxNoSequenceError, RelaxParamSetError, RelaxValueError
34 from lib.io import get_file_path, open_write_file
35 from lib.sequence import read_spin_data, write_spin_data
36 from pipe_control import minimise, pipes
37 from pipe_control.mol_res_spin import exists_mol_res_spin_data, generate_spin_id_unique, spin_loop
38 from pipe_control.pipes import check_pipe
39 from pipe_control.result_files import add_result_file
40 from specific_analyses.api import return_api
41 from status import Status; status = Status()
42
43
44 -def copy(pipe_from=None, pipe_to=None, param=None, force=False):
45 """Copy spin specific data values from pipe_from to pipe_to.
46
47 @param pipe_from: The data pipe to copy the value from. This defaults to the current data
48 pipe.
49 @type pipe_from: str
50 @param pipe_to: The data pipe to copy the value to. This defaults to the current data pipe.
51 @type pipe_to: str
52 @param param: The name of the parameter to copy the values of.
53 @type param: str
54 @keyword force: A flag forcing the overwriting of current values.
55 @type force: bool
56 """
57
58
59 if pipe_from == None:
60 pipe_from = pipes.cdp_name()
61 if pipe_to == None:
62 pipe_to = pipes.cdp_name()
63 pipe_orig = pipes.cdp_name()
64
65
66 check_pipe(pipe_to)
67
68
69 if not exists_mol_res_spin_data(pipe_from):
70 raise RelaxNoSequenceError(pipe_from)
71
72
73 if not exists_mol_res_spin_data(pipe_to):
74 raise RelaxNoSequenceError(pipe_to)
75
76
77 api = return_api(pipe_name=pipe_from)
78
79
80 if force == False:
81 for spin in spin_loop(pipe=pipe_to):
82
83 value, error = api.return_value(spin, param)
84
85
86 if value != None or error != None:
87 raise RelaxValueError(param, pipe_to)
88
89
90 pipes.switch(pipe_to)
91
92
93 for spin, spin_id in spin_loop(pipe=pipe_from, return_id=True):
94
95 value, error = api.return_value(spin, param)
96
97
98 if value != None:
99 set(spin_id=spin_id, val=value, param=param, pipe=pipe_to, force=force)
100 if error != None:
101 set(spin_id=spin_id, val=error, param=param, pipe=pipe_to, error=True, force=force)
102
103
104 minimise.reset_min_stats(pipe_to)
105
106
107 pipes.switch(pipe_orig)
108
109
110 -def display(param=None, scaling=1.0):
128
129
167
168
170 """Function for sorting and partitioning the parameters and their values.
171
172 The two major partitions are the tensor parameters and the spin specific parameters.
173
174 @param val: The parameter values.
175 @type val: None, number, or list of numbers
176 @param param: The parameter names.
177 @type param: None, str, or list of str
178 @return: A tuple, of length 4, of lists. The first and second elements are the lists of
179 spin specific parameters and values respectively. The third and forth elements
180 are the lists of all other parameters and their values.
181 @rtype: tuple of 4 lists
182 """
183
184
185 api = return_api()
186
187
188 spin_params = []
189 spin_values = []
190 other_params = []
191 other_values = []
192
193
194 if isinstance(param, str):
195
196 if api.is_spin_param(param):
197 params = spin_params
198 values = spin_values
199
200
201 else:
202 params = other_params
203 values = other_values
204
205
206 if isinstance(val, list) or isinstance(val, ndarray):
207
208 for i in range(len(val)):
209 params.append(param)
210
211
212 values = val
213
214
215 else:
216
217 params.append(param)
218
219
220 values.append(val)
221
222
223 elif isinstance(param, list):
224
225 for i in range(len(param)):
226
227 if api.is_spin_param(param[i]):
228 params = spin_params
229 values = spin_values
230
231
232 else:
233 params = other_params
234 values = other_values
235
236
237 params.append(param[i])
238
239
240 if isinstance(val, list) or isinstance(val, ndarray):
241 values.append(val[i])
242 else:
243 values.append(val)
244
245
246
247 return spin_params, spin_values, other_params, other_values
248
249
250 -def read(param=None, scaling=1.0, file=None, dir=None, file_data=None, spin_id_col=None, mol_name_col=None, res_num_col=None, res_name_col=None, spin_num_col=None, spin_name_col=None, data_col=None, error_col=None, sep=None, spin_id=None):
251 """Read spin specific data values from a file.
252
253 @keyword param: The name of the parameter to read.
254 @type param: str
255 @keyword scaling: A scaling factor by which all read values are multiplied by.
256 @type scaling: float
257 @keyword file: The name of the file to open.
258 @type file: str
259 @keyword dir: The directory containing the file (defaults to the current directory if None).
260 @type dir: str or None
261 @keyword file_data: An alternative to opening a file, if the data already exists in the correct format. The format is a list of lists where the first index corresponds to the row and the second the column.
262 @type file_data: list of lists
263 @keyword spin_id_col: The column containing the spin ID strings. If supplied, the mol_name_col, res_name_col, res_num_col, spin_name_col, and spin_num_col arguments must be none.
264 @type spin_id_col: int or None
265 @keyword mol_name_col: The column containing the molecule name information. If supplied, spin_id_col must be None.
266 @type mol_name_col: int or None
267 @keyword res_name_col: The column containing the residue name information. If supplied, spin_id_col must be None.
268 @type res_name_col: int or None
269 @keyword res_num_col: The column containing the residue number information. If supplied, spin_id_col must be None.
270 @type res_num_col: int or None
271 @keyword spin_name_col: The column containing the spin name information. If supplied, spin_id_col must be None.
272 @type spin_name_col: int or None
273 @keyword spin_num_col: The column containing the spin number information. If supplied, spin_id_col must be None.
274 @type spin_num_col: int or None
275 @keyword data_col: The column containing the RDC data in Hz.
276 @type data_col: int or None
277 @keyword error_col: The column containing the RDC errors.
278 @type error_col: int or None
279 @keyword sep: The column separator which, if None, defaults to whitespace.
280 @type sep: str or None
281 @keyword spin_id: The spin ID string.
282 @type spin_id: None or str
283 """
284
285
286 check_pipe()
287
288
289 if not exists_mol_res_spin_data():
290 raise RelaxNoSequenceError
291
292
293 min_stat = False
294
295
296 api = return_api()
297 return_value = api.return_value
298
299
300 set_fn = set
301
302
303 for spin in spin_loop():
304
305 if not spin.select:
306 continue
307
308
309 value, error = return_value(spin, param)
310
311
312 if value != None or error != None:
313 raise RelaxValueError(param)
314
315
316 mol_names = []
317 res_nums = []
318 res_names = []
319 spin_nums = []
320 spin_names = []
321 values = []
322 errors = []
323 for data in read_spin_data(file=file, dir=dir, file_data=file_data, spin_id_col=spin_id_col, mol_name_col=mol_name_col, res_num_col=res_num_col, res_name_col=res_name_col, spin_num_col=spin_num_col, spin_name_col=spin_name_col, data_col=data_col, error_col=error_col, sep=sep, spin_id=spin_id):
324
325 if data_col and error_col:
326 mol_name, res_num, res_name, spin_num, spin_name, value, error = data
327 elif data_col:
328 mol_name, res_num, res_name, spin_num, spin_name, value = data
329 error = None
330 else:
331 mol_name, res_num, res_name, spin_num, spin_name, error = data
332 value = None
333
334
335 id = generate_spin_id_unique(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin_num, spin_name=spin_name)
336 set_fn(val=value, error=error, param=param, spin_id=id)
337
338
339 mol_names.append(mol_name)
340 res_nums.append(res_num)
341 res_names.append(res_name)
342 spin_nums.append(spin_num)
343 spin_names.append(spin_name)
344 values.append(value)
345 errors.append(error)
346
347
348 write_spin_data(file=sys.stdout, mol_names=mol_names, res_nums=res_nums, res_names=res_names, spin_nums=spin_nums, spin_names=spin_names, data=values, data_name=param, error=errors, error_name='%s_error'%param)
349
350
351 if api.set(param) == 'min':
352 minimise.reset_min_stats()
353
354
355 -def set(val=None, param=None, index=None, pipe=None, spin_id=None, verbosity=1, error=False, force=True, reset=True):
356 """Set global or spin specific data values.
357
358 @keyword val: The parameter values.
359 @type val: None or list
360 @keyword param: The parameter names.
361 @type param: None, str, or list of str
362 @keyword index: The index for parameters which are of the list-type. This is ignored for all other types.
363 @type index: None or int
364 @keyword pipe: The data pipe the values should be placed in.
365 @type pipe: None or str
366 @keyword spin_id: The spin identification string.
367 @type spin_id: str
368 @keyword verbosity: The amount of information to print. The higher the value, the greater the verbosity.
369 @type verbosity: int
370 @keyword error: A flag which if True will allow the parameter errors to be set instead of the values.
371 @type error: bool
372 @keyword force: A flag forcing the overwriting of current values.
373 @type force: bool
374 @keyword reset: A flag which if True will cause all minimisation statistics to be reset.
375 @type reset: bool
376 """
377
378
379 if pipe:
380 orig_pipe = pipes.cdp_name()
381 pipes.switch(pipe)
382
383
384 check_pipe()
385
386
387 api = return_api()
388
389
390 if isinstance(val, ndarray):
391 val = val.tolist()
392
393
394 if (isinstance(val, float) or isinstance(val, int)) and param == None:
395 raise RelaxError("The combination of a single value '%s' without specifying the parameter name is invalid." % val)
396 if isinstance(val, list) and isinstance(param, str):
397 raise RelaxError("Invalid combination: When multiple values '%s' are specified, either no parameters or a list of parameters must by supplied rather than the single parameter '%s'." % (val, param))
398
399
400 if isinstance(val, list) and isinstance(param, list) and len(val) != len(param):
401 raise RelaxError("Both the value array and parameter array must be of equal length.")
402
403
404 if param == None:
405 param = api.get_param_names()
406
407
408 if not isinstance(param, list):
409 param = [param]
410
411
412 if val != None and not isinstance(val, list):
413 val = [val] * len(param)
414
415
416 if val == None:
417
418 val = []
419 for i in range(len(param)):
420 val.append(api.default_value(param[i]))
421
422
423 if val[-1] == None:
424 raise RelaxParamSetError(param[i])
425
426
427 api.set_param_values(param=param, value=val, index=index, spin_id=spin_id, error=error, force=force)
428
429
430 if reset:
431 minimise.reset_min_stats(verbosity=verbosity)
432
433
434 if pipe:
435 pipes.switch(orig_pipe)
436
437
438 -def write(param=None, file=None, dir=None, scaling=1.0, return_value=None, return_data_desc=None, comment=None, bc=False, force=False):
439 """Write data to a file.
440
441 @keyword param: The name of the parameter to write to file.
442 @type param: str
443 @keyword file: The file to write the data to.
444 @type file: str
445 @keyword dir: The name of the directory to place the file into (defaults to the current directory).
446 @type dir: str
447 @keyword scaling: The value to scale the parameter by.
448 @type scaling: float
449 @keyword return_value: An optional function which if supplied will override the default value returning function.
450 @type return_value: None or func
451 @keyword return_data_desc: An optional function which if supplied will override the default parameter description returning function.
452 @type return_data_desc: None or func
453 @keyword comment: Text which will be added to the start of the file as comments. All lines will be prefixed by '# '.
454 @type comment: str
455 @keyword bc: A flag which if True will cause the back calculated values to be written.
456 @type bc: bool
457 @keyword force: A flag which if True will cause any pre-existing file to be overwritten.
458 @type force: bool
459 """
460
461
462 check_pipe()
463
464
465 if not exists_mol_res_spin_data():
466 raise RelaxNoSequenceError
467
468
469 file_path = get_file_path(file, dir)
470 file = open_write_file(file, dir, force)
471
472
473 write_data(param=param, file=file, scaling=scaling, return_value=return_value, return_data_desc=return_data_desc, comment=comment, bc=bc)
474
475
476 file.close()
477
478
479 add_result_file(type='text', label='Text', file=file_path)
480
481
482 -def write_data(param=None, file=None, scaling=1.0, bc=False, return_value=None, return_data_desc=None, comment=None):
483 """The function which actually writes the data.
484
485 @keyword param: The parameter to write.
486 @type param: str
487 @keyword file: The file to write the data to.
488 @type file: str
489 @keyword scaling: The value to scale the parameter by.
490 @type scaling: float
491 @keyword bc: A flag which if True will cause the back calculated values to be written.
492 @type bc: bool
493 @keyword return_value: An optional function which if supplied will override the default value returning function.
494 @type return_value: None or func
495 @keyword return_data_desc: An optional function which if supplied will override the default parameter description returning function.
496 @type return_data_desc: None or func
497 @keyword comment: Text which will be added to the start of the file as comments. All lines will be prefixed by '# '.
498 @type comment: str
499 """
500
501
502 api = return_api()
503
504
505 if not return_value:
506 return_value = api.return_value
507 if not return_data_desc:
508 return_data_desc = api.return_data_desc
509
510
511 format = "%-30s%-30s"
512
513
514 mol_names = []
515 res_nums = []
516 res_names = []
517 spin_nums = []
518 spin_names = []
519 values = []
520 errors = []
521
522
523 desc = return_data_desc(param)
524 if desc:
525 file.write("# Parameter description: %s.\n" % desc)
526 file.write("#\n")
527
528
529 if comment:
530
531 lines = comment.splitlines()
532
533
534 for line in lines:
535 file.write("# %s\n" % line)
536 file.write("#\n")
537
538
539 data_names = 'value'
540 error_names = 'error'
541 data_type = None
542 for spin, mol_name, res_num, res_name in spin_loop(full_info=True):
543
544 value, error = return_value(spin, param, bc=bc)
545
546
547 if isinstance(value, dict):
548
549 if not data_type in [None, 'dict']:
550 raise RelaxError("Mixed data types.")
551 data_type = 'dict'
552
553
554 if not isinstance(data_names, list):
555 data_names = []
556 error_names = []
557
558
559 keys = sorted(value.keys())
560
561
562 for key in keys:
563
564 if key not in data_names:
565 data_names.append(key)
566 error_names.append('sd(%s)' % key)
567
568
569 elif isinstance(value, list):
570
571 if not data_type in [None, 'list']:
572 raise RelaxError("Mixed data types.")
573 data_type = 'list'
574
575
576 if not isinstance(data_names, list):
577 data_names = []
578 error_names = []
579
580
581 elif len(data_names) != len(value):
582 raise RelaxError("The list type data has an inconsistent number of elements between different spin systems.")
583
584
585 for i in range(len(value)):
586
587 data_names.append('value_%s' % i)
588 error_names.append('error_%s' % i)
589
590
591 elif value == None:
592 pass
593
594
595 else:
596
597 if not data_type in [None, 'value']:
598 raise RelaxError("Mixed data types.")
599 data_type = 'value'
600
601
602 for spin, mol_name, res_num, res_name in spin_loop(full_info=True):
603
604 value, error = return_value(spin, param, bc=bc)
605
606
607 mol_names.append(mol_name)
608 res_nums.append(res_num)
609 res_names.append(res_name)
610 spin_nums.append(spin.num)
611 spin_names.append(spin.name)
612
613
614 if data_type == 'dict':
615
616 values.append([])
617 errors.append([])
618
619
620 for key in data_names:
621
622 if value == None or key not in value:
623 values[-1].append(None)
624 else:
625 values[-1].append(scale(value[key], scaling))
626 if error == None or key not in error:
627 errors[-1].append(None)
628 else:
629 errors[-1].append(scale(error[key], scaling))
630
631
632 elif data_type == 'list':
633
634 values.append([])
635 errors.append([])
636
637
638 for i in range(len(data_names)):
639
640 if value == None:
641 values[-1].append(None)
642 else:
643 values[-1].append(scale(value[i], scaling))
644 if error == None:
645 errors[-1].append(None)
646 else:
647 errors[-1].append(scale(error[i], scaling))
648
649
650 else:
651
652 values.append(scale(value, scaling))
653 errors.append(scale(error, scaling))
654
655
656 if isinstance(data_names, list):
657 for i, data_name in enumerate(data_names):
658 data_str = data_name.replace(" ", "_")
659
660 data_names[i] = data_str
661
662
663 if isinstance(error_names, list):
664 for i, error_name in enumerate(error_names):
665 error_str = error_name.replace(" ", "_")
666
667 error_names[i] = error_str
668
669
670 write_spin_data(file, mol_names=mol_names, res_nums=res_nums, res_names=res_names, spin_nums=spin_nums, spin_names=spin_names, data=values, data_name=data_names, error=errors, error_name=error_names)
671
672
673 -def scale(value, scaling):
674 """Scale the given value by the scaling factor, handling all input value types.
675
676 @param value: The value to scale.
677 @type value: anything
678 @param scaling: The scaling factor.
679 @type scaling: float
680 """
681
682
683 if not is_num(value):
684 return value
685
686
687 return value * scaling
688