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

Source Code for Module pipe_control.value

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2009,2011-2014 Edward d'Auvergne                         # 
  4  # Copyright (C) 2008 Sebastien Morin                                          # 
  5  # Copyright (C) 2014 Troels E. Linnet                                         # 
  6  #                                                                             # 
  7  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  8  #                                                                             # 
  9  # This program is free software: you can redistribute it and/or modify        # 
 10  # it under the terms of the GNU General Public License as published by        # 
 11  # the Free Software Foundation, either version 3 of the License, or           # 
 12  # (at your option) any later version.                                         # 
 13  #                                                                             # 
 14  # This program is distributed in the hope that it will be useful,             # 
 15  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 16  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 17  # GNU General Public License for more details.                                # 
 18  #                                                                             # 
 19  # You should have received a copy of the GNU General Public License           # 
 20  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 21  #                                                                             # 
 22  ############################################################################### 
 23   
 24  # Module docstring. 
 25  """Module for the manipulation of parameter and constant values.""" 
 26   
 27  # Python module imports. 
 28  from numpy import ndarray 
 29  import sys 
 30   
 31  # relax module imports. 
 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 # The current data pipe. 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 # The second pipe does not exist. 66 check_pipe(pipe_to) 67 68 # Test if the sequence data for pipe_from is loaded. 69 if not exists_mol_res_spin_data(pipe_from): 70 raise RelaxNoSequenceError(pipe_from) 71 72 # Test if the sequence data for pipe_to is loaded. 73 if not exists_mol_res_spin_data(pipe_to): 74 raise RelaxNoSequenceError(pipe_to) 75 76 # The specific analysis API object. 77 api = return_api(pipe_name=pipe_from) 78 79 # Test if the data exists for pipe_to. 80 if force == False: 81 for spin in spin_loop(pipe=pipe_to): 82 # Get the value and error for pipe_to. 83 value, error = api.return_value(spin, param) 84 85 # Data exists. 86 if value != None or error != None: 87 raise RelaxValueError(param, pipe_to) 88 89 # Switch to the data pipe to copy values to. 90 pipes.switch(pipe_to) 91 92 # Copy the values. 93 for spin, spin_id in spin_loop(pipe=pipe_from, return_id=True): 94 # Get the value and error from pipe_from. 95 value, error = api.return_value(spin, param) 96 97 # Set the values of pipe_to. 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 # Reset all minimisation statistics. 104 minimise.reset_min_stats(pipe_to) 105 106 # Switch back to the original current data pipe. 107 pipes.switch(pipe_orig)
