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