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