Package pipe_control :: Module value
[hide private]
[frames] | no frames]

Source Code for Module pipe_control.value

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2014 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """Module for the manipulation of parameter and constant values.""" 
 24   
 25  # Python module imports. 
 26  from numpy import ndarray 
 27  import sys 
 28   
 29  # relax module imports. 
 30  from lib.check_types import is_num 
 31  from lib.errors import RelaxError, RelaxNoSequenceError, RelaxParamSetError, RelaxValueError 
 32  from lib.io import get_file_path, open_write_file, read_spin_data, write_spin_data 
 33  from pipe_control import minimise, pipes 
 34  from pipe_control.mol_res_spin import exists_mol_res_spin_data, generate_spin_id_unique, spin_loop 
 35  from pipe_control.result_files import add_result_file 
 36  import specific_analyses 
 37  from status import Status; status = Status() 
 38   
 39   
40 -def copy(pipe_from=None, pipe_to=None, param=None):
41 """Copy spin specific data values from pipe_from to pipe_to. 42 43 @param pipe_from: The data pipe to copy the value from. This defaults to the current data 44 pipe. 45 @type pipe_from: str 46 @param pipe_to: The data pipe to copy the value to. This defaults to the current data pipe. 47 @type pipe_to: str 48 @param param: The name of the parameter to copy the values of. 49 @type param: str 50 """ 51 52 # The current data pipe. 53 if pipe_from == None: 54 pipe_from = pipes.cdp_name() 55 if pipe_to == None: 56 pipe_to = pipes.cdp_name() 57 pipe_orig = pipes.cdp_name() 58 59 # The second pipe does not exist. 60 pipes.test(pipe_to) 61 62 # Test if the sequence data for pipe_from is loaded. 63 if not exists_mol_res_spin_data(pipe_from): 64 raise RelaxNoSequenceError(pipe_from) 65 66 # Test if the sequence data for pipe_to is loaded. 67 if not exists_mol_res_spin_data(pipe_to): 68 raise RelaxNoSequenceError(pipe_to) 69 70 # Specific value and error returning function. 71 return_value = specific_analyses.setup.get_specific_fn('return_value', pipes.get_type(pipe_from)) 72 73 # Test if the data exists for pipe_to. 74 for spin in spin_loop(pipe=pipe_to): 75 # Get the value and error for pipe_to. 76 value, error = return_value(spin, param) 77 78 # Data exists. 79 if value != None or error != None: 80 raise RelaxValueError(param, pipe_to) 81 82 # Switch to the data pipe to copy values to. 83 pipes.switch(pipe_to) 84 85 # Copy the values. 86 for spin, spin_id in spin_loop(pipe=pipe_from, return_id=True): 87 # Get the value and error from pipe_from. 88 value, error = return_value(spin, param) 89 90 # Set the values of pipe_to. 91 if value != None: 92 set(spin_id=spin_id, val=value, param=param, pipe=pipe_to) 93 if error != None: 94 set(spin_id=spin_id, val=error, param=param, pipe=pipe_to, error=True) 95 96 # Reset all minimisation statistics. 97 minimise.reset_min_stats(pipe_to) 98 99 # Switch back to the original current data pipe. 100 pipes.switch(pipe_orig)
101 102
103 -def display(param=None, scaling=1.0):
104 """Display spin specific data values. 105 106 @keyword param: The name of the parameter to display. 107 @type param: str 108 @keyword scaling: The value to scale the parameter by. 109 @type scaling: float 110 """ 111 112 # Test if the current pipe exists. 113 pipes.test() 114 115 # Test if the sequence data is loaded. 116 if not exists_mol_res_spin_data(): 117 raise RelaxNoSequenceError 118 119 # Print the data. 120 write_data(param=param, file=sys.stdout, scaling=scaling)
121 122
123 -def get_parameters():
124 """Return a list of the parameters associated with the current data pipe. 125 126 @return: The list of parameters. 127 @rtype: list of str 128 """ 129 130 # No data pipes. 131 if cdp == None: 132 return [] 133 134 # Get the specific functions. 135 data_names = specific_analyses.setup.get_specific_fn('data_names', cdp.pipe_type, raise_error=False) 136 return_data_desc = specific_analyses.setup.get_specific_fn('return_data_desc', cdp.pipe_type, raise_error=False) 137 138 # Loop over the parameters. 139 params = [] 140 for name in (data_names(set='params') + data_names(set='generic') + data_names(set='min')): 141 # Get the description. 142 desc = return_data_desc(name) 143 144 # No description. 145 if not desc: 146 text = name 147 148 # The text. 149 else: 150 text = "'%s': %s" % (name, desc) 151 152 # Append the data as a list. 153 params.append((text, name)) 154 155 # Return the data. 156 return params
157 158
159 -def partition_params(val, param):
160 """Function for sorting and partitioning the parameters and their values. 161 162 The two major partitions are the tensor parameters and the spin specific parameters. 163 164 @param val: The parameter values. 165 @type val: None, number, or list of numbers 166 @param param: The parameter names. 167 @type param: None, str, or list of str 168 @return: A tuple, of length 4, of lists. The first and second elements are the lists of 169 spin specific parameters and values respectively. The third and forth elements 170 are the lists of all other parameters and their values. 171 @rtype: tuple of 4 lists 172 """ 173 174 # Specific functions. 175 is_spin_param = specific_analyses.setup.get_specific_fn('is_spin_param', pipes.get_type()) 176 177 # Initialise. 178 spin_params = [] 179 spin_values = [] 180 other_params = [] 181 other_values = [] 182 183 # Single parameter. 184 if isinstance(param, str): 185 # Spin specific parameter. 186 if is_spin_param(param): 187 params = spin_params 188 values = spin_values 189 190 # Other parameters. 191 else: 192 params = other_params 193 values = other_values 194 195 # List of values. 196 if isinstance(val, list) or isinstance(val, ndarray): 197 # Parameter name. 198 for i in range(len(val)): 199 params.append(param) 200 201 # Parameter value. 202 values = val 203 204 # Single value. 205 else: 206 # Parameter name. 207 params.append(param) 208 209 # Parameter value. 210 values.append(val) 211 212 # Multiple parameters. 213 elif isinstance(param, list): 214 # Loop over all parameters. 215 for i in range(len(param)): 216 # Spin specific parameter. 217 if is_spin_param(param[i]): 218 params = spin_params 219 values = spin_values 220 221 # Other parameters. 222 else: 223 params = other_params 224 values = other_values 225 226 # Parameter name. 227 params.append(param[i]) 228 229 # Parameter value. 230 if isinstance(val, list) or isinstance(val, ndarray): 231 values.append(val[i]) 232 else: 233 values.append(val) 234 235 236 # Return the partitioned parameters and values. 237 return spin_params, spin_values, other_params, other_values
238 239
240 -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):
241 """Read spin specific data values from a file. 242 243 @keyword param: The name of the parameter to read. 244 @type param: str 245 @keyword scaling: A scaling factor by which all read values are multiplied by. 246 @type scaling: float 247 @keyword file: The name of the file to open. 248 @type file: str 249 @keyword dir: The directory containing the file (defaults to the current directory if None). 250 @type dir: str or None 251 @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. 252 @type file_data: list of lists 253 @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. 254 @type spin_id_col: int or None 255 @keyword mol_name_col: The column containing the molecule name information. If supplied, spin_id_col must be None. 256 @type mol_name_col: int or None 257 @keyword res_name_col: The column containing the residue name information. If supplied, spin_id_col must be None. 258 @type res_name_col: int or None 259 @keyword res_num_col: The column containing the residue number information. If supplied, spin_id_col must be None. 260 @type res_num_col: int or None 261 @keyword spin_name_col: The column containing the spin name information. If supplied, spin_id_col must be None. 262 @type spin_name_col: int or None 263 @keyword spin_num_col: The column containing the spin number information. If supplied, spin_id_col must be None. 264 @type spin_num_col: int or None 265 @keyword data_col: The column containing the RDC data in Hz. 266 @type data_col: int or None 267 @keyword error_col: The column containing the RDC errors. 268 @type error_col: int or None 269 @keyword sep: The column separator which, if None, defaults to whitespace. 270 @type sep: str or None 271 @keyword spin_id: The spin ID string. 272 @type spin_id: None or str 273 """ 274 275 # Test if the current pipe exists. 276 pipes.test() 277 278 # Test if sequence data is loaded. 279 if not exists_mol_res_spin_data(): 280 raise RelaxNoSequenceError 281 282 # Minimisation parameter. 283 if minimise.return_data_name(param): 284 # Minimisation statistic flag. 285 min_stat = True 286 287 # Specific value and error returning function. 288 return_value = minimise.return_value 289 290 # Specific set function. 291 set_fn = minimise.set 292 293 # Normal parameter. 294 else: 295 # Minimisation statistic flag. 296 min_stat = False 297 298 # Specific v 299 return_value = specific_analyses.setup.get_specific_fn('return_value', pipes.get_type()) 300 301 # Specific set function. 302 set_fn = set 303 304 # Test data corresponding to param already exists. 305 for spin in spin_loop(): 306 # Skip deselected spins. 307 if not spin.select: 308 continue 309 310 # Get the value and error. 311 value, error = return_value(spin, param) 312 313 # Data exists. 314 if value != None or error != None: 315 raise RelaxValueError(param) 316 317 # Loop over the data. 318 mol_names = [] 319 res_nums = [] 320 res_names = [] 321 spin_nums = [] 322 spin_names = [] 323 values = [] 324 errors = [] 325 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): 326 # Unpack. 327 if data_col and error_col: 328 mol_name, res_num, res_name, spin_num, spin_name, value, error = data 329 elif data_col: 330 mol_name, res_num, res_name, spin_num, spin_name, value = data 331 error = None 332 else: 333 mol_name, res_num, res_name, spin_num, spin_name, error = data 334 value = None 335 336 # Set the value. 337 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) 338 set_fn(val=value, error=error, param=param, spin_id=id) 339 340 # Append the data for printout. 341 mol_names.append(mol_name) 342 res_nums.append(res_num) 343 res_names.append(res_name) 344 spin_nums.append(spin_num) 345 spin_names.append(spin_name) 346 values.append(value) 347 errors.append(error) 348 349 # Print out. 350 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) 351 352 # Reset the minimisation statistics. 353 if not min_stat: 354 minimise.reset_min_stats()
355 356
357 -def set(val=None, param=None, pipe=None, spin_id=None, error=False, force=True, reset=True):
358 """Set global or spin specific data values. 359 360 @keyword val: The parameter values. 361 @type val: None or list 362 @keyword param: The parameter names. 363 @type param: None, str, or list of str 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 error: A flag which if True will allow the parameter errors to be set instead of the values. 369 @type error: bool 370 @keyword force: A flag forcing the overwriting of current values. 371 @type force: bool 372 @keyword reset: A flag which if True will cause all minimisation statistics to be reset. 373 @type reset: bool 374 """ 375 376 # Switch to the data pipe, storing the original. 377 if pipe: 378 orig_pipe = pipes.cdp_name() 379 pipes.switch(pipe) 380 381 # Test if the current data pipe exists. 382 pipes.test() 383 384 # Specific functions. 385 default_value = specific_analyses.setup.get_specific_fn('default_value', pipes.get_type()) 386 get_param_names = specific_analyses.setup.get_specific_fn('get_param_names', pipes.get_type()) 387 return_data_name = specific_analyses.setup.get_specific_fn('return_data_name', pipes.get_type()) 388 set_param_values = specific_analyses.setup.get_specific_fn('set_param_values', pipes.get_type()) 389 390 # Convert numpy arrays to lists, if necessary. 391 if isinstance(val, ndarray): 392 val = val.tolist() 393 394 # Invalid combinations. 395 if (isinstance(val, float) or isinstance(val, int)) and param == None: 396 raise RelaxError("The combination of a single value '%s' without specifying the parameter name is invalid." % val) 397 if isinstance(val, list) and isinstance(param, str): 398 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)) 399 400 # Value array and parameter array of equal length. 401 if isinstance(val, list) and isinstance(param, list) and len(val) != len(param): 402 raise RelaxError("Both the value array and parameter array must be of equal length.") 403 404 # Get the parameter list if needed. 405 if param == None: 406 param = get_param_names() 407 408 # Convert the param to a list if needed. 409 if not isinstance(param, list): 410 param = [param] 411 412 # Convert the value to a list if needed. 413 if val != None and not isinstance(val, list): 414 val = [val] * len(param) 415 416 # Default values. 417 if val == None: 418 # Loop over the parameters, getting the default values. 419 val = [] 420 for i in range(len(param)): 421 val.append(default_value(return_data_name(param[i]))) 422 423 # Check that there is a default. 424 if val[-1] == None: 425 raise RelaxParamSetError(param[i]) 426 427 # Set the parameter values. 428 set_param_values(param=param, value=val, spin_id=spin_id, error=error, force=force) 429 430 # Reset all minimisation statistics. 431 if reset: 432 minimise.reset_min_stats() 433 434 # Switch back. 435 if pipe: 436 pipes.switch(orig_pipe)
437 438
439 -def write(param=None, file=None, dir=None, scaling=1.0, return_value=None, return_data_desc=None, comment=None, bc=False, force=False):
440 """Write data to a file. 441 442 @keyword param: The name of the parameter to write to file. 443 @type param: str 444 @keyword file: The file to write the data to. 445 @type file: str 446 @keyword dir: The name of the directory to place the file into (defaults to the current directory). 447 @type dir: str 448 @keyword scaling: The value to scale the parameter by. 449 @type scaling: float 450 @keyword return_value: An optional function which if supplied will override the default value returning function. 451 @type return_value: None or func 452 @keyword return_data_desc: An optional function which if supplied will override the default parameter description returning function. 453 @type return_data_desc: None or func 454 @keyword comment: Text which will be added to the start of the file as comments. All lines will be prefixed by '# '. 455 @type comment: str 456 @keyword bc: A flag which if True will cause the back calculated values to be written. 457 @type bc: bool 458 @keyword force: A flag which if True will cause any pre-existing file to be overwritten. 459 @type force: bool 460 """ 461 462 # Test if the current pipe exists. 463 pipes.test() 464 465 # Test if the sequence data is loaded. 466 if not exists_mol_res_spin_data(): 467 raise RelaxNoSequenceError 468 469 # Open the file for writing. 470 file_path = get_file_path(file, dir) 471 file = open_write_file(file, dir, force) 472 473 # Write the data. 474 write_data(param=param, file=file, scaling=scaling, return_value=return_value, return_data_desc=return_data_desc, comment=comment, bc=bc) 475 476 # Close the file. 477 file.close() 478 479 # Add the file to the results file list. 480 add_result_file(type='text', label='Text', file=file_path)
481 482
483 -def write_data(param=None, file=None, scaling=1.0, bc=False, return_value=None, return_data_desc=None, comment=None):
484 """The function which actually writes the data. 485 486 @keyword param: The parameter to write. 487 @type param: str 488 @keyword file: The file to write the data to. 489 @type file: str 490 @keyword scaling: The value to scale the parameter by. 491 @type scaling: float 492 @keyword bc: A flag which if True will cause the back calculated values to be written. 493 @type bc: bool 494 @keyword return_value: An optional function which if supplied will override the default value returning function. 495 @type return_value: None or func 496 @keyword return_data_desc: An optional function which if supplied will override the default parameter description returning function. 497 @type return_data_desc: None or func 498 @keyword comment: Text which will be added to the start of the file as comments. All lines will be prefixed by '# '. 499 @type comment: str 500 """ 501 502 # Get the value and error returning function parameter description function if required. 503 if not return_value: 504 return_value = specific_analyses.setup.get_specific_fn('return_value', pipes.get_type()) 505 if not return_data_desc: 506 return_data_desc = specific_analyses.setup.get_specific_fn('return_data_desc', pipes.get_type()) 507 508 # Format string. 509 format = "%-30s%-30s" 510 511 # Init the data. 512 mol_names = [] 513 res_nums = [] 514 res_names = [] 515 spin_nums = [] 516 spin_names = [] 517 values = [] 518 errors = [] 519 520 # Get the parameter description and add it to the file. 521 desc = return_data_desc(param) 522 if desc: 523 file.write("# Parameter description: %s.\n" % desc) 524 file.write("#\n") 525 526 # The comments. 527 if comment: 528 # Split up the lines. 529 lines = comment.splitlines() 530 531 # Write out. 532 for line in lines: 533 file.write("# %s\n" % line) 534 file.write("#\n") 535 536 # Determine the data type, check the data, and set up the dictionary type data keys. 537 data_names = 'value' 538 error_names = 'error' 539 data_type = None 540 for spin, mol_name, res_num, res_name in spin_loop(full_info=True): 541 # Get the value and error. 542 value, error = return_value(spin, param, bc=bc) 543 544 # Dictionary type data. 545 if isinstance(value, dict): 546 # Sanity check. 547 if not data_type in [None, 'dict']: 548 raise RelaxError("Mixed data types.") 549 data_type = 'dict' 550 551 # Initialise the structures. 552 if not isinstance(data_names, list): 553 data_names = [] 554 error_names = [] 555 556 # Sort the keys. 557 keys = sorted(value.keys()) 558 559 # Loop over the keys. 560 for key in keys: 561 # Add the data and error names if new. 562 if key not in data_names: 563 data_names.append(key) 564 error_names.append('sd(%s)' % key) 565 566 # List type data. 567 elif isinstance(value, list): 568 # Sanity check. 569 if not data_type in [None, 'list']: 570 raise RelaxError("Mixed data types.") 571 data_type = 'list' 572 573 # Initialise the structures. 574 if not isinstance(data_names, list): 575 data_names = [] 576 error_names = [] 577 578 # Check the length. 579 elif len(data_names) != len(value): 580 raise RelaxError("The list type data has an inconsistent number of elements between different spin systems.") 581 582 # Loop over the data. 583 for i in range(len(value)): 584 # The data and error names. 585 data_names.append('value_%s' % i) 586 error_names.append('error_%s' % i) 587 588 # None. 589 elif value == None: 590 pass 591 592 # Simple values. 593 else: 594 # Sanity check. 595 if not data_type in [None, 'value']: 596 raise RelaxError("Mixed data types.") 597 data_type = 'value' 598 599 # Pack the data. 600 for spin, mol_name, res_num, res_name in spin_loop(full_info=True): 601 # Get the value and error. 602 value, error = return_value(spin, param, bc=bc) 603 604 # Append the spin data (scaled). 605 mol_names.append(mol_name) 606 res_nums.append(res_num) 607 res_names.append(res_name) 608 spin_nums.append(spin.num) 609 spin_names.append(spin.name) 610 611 # Dictionary type data. 612 if data_type == 'dict': 613 # Initialise the lists. 614 values.append([]) 615 errors.append([]) 616 617 # Loop over the keys. 618 for key in data_names: 619 # Append the scaled values and errors. 620 if value == None or key not in value: 621 values[-1].append(None) 622 else: 623 values[-1].append(scale(value[key], scaling)) 624 if error == None or key not in error: 625 errors[-1].append(None) 626 else: 627 errors[-1].append(scale(error[key], scaling)) 628 629 # List type data. 630 elif data_type == 'list': 631 # Initialise the lists. 632 values.append([]) 633 errors.append([]) 634 635 # Loop over the data. 636 for i in range(len(data_names)): 637 # Append the scaled values and errors. 638 if value == None: 639 values[-1].append(None) 640 else: 641 values[-1].append(scale(value[i], scaling)) 642 if error == None: 643 errors[-1].append(None) 644 else: 645 errors[-1].append(scale(error[i], scaling)) 646 647 # Simple values. 648 else: 649 # Append the scaled values and errors. 650 values.append(scale(value, scaling)) 651 errors.append(scale(error, scaling)) 652 653 # Write the data. 654 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)
655 656
657 -def scale(value, scaling):
658 """Scale the given value by the scaling factor, handling all input value types. 659 660 @param value: The value to scale. 661 @type value: anything 662 @param scaling: The scaling factor. 663 @type scaling: float 664 """ 665 666 # No a number, so return the value unmodified. 667 if not is_num(value): 668 return value 669 670 # Scale. 671 return value * scaling
672