1 """@namespace IMP.isd.utils
2 Miscellaneous utilities.
31 from Queue
import Queue
32 from threading
import Thread
61 return sum(x)/float(len(x))
63 def atexit_register(*args):
65 atexit.register(*args)
67 def atexit_unregister(func):
69 exit_funcs= [x[0]
for x
in atexit._exithandlers]
72 i = exit_funcs.index(func)
76 atexit._exithandlers.pop( i )
78 class WatchDog(Thread):
80 def __init__(self, timeout, debug=False, logfile=None):
88 self.timeout = timeout*60.
90 self._last_ping =
None
93 if logfile
is not None:
94 logfile = os.path.expanduser(logfile)
96 self.logfile = logfile
104 "set the _last_ping variable of the WatchDog instance"
107 print 'Watchdog: set(%s) called.' % str(x)
112 """run the Watchdog thread, which sits in a loop sleeping for timeout/4. at
113 each iteration, and if abs(time() - _last_ping) > timeout, exits.
116 while not self._stop:
118 if self._last_ping
is not None:
119 delta = abs(self._last_ping - time.time())
128 val =
'%.0f s' % delta
130 print 'Watchdog: last life sign %s ago; timeout is %d min(s).' % \
131 (val, self.timeout/60.)
133 if self._last_ping
is not None and delta > self.timeout:
135 s =
'No life sign for > %d minute(s)' % (self.timeout/60.)
137 print s +
', exiting...'
139 if self.logfile
is not None:
141 if os.path.exists(self.logfile):
147 f = open(self.logfile, mode)
148 f.write(s+
'; host %s, %s\n' % (socket.gethostname(), time.ctime()))
157 print 'Watchdog: keeping Python interpreter alive.'
160 time.sleep(self.timeout/4.)
164 symbols = (
'-',
'/',
'|',
'\\')
169 def update(self, s=''):
173 sys.stdout.write(
'\r%s%s' % (s, self.symbols[self.state]))
176 self.state = (self.state + 1) % len(self.symbols)
179 """implements a FIFO pipe that merges lists (see self.put)"""
181 def __init__(self, length = -1):
187 """if x is subscriptable, insert its contents at the beginning of the pipe.
188 Else insert the element itself.
189 If the pipe is full, drop the oldest element.
194 self.pipe = list(x) + self.pipe
197 self.pipe.insert(0, x)
199 if self.length > 0
and len(self.pipe) > self.length:
200 self.pipe = self.pipe[:-1]
203 """ x must be a list and will be appended to the end of the pipe, dropping
204 rightmost elements if necessary
207 self.pipe = (list(x) + self.pipe)[:self.length]
210 """returns the oldest element, without popping it out of the pipe.
211 Popping occurs in the put() method
215 def __getitem__(self, index):
216 return self.pipe.__getitem__(index)
219 return len(self.pipe)
222 return str(self.pipe)
225 return len(self.pipe) == self.length
229 class SortedQueue(Queue):
233 from numpy.oldnumeric
import array
234 from Isd.misc.mathutils
import average
236 self.queue.sort(
lambda a, b: cmp(average(a.time), average(b.time)))
238 self.times = array([average(x.time)
for x
in self.queue])
240 def _put(self, item):
242 Queue._put(self, item)
247 from numpy.oldnumeric
import power
248 from Isd.misc.mathutils
import draw_dirichlet, rescale_uniform
252 p = 1. - rescale_uniform(self.times)
255 index = draw_dirichlet(p)
257 val = self.queue[index]
259 self.queue = self.queue[:index] + self.queue[index + 1:]
266 def load_pdb(filename):
270 from Scientific.IO.PDB
import Structure
272 return Structure(os.path.expanduser(filename))
274 def copyfiles(src_path, dest_path, pattern=None, verbose=False):
276 from glob
import glob
277 from shutil
import copyfile
283 file_list = glob(os.path.join(src_path,pattern))
286 copyfile(f, os.path.join(dest_path, os.path.basename(f)))
294 f = open(filename,
'w')
297 except IOError, error:
299 if os.path.isdir(filename):
306 """read sequence of ONE chain, 1-letter or 3-letter, returns dict of
307 no:3-letter code. Fails on unknown amino acids.
310 filename = os.path.abspath(filename)
314 raise IOError,
'Could not open sequence file "%s".' % filename
315 seq = f.read().upper()
317 if seq.startswith(
'>'):
318 print "Detected FASTA 1-letter sequence"
321 seq=
''.join(seq[pos+1:].split())
322 names = [code[i]
for i
in seq]
323 numbers = range(first_residue_number, first_residue_number+len(seq))
324 return dict(zip(numbers,names))
328 if not x
in code.values():
329 print 'Warning: unknown 3-letter code: %s' % x
330 numbers = range(first_residue_number, first_residue_number+len(l))
331 return dict(zip(numbers,l))
335 "checks whether residue codes a and b are the same, doing necessary conversions"
340 print 'Warning: unknown 1-letter code: %s' % a
345 print 'Warning: unknown 1-letter code: %s' % b
349 print 'Unknown residue code %s' % a
352 print 'Unknown residue code %s' % b
355 print 'Residues %s and %s are not the same' % (a,b)
362 def my_glob(x, do_touch=False):
364 from glob
import glob
370 path, name = os.path.split(x)
377 def Dump(this, filename, gzip = 0, mode = 'w', bin=1):
379 Dump(this, filename, gzip = 0)
380 Supports also '~' or '~user'.
385 filename = os.path.expanduser(filename)
387 if not mode
in [
'w',
'a']:
388 raise "mode has to be 'w' (write) or 'a' (append)"
392 f = gzip.GzipFile(filename, mode)
394 f = open(filename, mode)
396 cPickle.dump(this, f, bin)
400 def Load(filename, gzip = 0, force=0):
402 Load(filename, gzip=0, force=0)
404 force: returns all objects that could be unpickled. Useful
405 when unpickling of sequential objects fails at some point.
409 filename = os.path.expanduser(filename)
414 f = gzip.GzipFile(filename)
428 object = cPickle.load(f)
442 print 'Could not load chunk %d. Stopped.' % n
447 object = cPickle.load(f)
453 def get_pdb(pdb_entry, dest='.', verbose_level=0):
456 from tempfile
import mktemp
459 url =
'ftp.ebi.ac.uk'
460 path =
'pub/databases/rcsb/pdb-remediated/data/structures/all/pdb'
461 filename_template =
'pdb%s.ent.gz'
463 dest = os.path.expanduser(dest)
465 ftp = ftplib.FTP(url)
467 ftp.set_debuglevel(verbose_level)
471 filename = os.path.join(dest,
'%s.pdb.gz' % pdb_entry)
473 f = open(filename,
'wb')
476 ftp.retrbinary(
'RETR %s' % filename_template % pdb_entry.lower(),
483 except ftplib.error_perm:
484 raise IOError,
'File %s not found on server' % filename
486 os.system(
'gunzip -f %s' % filename)
488 def compile_index_list(chain, atom_names, residue_index_list=None):
490 if residue_index_list
is None:
491 residue_index_list = range(len(chain))
501 for res_index
in residue_index_list:
503 if atom_names
is None:
504 names = chain[res_index].keys()
509 if n
in chain[res_index]:
510 index = chain[res_index][n].index
511 index_list.append(index)
515 return index_list, index_map
517 def get_coordinates(universe, E, indices=None, atom_names=(
'CA',),
518 residue_index_list=
None, atom_index_list=
None):
520 from numpy.oldnumeric
import array, take
523 indices = range(len(E))
525 chain = universe.get_polymer()
527 if atom_index_list
is None:
528 atom_index_list, index_map = compile_index_list(chain, atom_names,
535 chain.set_torsions(E.torsion_angles[i], 1)
537 X = array(take(universe.X, atom_index_list))
545 maps angles into interval [-pi,pi]
548 from numpy.oldnumeric
import fmod, greater, logical_not
551 from numpy.oldnumeric
import pi
as period
553 mask = greater(angles, 0.)
555 return mask * (fmod(angles+period, 2*period)-period) + \
556 logical_not(mask) * (fmod(angles-period, 2*period)+period)
558 def remove_from_dict(d, items):
564 def myrange(a, b, n):
566 from numpy.oldnumeric
import arange
568 step = (b - a) / (n - 1)
570 x = arange(a, b + step, step)
574 def indent(lines, prefix):
576 tag =
' ' * len(str(prefix))
578 lines[0] = prefix + lines[0]
579 lines = [lines[0]] + map(
lambda s, t = tag: t + s, lines[1:])
581 return '\n'.join(lines)
583 def make_block(s, length = 80, tol = 10):
584 blocks = s.split(
'\n')
587 l += _make_block(block, length, tol)
591 def _make_block(s, length, tol):
594 l = [(w,
' ')
for w
in l]
599 g = [w+
'/' for w
in g]
600 g[-1] = g[-1][:-1] +
' '
607 for i
in range(len(words)):
610 if len(line + word) <= length:
614 if length - len(line) > tol:
615 m = length - len(line)
619 if len(line) > 1
and line[0] ==
' ' and \
627 if len(line) > 1
and line[0] ==
' ' and \
635 def _save_dump(x, filename, err_msg=None, delay=10, show_io_err=True,
636 gzip=
False, bin=
True):
639 Dump(x, filename, gzip=gzip, bin=bin)
646 print 'IOError: %s' % str(msg)
650 print '%s. %s' % (str(msg), err_msg)
658 time.sleep(60. * delay)
661 Dump(x, filename, gzip=gzip, bin=bin)
667 def save_dump(x, filename, err_msg=None, delay=10, show_io_err=True,
668 gzip=
False, mode=
'w', bin=
True):
672 path, _filename = os.path.split(filename)
674 temp_path, temp_filename = os.path.split(tempfile.mktemp())
675 temp_filename = os.path.join(path, temp_filename)
677 _save_dump(x, temp_filename, err_msg, delay, show_io_err,
683 os.rename(temp_filename, filename)
686 os.unlink(temp_filename)
687 Dump(x, filename, mode=
'a', gzip=gzip, bin=bin)
690 raise StandardError,
'Mode "%s" invalid.' % mode
def map_angles
maps angles into interval [-pi,pi]
def put
if x is subscriptable, insert its contents at the beginning of the pipe.
implements a FIFO pipe that merges lists (see self.put)
def get
returns the oldest element, without popping it out of the pipe.
def read_sequence_file
read sequence of ONE chain, 1-letter or 3-letter, returns dict of no:3-letter code.
def append
x must be a list and will be appended to the end of the pipe, dropping rightmost elements if necessar...
def check_residue
checks whether residue codes a and b are the same, doing necessary conversions