1 """@namespace IMP.isd.utils
2 Miscellaneous utilities.
5 from __future__
import print_function
30 from threading
import Thread
59 return sum(x) / float(len(x))
62 def atexit_register(*args):
64 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)
79 class WatchDog(Thread):
81 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
113 timeout/4. at each iteration, and
114 if abs(time() - _last_ping) > timeout, exits.
117 while not self._stop:
119 if self._last_ping
is not None:
120 delta = abs(self._last_ping - time.time())
129 val =
'%.0f s' % delta
131 print(
'Watchdog: last life sign %s ago; timeout is %d min(s).'
132 % (val, self.timeout / 60.))
134 if self._last_ping
is not None and delta > self.timeout:
136 s =
'No life sign for > %d minute(s)' % (self.timeout / 60.)
138 print(s +
', exiting...')
140 if self.logfile
is not None:
142 if os.path.exists(self.logfile):
148 f = open(self.logfile, mode)
150 s +
'; host %s, %s\n' %
151 (socket.gethostname(), time.ctime()))
160 print(
'Watchdog: keeping Python interpreter alive.')
163 time.sleep(self.timeout / 4.)
168 symbols = (
'-',
'/',
'|',
'\')
173 def update(self, s=''):
174 sys.stdout.write(
'\r%s%s' % (s, self.symbols[self.state]))
177 self.state = (self.state + 1) % len(self.symbols)
182 """implements a FIFO pipe that merges lists (see self.put)"""
184 def __init__(self, length=-1):
190 """If x is subscriptable, insert its contents at the beginning of
191 the pipe. Else insert the element itself.
192 If the pipe is full, drop the oldest element.
197 self.pipe = list(x) + self.pipe
200 self.pipe.insert(0, x)
202 if self.length > 0
and len(self.pipe) > self.length:
203 self.pipe = self.pipe[:-1]
206 """x must be a list and will be appended to the end of the pipe,
207 dropping rightmost elements if necessary
210 self.pipe = (list(x) + self.pipe)[:self.length]
213 """returns the oldest element, without popping it out of the pipe.
214 Popping occurs in the put() method
218 def __getitem__(self, index):
219 return self.pipe.__getitem__(index)
222 return len(self.pipe)
225 return str(self.pipe)
228 return len(self.pipe) == self.length
233 def load_pdb(filename):
237 from Scientific.IO.PDB
import Structure
239 return Structure(os.path.expanduser(filename))
242 def copyfiles(src_path, dest_path, pattern=None, verbose=False):
244 from glob
import glob
245 from shutil
import copyfile
251 file_list = glob(os.path.join(src_path, pattern))
254 copyfile(f, os.path.join(dest_path, os.path.basename(f)))
263 f = open(filename,
'w')
266 except IOError
as error:
268 if os.path.isdir(filename):
277 """read sequence of ONE chain, 1-letter or 3-letter, returns dict of
278 no:3-letter code. Fails on unknown amino acids.
281 filename = os.path.abspath(filename)
285 raise IOError(
'Could not open sequence file "%s".' % filename)
286 seq = f.read().upper()
288 if seq.startswith(
'>'):
289 print(
"Detected FASTA 1-letter sequence")
292 seq =
''.join(seq[pos + 1:].split())
293 names = [code[i]
for i
in seq]
294 numbers = list(range(first_residue_number,
295 first_residue_number + len(seq)))
296 return dict(list(zip(numbers, names)))
300 if x
not in code.values():
301 print(
'Warning: unknown 3-letter code: %s' % x)
302 numbers = list(range(first_residue_number,
303 first_residue_number + len(spl)))
304 return dict(list(zip(numbers, spl)))
310 """checks whether residue codes a and b are the same, doing necessary
316 print(
'Warning: unknown 1-letter code: %s' % a)
321 print(
'Warning: unknown 1-letter code: %s' % b)
325 print(
'Unknown residue code %s' % a)
328 print(
'Unknown residue code %s' % b)
331 print(
'Residues %s and %s are not the same' % (a, b))
337 def my_glob(x, do_touch=False):
339 from glob
import glob
345 path, name = os.path.split(x)
353 def Dump(this, filename, gzip=0, mode='w', bin=1):
355 Dump(this, filename, gzip = 0)
356 Supports also '~' or '~user'.
361 import cPickle
as pickle
365 filename = os.path.expanduser(filename)
367 if mode
not in [
'w',
'a']:
368 raise ValueError(
"mode has to be 'w' (write) or 'a' (append)")
372 f = gzip.GzipFile(filename, mode)
374 f = open(filename, mode)
376 pickle.dump(this, f, bin)
381 def Load(filename, gzip=0, force=0):
383 Load(filename, gzip=0, force=0)
385 force: returns all objects that could be unpickled. Useful
386 when unpickling of sequential objects fails at some point.
391 filename = os.path.expanduser(filename)
396 f = gzip.GzipFile(filename)
400 f = open(filename,
'rb')
410 object = pickle.load(f)
424 print(
'Could not load chunk %d. Stopped.' % n)
429 object = pickle.load(f)
436 def get_pdb(pdb_entry, dest='.', verbose_level=0):
441 url =
'ftp.ebi.ac.uk'
442 path =
'pub/databases/rcsb/pdb-remediated/data/structures/all/pdb'
443 filename_template =
'pdb%s.ent.gz'
445 dest = os.path.expanduser(dest)
447 ftp = ftplib.FTP(url)
449 ftp.set_debuglevel(verbose_level)
453 filename = os.path.join(dest,
'%s.pdb.gz' % pdb_entry)
455 f = open(filename,
'wb')
458 ftp.retrbinary(
'RETR %s' % filename_template % pdb_entry.lower(),
465 except ftplib.error_perm:
466 raise IOError(
'File %s not found on server' % filename)
468 os.system(
'gunzip -f %s' % filename)
471 def compile_index_list(chain, atom_names, residue_index_list=None):
473 if residue_index_list
is None:
474 residue_index_list = list(range(len(chain)))
484 for res_index
in residue_index_list:
486 if atom_names
is None:
487 names = sorted(chain[res_index].keys())
491 if n
in chain[res_index]:
492 index = chain[res_index][n].index
493 index_list.append(index)
497 return index_list, index_map
500 def get_coordinates(universe, E, indices=None, atom_names=(
'CA',),
501 residue_index_list=
None, atom_index_list=
None):
503 from numpy.oldnumeric
import array, take
506 indices = list(range(len(E)))
508 chain = universe.get_polymer()
510 if atom_index_list
is None:
511 atom_index_list, index_map = compile_index_list(chain, atom_names,
518 chain.set_torsions(E.torsion_angles[i], 1)
520 X = array(take(universe.X, atom_index_list))
529 maps angles into interval [-pi,pi]
532 from numpy.oldnumeric
import fmod, greater, logical_not
535 from numpy.oldnumeric
import pi
as period
537 mask = greater(angles, 0.)
539 return mask * (fmod(angles + period, 2 * period) - period) + \
540 logical_not(mask) * (fmod(angles - period, 2 * period) + period)
543 def remove_from_dict(d, items):
550 def myrange(a, b, n):
552 from numpy.oldnumeric
import arange
554 step = (b - a) / (n - 1)
556 x = arange(a, b + step, step)
561 def indent(lines, prefix):
563 tag =
' ' * len(str(prefix))
565 lines[0] = prefix + lines[0]
566 lines = [lines[0]] + list(map(
lambda s, t=tag: t + s, lines[1:]))
568 return '\n'.join(lines)
571 def make_block(s, length=80, tol=10):
572 blocks = s.split(
'\n')
575 spl += _make_block(block, length, tol)
580 def _make_block(s, length, tol):
583 spl = [(w,
' ')
for w
in spl]
588 g = [w +
'/' for w
in g]
589 g[-1] = g[-1][:-1] +
' '
596 for i
in range(len(words)):
599 if len(line + word) <= length:
603 if length - len(line) > tol:
604 m = length - len(line)
608 if len(line) > 1
and line[0] ==
' ' and \
616 if len(line) > 1
and line[0] ==
' ' and \
625 def _save_dump(x, filename, err_msg=None, delay=10, show_io_err=True,
626 gzip=
False, bin=
True):
629 Dump(x, filename, gzip=gzip, bin=bin)
631 except IOError
as msg:
636 print(
'IOError: %s' % str(msg))
640 print(
'%s. %s' % (str(msg), err_msg))
648 time.sleep(60. * delay)
651 Dump(x, filename, gzip=gzip, bin=bin)
658 def save_dump(x, filename, err_msg=None, delay=10, show_io_err=True,
659 gzip=
False, mode=
'w', bin=
True):
664 path, _filename = os.path.split(filename)
666 temp_path, temp_filename = os.path.split(tempfile.mktemp())
667 temp_filename = os.path.join(path, temp_filename)
669 _save_dump(x, temp_filename, err_msg, delay, show_io_err,
675 os.rename(temp_filename, filename)
678 os.unlink(temp_filename)
679 Dump(x, filename, mode=
'a', gzip=gzip, bin=bin)
682 raise Exception(
'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...
The general base class for IMP exceptions.
def check_residue
checks whether residue codes a and b are the same, doing necessary conversions