108 109
110 -def display(param=None, scaling=1.0):
111 """Display spin specific data values. 112 113 @keyword param: The name of the parameter to display. 114 @type param: str 115 @keyword scaling: The value to scale the parameter by. 116 @type scaling: float 117 """ 118 119 # Test if the current pipe exists. 120 check_pipe() 121 122 # Test if the sequence data is loaded. 123 if not exists_mol_res_spin_data(): 124 raise RelaxNoSequenceError 125 126 # Print the data. 127 write_data(param=param, file=sys.stdout, scaling=scaling)
128 129
130 -def get_parameters():
131 """Return a list of the parameters associated with the current data pipe. 132 133 @return: The list of parameters. 134 @rtype: list of str 135 """ 136 137 # No data pipes. 138 if cdp == None: 139 return [] 140 141 # The specific analysis API object. 142 api = return_api() 143 144 # Return an empty list if the required functions are absent. 145 if not hasattr(api, 'data_names') or not hasattr(api, 'return_data_desc'): 146 return [] 147 148 # Loop over the parameters. 149 params = [] 150 for name in (api.data_names(set='params') + api.data_names(set='generic') + api.data_names(set='min')): 151 # Get the description. 152 desc = api.return_data_desc(name) 153 154 # No description. 155 if not desc: 156 text = name 157 158 # The text. 159 else: 160 text = "'%s': %s" % (name, desc) 161 162 # Append the data as a list. 163 params.append((text, name)) 164 165 # Return the data. 166 return params
167 168
169 -def partition_params(val, param):
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 # The specific analysis API object. 185 api = return_api() 186 187 # Initialise. 188 spin_params = [] 189 spin_values = [] 190 other_params = [] 191 other_values = [] 192 193 # Single parameter. 194 if isinstance(param, str): 195 # Spin specific parameter. 196 if api.is_spin_param(param): 197 params = spin_params 198 values = spin_values 199 200 # Other parameters. 201 else: 202 params = other_params 203 values = other_values 204 205 # List of values. 206 if isinstance(val, list) or isinstance(val, ndarray): 207 # Parameter name. 208 for i in range(len(val)): 209 params.append(param) 210 211 # Parameter value. 212 values = val 213 214 # Single value. 215 else: 216 # Parameter name. 217 params.append(param) 218 219 # Parameter value. 220 values.append(val) 221 222 # Multiple parameters. 223 elif isinstance(param, list): 224 # Loop over all parameters. 225 for i in range(len(param)): 226 # Spin specific parameter. 227 if api.is_spin_param(param[i]): 228 params = spin_params 229 values = spin_values 230 231 # Other parameters. 232 else: 233 params = other_params 234 values = other_values 235 236 # Parameter name. 237 params.append(param[i]) 238 239 # Parameter value. 240 if isinstance(val, list) or isinstance(val, ndarray): 241 values.append(val[i]) 242 else: 243 values.append(val) 244 245 246 # Return the partitioned parameters and values. 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 # Test if the current pipe exists. 286 check_pipe() 287 288 # Test if sequence data is loaded. 289 if not exists_mol_res_spin_data(): 290 raise RelaxNoSequenceError 291 292 # Minimisation statistic flag. 293 min_stat = False 294 295 # Alias specific analysis API object method. 296 api = return_api() 297 return_value = api.return_value 298 299 # Specific set function. 300 set_fn = set 301 302 # Test data corresponding to param already exists. 303 for spin in spin_loop(): 304 # Skip deselected spins. 305 if not spin.select: 306 continue 307 308 # Get the value and error. 309 value, error = return_value(spin, param) 310 311 # Data exists. 312 if value != None or error != None: 313 raise RelaxValueError(param) 314 315 # Loop over the data. 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 # Unpack. 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 # Set the value. 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 # Append the data for printout. 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 # Print out. 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 # Reset the minimisation statistics. 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 # Switch to the data pipe, storing the original. 379 if pipe: 380 orig_pipe = pipes.cdp_name() 381 pipes.switch(pipe) 382 383 # Test if the current data pipe exists. 384 check_pipe() 385 386 # The specific analysis API object. 387 api = return_api() 388 389 # Convert numpy arrays to lists, if necessary. 390 if isinstance(val, ndarray): 391 val = val.tolist() 392 393 # Invalid combinations. 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 # Value array and parameter array of equal length. 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 # Get the parameter list if needed. 404 if param == None: 405 param = api.get_param_names() 406 407 # Convert the param to a list if needed. 408 if not isinstance(param, list): 409 param = [param] 410 411 # Convert the value to a list if needed. 412 if val != None and not isinstance(val, list): 413 val = [val] * len(param) 414 415 # Default values. 416 if val == None: 417 # Loop over the parameters, getting the default values. 418 val = [] 419 for i in range(len(param)): 420 val.append(api.default_value(param[i])) 421 422 # Check that there is a default. 423 if val[-1] == None: 424 raise RelaxParamSetError(param[i]) 425 426 # Set the parameter values. 427 api.set_param_values(param=param, value=val, index=index, spin_id=spin_id, error=error, force=force) 428 429 # Reset all minimisation statistics. 430 if reset: 431 minimise.reset_min_stats(verbosity=verbosity) 432 433 # Switch back. 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 # Test if the current pipe exists. 462 check_pipe() 463 464 # Test if the sequence data is loaded. 465 if not exists_mol_res_spin_data(): 466 raise RelaxNoSequenceError 467 468 # Open the file for writing. 469 file_path = get_file_path(file, dir) 470 file = open_write_file(file, dir, force) 471 472 # Write the data. 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 # Close the file. 476 file.close() 477 478 # Add the file to the results file list. 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 # The specific analysis API object. 502 api = return_api() 503 504 # Get the value and error returning function parameter description function if required. 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 # Format string. 511 format = "%-30s%-30s" 512 513 # Init the data. 514 mol_names = [] 515 res_nums = [] 516 res_names = [] 517 spin_nums = [] 518 spin_names = [] 519 values = [] 520 errors = [] 521 522 # Get the parameter description and add it to the file. 523 desc = return_data_desc(param) 524 if desc: 525 file.write("# Parameter description: %s.\n" % desc) 526 file.write("#\n") 527 528 # The comments. 529 if comment: 530 # Split up the lines. 531 lines = comment.splitlines() 532 533 # Write out. 534 for line in lines: 535 file.write("# %s\n" % line) 536 file.write("#\n") 537 538 # Determine the data type, check the data, and set up the dictionary type data keys. 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 # Get the value and error. 544 value, error = return_value(spin, param, bc=bc) 545 546 # Dictionary type data. 547 if isinstance(value, dict): 548 # Sanity check. 549 if not data_type in [None, 'dict']: 550 raise RelaxError("Mixed data types.") 551 data_type = 'dict' 552 553 # Initialise the structures. 554 if not isinstance(data_names, list): 555 data_names = [] 556 error_names = [] 557 558 # Sort the keys. 559 keys = sorted(value.keys()) 560 561 # Loop over the keys. 562 for key in keys: 563 # Add the data and error names if new. 564 if key not in data_names: 565 data_names.append(key) 566 error_names.append('sd(%s)' % key) 567 568 # List type data. 569 elif isinstance(value, list): 570 # Sanity check. 571 if not data_type in [None, 'list']: 572 raise RelaxError("Mixed data types.") 573 data_type = 'list' 574 575 # Initialise the structures. 576 if not isinstance(data_names, list): 577 data_names = [] 578 error_names = [] 579 580 # Check the length. 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 # Loop over the data. 585 for i in range(len(value)): 586 # The data and error names. 587 data_names.append('value_%s' % i) 588 error_names.append('error_%s' % i) 589 590 # None. 591 elif value == None: 592 pass 593 594 # Simple values. 595 else: 596 # Sanity check. 597 if not data_type in [None, 'value']: 598 raise RelaxError("Mixed data types.") 599 data_type = 'value' 600 601 # Pack the data. 602 for spin, mol_name, res_num, res_name in spin_loop(full_info=True): 603 # Get the value and error. 604 value, error = return_value(spin, param, bc=bc) 605 606 # Append the spin data (scaled). 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 # Dictionary type data. 614 if data_type == 'dict': 615 # Initialise the lists. 616 values.append([]) 617 errors.append([]) 618 619 # Loop over the keys. 620 for key in data_names: 621 # Append the scaled values and errors. 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 # List type data. 632 elif data_type == 'list': 633 # Initialise the lists. 634 values.append([]) 635 errors.append([]) 636 637 # Loop over the data. 638 for i in range(len(data_names)): 639 # Append the scaled values and errors. 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 # Simple values. 650 else: 651 # Append the scaled values and errors. 652 values.append(scale(value, scaling)) 653 errors.append(scale(error, scaling)) 654 655 # Replace all spaces " " with "_" in data_names list. 656 if isinstance(data_names, list): 657 for i, data_name in enumerate(data_names): 658 data_str = data_name.replace(" ", "_") 659 # Replace string. 660 data_names[i] = data_str 661 662 # Replace all spaces " " with "_" in error_names list. 663 if isinstance(error_names, list): 664 for i, error_name in enumerate(error_names): 665 error_str = error_name.replace(" ", "_") 666 # Replace string. 667 error_names[i] = error_str 668 669 # Write the data. 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 # No a number, so return the value unmodified. 683 if not is_num(value): 684 return value 685 686 # Scale. 687 return value * scaling
688