Package generic_fns :: Module minimise
[hide private]
[frames] | no frames]

Source Code for Module generic_fns.minimise

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2005 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax.                                     # 
  6  #                                                                             # 
  7  # relax 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 2 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # relax 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 relax; if not, write to the Free Software                        # 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23   
 24  from Queue import Queue 
 25  from re import search 
 26   
 27  #from processes import RelaxPopen3 
 28  from thread_classes import RelaxParentThread, RelaxThread 
 29   
 30   
31 -class Minimise:
32 - def __init__(self, relax):
33 """Class containing the calc, grid_search, minimise, and set functions.""" 34 35 self.relax = relax
36 37
38 - def calc(self, run=None, print_flag=1):
39 """Function for calculating the function value.""" 40 41 # Test if the run exists. 42 if not run in self.relax.data.run_names: 43 raise RelaxNoRunError, run 44 45 # Function type. 46 function_type = self.relax.data.run_types[self.relax.data.run_names.index(run)] 47 48 # Specific calculate function setup. 49 calculate = self.relax.specific_setup.setup('calculate', function_type) 50 overfit_deselect = self.relax.specific_setup.setup('overfit_deselect', function_type) 51 52 # Deselect residues lacking data: 53 overfit_deselect(run) 54 55 # Monte Carlo simulation calculation. 56 if hasattr(self.relax.data, 'sim_state') and self.relax.data.sim_state.has_key(run) and self.relax.data.sim_state[run] == 1: 57 # Loop over the simulations. 58 for i in xrange(self.relax.data.sim_number[run]): 59 if print_flag: 60 print "Simulation " + `i+1` 61 calculate(run=run, print_flag=print_flag-1, sim_index=i) 62 63 # Minimisation. 64 else: 65 66 calculate(run=run, print_flag=print_flag)
67 68
69 - def grid_search(self, run=None, lower=None, upper=None, inc=None, constraints=1, print_flag=1):
70 """The grid search function.""" 71 72 # Test if the run exists. 73 if not run in self.relax.data.run_names: 74 raise RelaxNoRunError, run 75 76 # Function type. 77 function_type = self.relax.data.run_types[self.relax.data.run_names.index(run)] 78 79 # Specific grid search function. 80 grid_search = self.relax.specific_setup.setup('grid_search', function_type) 81 overfit_deselect = self.relax.specific_setup.setup('overfit_deselect', function_type) 82 83 # Deselect residues lacking data: 84 overfit_deselect(run) 85 86 # Monte Carlo simulation grid search. 87 if hasattr(self.relax.data, 'sim_state') and self.relax.data.sim_state.has_key(run) and self.relax.data.sim_state[run] == 1: 88 # Loop over the simulations. 89 for i in xrange(self.relax.data.sim_number[run]): 90 if print_flag: 91 print "Simulation " + `i+1` 92 grid_search(run=run, lower=lower, upper=upper, inc=inc, constraints=constraints, print_flag=print_flag-1, sim_index=i) 93 94 # Grid search. 95 else: 96 grid_search(run=run, lower=lower, upper=upper, inc=inc, constraints=constraints, print_flag=print_flag)
97 98
99 - def minimise(self, run=None, min_algor=None, min_options=None, func_tol=None, grad_tol=None, max_iterations=None, constraints=1, scaling=1, print_flag=1, sim_index=None):
100 """Minimisation function.""" 101 102 # Test if the run exists. 103 if not run in self.relax.data.run_names: 104 raise RelaxNoRunError, run 105 106 # Function type. 107 function_type = self.relax.data.run_types[self.relax.data.run_names.index(run)] 108 109 # Specific minimisation function. 110 minimise = self.relax.specific_setup.setup('minimise', function_type) 111 overfit_deselect = self.relax.specific_setup.setup('overfit_deselect', function_type) 112 113 # Deselect residues lacking data: 114 overfit_deselect(run) 115 116 # Single Monte Carlo simulation. 117 if sim_index != None: 118 minimise(run=run, min_algor=min_algor, min_options=min_options, func_tol=func_tol, grad_tol=grad_tol, max_iterations=max_iterations, constraints=constraints, scaling=scaling, print_flag=print_flag, sim_index=sim_index) 119 120 # Monte Carlo simulation minimisation. 121 elif hasattr(self.relax.data, 'sim_state') and self.relax.data.sim_state.has_key(run) and self.relax.data.sim_state[run] == 1: 122 # Threaded minimisation of simulations. 123 if self.relax.thread_data.status: 124 # Print out. 125 print "Threaded minimisation of Monte Carlo simulations.\n" 126 127 # Run the main threading loop. 128 RelaxMinParentThread(self.relax, run, min_algor, min_options, func_tol, grad_tol, max_iterations, constraints, scaling, print_flag) 129 130 # Non-threaded minimisation of simulations. 131 else: 132 for i in xrange(self.relax.data.sim_number[run]): 133 if print_flag: 134 print "Simulation " + `i+1` 135 minimise(run=run, min_algor=min_algor, min_options=min_options, func_tol=func_tol, grad_tol=grad_tol, max_iterations=max_iterations, constraints=constraints, scaling=scaling, print_flag=print_flag-1, sim_index=i) 136 137 # Standard minimisation. 138 else: 139 minimise(run=run, min_algor=min_algor, min_options=min_options, func_tol=func_tol, grad_tol=grad_tol, max_iterations=max_iterations, constraints=constraints, scaling=scaling, print_flag=print_flag)
140 141
142 - def reset_min_stats(self, run, index=None):
143 """Function for resetting the minimisation statistics.""" 144 145 # Arguments. 146 self.run = run 147 148 # Global minimisation statistics. 149 if index == None: 150 # Chi-squared. 151 if hasattr(self.relax.data, 'chi2') and self.relax.data.chi2.has_key(self.run): 152 self.relax.data.chi2[self.run] = None 153 154 # Iteration count. 155 if hasattr(self.relax.data, 'iter') and self.relax.data.iter.has_key(self.run): 156 self.relax.data.iter[self.run] = None 157 158 # Function count. 159 if hasattr(self.relax.data, 'f_count') and self.relax.data.f_count.has_key(self.run): 160 self.relax.data.f_count[self.run] = None 161 162 # Gradient count. 163 if hasattr(self.relax.data, 'g_count') and self.relax.data.g_count.has_key(self.run): 164 self.relax.data.g_count[self.run] = None 165 166 # Hessian count. 167 if hasattr(self.relax.data, 'h_count') and self.relax.data.h_count.has_key(self.run): 168 self.relax.data.h_count[self.run] = None 169 170 # Warning. 171 if hasattr(self.relax.data, 'warning') and self.relax.data.warning.has_key(self.run): 172 self.relax.data.warning[self.run] = None 173 174 # Sequence specific minimisation statistics. 175 else: 176 # Chi-squared. 177 if hasattr(self.relax.data.res[self.run][index], 'chi2'): 178 self.relax.data.res[self.run][index].chi2 = None 179 180 # Iteration count. 181 if hasattr(self.relax.data.res[self.run][index], 'iter'): 182 self.relax.data.res[self.run][index].iter = None 183 184 # Function count. 185 if hasattr(self.relax.data.res[self.run][index], 'f_count'): 186 self.relax.data.res[self.run][index].f_count = None 187 188 # Gradient count. 189 if hasattr(self.relax.data.res[self.run][index], 'g_count'): 190 self.relax.data.res[self.run][index].g_count = None 191 192 # Hessian count. 193 if hasattr(self.relax.data.res[self.run][index], 'h_count'): 194 self.relax.data.res[self.run][index].h_count = None 195 196 # Warning. 197 if hasattr(self.relax.data.res[self.run][index], 'warning'): 198 self.relax.data.res[self.run][index].warning = None
199 200
201 - def return_conversion_factor(self, stat_type):
202 """Dummy function for returning 1.0.""" 203 204 return 1.0
205 206
207 - def return_data_name(self, name):
208 """ 209 Minimisation statistic data type string matching patterns 210 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 211 212 ____________________________________________________________________________________________ 213 | | | | 214 | Data type | Object name | Patterns | 215 |________________________|______________|__________________________________________________| 216 | | | | 217 | Chi-squared statistic | 'chi2' | '^[Cc]hi2$' or '^[Cc]hi[-_ ][Ss]quare' | 218 | | | | 219 | Iteration count | 'iter' | '^[Ii]ter' | 220 | | | | 221 | Function call count | 'f_count' | '^[Ff].*[ -_][Cc]ount' | 222 | | | | 223 | Gradient call count | 'g_count' | '^[Gg].*[ -_][Cc]ount' | 224 | | | | 225 | Hessian call count | 'h_count' | '^[Hh].*[ -_][Cc]ount' | 226 |________________________|______________|__________________________________________________| 227 228 """ 229 230 # Chi-squared. 231 if search('^[Cc]hi2$', name) or search('^[Cc]hi[-_ ][Ss]quare', name): 232 return 'chi2' 233 234 # Iteration count. 235 if search('^[Ii]ter', name): 236 return 'iter' 237 238 # Function call count. 239 if search('^[Ff].*[ -_][Cc]ount', name): 240 return 'f_count' 241 242 # Gradient call count. 243 if search('^[Gg].*[ -_][Cc]ount', name): 244 return 'g_count' 245 246 # Hessian call count. 247 if search('^[Hh].*[ -_][Cc]ount', name): 248 return 'h_count'
249 250
251 - def return_grace_string(self, stat_type):
252 """Function for returning the Grace string representing the data type for axis labelling.""" 253 254 # Get the object name. 255 object_name = self.return_data_name(stat_type) 256 257 # Chi-squared. 258 if object_name == 'chi2': 259 grace_string = '\\xc\\S2' 260 261 # Iteration count. 262 elif object_name == 'iter': 263 grace_string = 'Iteration count' 264 265 # Function call count. 266 elif object_name == 'f_count': 267 grace_string = 'Function call count' 268 269 # Gradient call count. 270 elif object_name == 'g_count': 271 grace_string = 'Gradient call count' 272 273 # Hessian call count. 274 elif object_name == 'h_count': 275 grace_string = 'Hessian call count' 276 277 # Return the Grace string. 278 return grace_string
279 280
281 - def return_units(self, stat_type):
282 """Dummy function which returns None as the stats have no units.""" 283 284 return None
285 286
287 - def return_value(self, run, index=None, stat_type=None, sim=None):
288 """Function for returning the minimisation statistic corresponding to 'stat_type'.""" 289 290 # Arguments. 291 self.run = run 292 293 # Get the object name. 294 object_name = self.return_data_name(stat_type) 295 296 # The statistic type does not exist. 297 if not object_name: 298 raise RelaxError, "The statistic type " + `stat_type` + " does not exist." 299 300 # The simulation object name. 301 object_sim = object_name + '_sim' 302 303 # Get the global statistic. 304 if index == None: 305 # Get the statistic. 306 if sim == None: 307 if hasattr(self.relax.data, object_name) and getattr(self.relax.data.res[self.run][index], object_name).has_key(self.run): 308 stat = getattr(self.relax.data, object_name)[self.run] 309 else: 310 stat = None 311 312 # Get the simulation statistic. 313 else: 314 if hasattr(self.relax.data, object_sim) and getattr(self.relax.data.res[self.run][index], object_sim).has_key(self.run): 315 stat = getattr(self.relax.data, object_sim)[self.run][sim] 316 else: 317 stat = None 318 319 # Residue specific statistic. 320 else: 321 # Get the statistic. 322 if sim == None: 323 if hasattr(self.relax.data.res[self.run][index], object_name): 324 stat = getattr(self.relax.data.res[self.run][index], object_name) 325 else: 326 stat = None 327 328 # Get the simulation statistic. 329 else: 330 if hasattr(self.relax.data.res[self.run][index], object_sim): 331 stat = getattr(self.relax.data.res[self.run][index], object_sim)[sim] 332 else: 333 stat = None 334 335 # Return the statistic (together with None to indicate that there are no errors associated with the statistic). 336 return stat, None
337 338
339 - def set(self, run=None, value=None, error=None, param=None, scaling=None, index=None):
340 """ 341 Minimisation statistic set details 342 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 343 344 This shouldn't really be executed by a user. 345 """ 346 347 # Arguments. 348 self.run = run 349 350 # Get the parameter name. 351 param_name = self.return_data_name(param) 352 353 # Global minimisation stats. 354 if index == None: 355 # Chi-squared. 356 if param_name == 'chi2': 357 self.relax.data.chi2[self.run] = value 358 359 # Iteration count. 360 elif param_name == 'iter': 361 self.relax.data.iter[self.run] = value 362 363 # Function call count. 364 elif param_name == 'f_count': 365 self.relax.data.f_count[self.run] = value 366 367 # Gradient call count. 368 elif param_name == 'g_count': 369 self.relax.data.g_count[self.run] = value 370 371 # Hessian call count. 372 elif param_name == 'h_count': 373 self.relax.data.h_count[self.run] = value 374 375 # Residue specific minimisation. 376 else: 377 # Chi-squared. 378 if param_name == 'chi2': 379 self.relax.data.res[self.run][index].chi2 = value 380 381 # Iteration count. 382 elif param_name == 'iter': 383 self.relax.data.res[self.run][index].iter = value 384 385 # Function call count. 386 elif param_name == 'f_count': 387 self.relax.data.res[self.run][index].f_count = value 388 389 # Gradient call count. 390 elif param_name == 'g_count': 391 self.relax.data.res[self.run][index].g_count = value 392 393 # Hessian call count. 394 elif param_name == 'h_count': 395 self.relax.data.res[self.run][index].h_count = value
396 397 398 399 # Main threading loop for the minimisation of Monte Carlo simulations. 400 ###################################################################### 401
402 -class RelaxMinParentThread(RelaxParentThread):
403 - def __init__(self, relax, parent_run, *min_args):
404 """Initialisation of the Monte Carlo simulation minimisation parent thread.""" 405 406 # Arguments. 407 self.relax = relax 408 self.parent_run = parent_run 409 self.min_args = min_args 410 411 # Run the RelaxParentThread __init__ function. 412 RelaxParentThread.__init__(self) 413 414 # The number of jobs. 415 self.num_jobs = self.relax.data.sim_number[self.parent_run] 416 417 # Run the main loop. 418 self.run()
419 420
421 - def thread_object(self, i):
422 """Function for returning an initialised thread object.""" 423 424 # Return the thread object. 425 return RelaxMinimiseThread(self.relax, i, self.job_queue, self.results_queue, self.finished_jobs, self.job_locks, self.tag, self.parent_run, self.min_args)
426 427 428 429 # Threads for the minimisation of Monte Carlo simulations. 430 ########################################################## 431
432 -class RelaxMinimiseThread(RelaxThread):
433 - def __init__(self, relax, i, job_queue, results_queue, finished_jobs, job_locks, tag, parent_run, min_args):
434 """Initialisation of the thread.""" 435 436 # Arguments. 437 self.relax = relax 438 self.tag = tag 439 self.parent_run = parent_run 440 self.min_args = min_args 441 442 # Run the RelaxThread __init__ function (this is 'asserted' by the Thread class). 443 RelaxThread.__init__(self, i, job_queue, results_queue, finished_jobs, job_locks) 444 445 # Expand the minimisation arguments. 446 self.min_algor, self.min_options, self.func_tol, self.grad_tol, self.max_iterations, self.constraints, self.scaling, self.print_flag = self.min_args
447 448
449 - def generate_script(self):
450 """Function for generating the script for the thread to minimise sim `sim`.""" 451 452 # Function array. 453 fn = [] 454 455 # Function: Load the program state. 456 fn.append("self.relax.generic.state.load(file='%s')" % self.save_state_file) 457 458 # Function: Minimise. 459 fn.append("self.relax.generic.minimise.minimise(run='%s', min_algor='%s', min_options=%s, func_tol=%s, grad_tol=%s, max_iterations=%s, constraints=%s, scaling=%s, print_flag=%s, sim_index=%s)" % (self.parent_run, self.min_algor, self.min_options, self.func_tol, self.grad_tol, self.max_iterations, self.constraints, self.scaling, self.print_flag, self.job_number)) 460 461 # Function: Turn logging off. This is so that the results can come back through the child's stdout pipe. 462 fn.append("self.relax.IO.logging_off()") 463 464 # Generate the main text of the script file. 465 text = '' 466 for i in xrange(len(fn)): 467 text = text + "\nprint \"\\n" + fn[i] + "\"\n" 468 text = text + fn[i] + "\n" 469 470 # Function: Write the results to stdout. 471 text = text + "self.relax.generic.results.display(run='%s')\n" % (self.parent_run) 472 473 # Cat the text into the script file. 474 cmd = "cat > %s" % self.script_file 475 cmd = self.remote_command(cmd=cmd, login_cmd=self.login_cmd) 476 477 # Start the child process. 478 self.child = RelaxPopen3(cmd, capturestderr=1) 479 480 # Write the text to the child's stdin, then close it. 481 self.child.tochild.write(text) 482 self.child.tochild.close() 483 484 # Catch errors. 485 err = self.child.childerr.readlines() 486 487 # Close all pipes. 488 self.child.fromchild.close() 489 self.child.childerr.close() 490 491 # The file could not be copied. 492 if len(err): 493 raise RelaxError, "The command `%s` could not be executed." % cmd
494 495
496 - def post_locked_code(self):
497 """Code to run after locking the job.""" 498 499 # Create a run in the parent to temporarily store the data prior to copying into the main run. 500 self.relax.generic.runs.create(run=self.thread_run, run_type=self.relax.data.run_types[self.relax.data.run_names.index(self.parent_run)]) 501 502 # Read the data into the run. 503 self.relax.generic.results.read(run=self.thread_run, file_data=self.results, print_flag=0) 504 505 # Copy the results from the thread run to the parent run. 506 self.relax.generic.results.copy(run1=self.thread_run, run2=self.parent_run, sim=self.job_number) 507 508 # Delete the thread run. 509 self.relax.generic.runs.delete(self.thread_run) 510 511 # Print out. 512 print "Simulation: " + `self.job_number`
513