#!/usr/bin/env ccp4-python import os import sys import subprocess import shutil import time import signal from threading import Thread, Event, Timer #import traceback # ------------------------------------------------------------------------------ class Printable( object ) : def __str__( self ) : n = 0 for key in self.__dict__.keys() : n = max( n, len(key) ) fmt = "%-" + str(n) + "s = %s\n" txt = "-"* 12 + "\n" txt += type( self ).__name__ + "\n" for key, val in self.__dict__.items() : tv = type( val ) sv = str( tv ) if tv == str or tv == int or tv == float or tv == bool : sv = str( val ) txt += fmt %( key, sv ) txt += "-"* 12 return txt # ------------------------------------------------------------------------------ class Program( list ) : def __init__( self, *items ) : if len( items ) == 0 : raise Exception() self.cmd = [] self.txt = ["", "", "<<+"] self.sep = "" self.add_cmd( *items ) self.sep = "\n " def add_cmd( self, *items ) : if len( items ) == 0 : return self.txt[1] += self.sep for item in items : string = str( item ) self.cmd.append( string ) self.txt[1] += string + " " self.txt[1] += "\\" def add_kwd( self, *items ) : for item in items : self.txt.append( str( item ) ) def input( self ) : return "\n".join( self.txt[3:] + [""] ) def __str__( self ) : return "\n".join( self.txt + ["+", "", ""] ) # ------------------------------------------------------------------------------ class Scratch( object ) : holders = [] path = None sgpath = None test = 0 @classmethod def setup( cls, path, prefix, sgpath, test=0 ) : cls.count = 0 cls.test = test cls.path = os.path.abspath( path ) if os.path.isfile( cls.path ) : os.remove( cls.path ) if not cls.test and os.path.isdir( cls.path ) : shutil.rmtree( cls.path ) if not os.path.lexists( cls.path ) : os.mkdir( cls.path ) cls.prefix = os.path.join( cls.path, prefix ) if sgpath : cls.sgpath = os.path.abspath( sgpath ) if cls.sgpath == cls.path : raise ZnError( "Cannot handle " + str( dir ) + " - we should not get here" ) os.mkdir( cls.sgpath ) @classmethod def append( cls, subgrp, pdb, mtz ) : cls.holders.append( ( subgrp, pdb, mtz ) ) @classmethod def clear( cls ) : if cls.holders and cls.sgpath : try : if os.path.isfile( cls.sgpath ) : os.remove( cls.sgpath ) if os.path.isdir( cls.sgpath ) : shutil.rmtree( cls.sgpath ) os.mkdir( cls.sgpath ) for subgrp, pdb, mtz in cls.holders : dir = os.path.join( cls.sgpath, "sg%03d" %( subgrp ) ) os.mkdir( dir ) if cls.test : shutil.copy( pdb, dir ) shutil.copy( mtz, dir ) else : shutil.move( pdb, dir ) shutil.move( mtz, dir ) except : pass raise ZnError( "Cannot handle " + str( cls.sgpath ) + " - we should not get here" ) if cls.test : return if cls.path and os.path.isdir( cls.path ) : shutil.rmtree( cls.path ) def __init__( self, suffix ) : cls = type( self ) cls.count += 1 dir = "%s%03d_%s" %( cls.prefix, cls.count, suffix ) if os.path.isfile( dir ) : os.remove( dir ) if not os.path.isdir( dir ) : os.mkdir( dir ) self.bname = os.path.join( dir, "x" ) # ------------------------------------------------------------------------------ class Runnable( Printable ) : @classmethod def setup( cls, max_time, max_size, blck_size=256, test=0 ) : cls.max_time = max_time cls.max_size = max_size cls.blck_size = blck_size cls.test = test try : startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW cls.args = dict( bufsize=cls.blck_size, startupinfo = startupinfo ) except : cls.args = dict( bufsize=cls.blck_size ) std_items = (("com", ".com"), ("inp", ".inp"), ("log", ".log"), ("err", ".err")) def _setup( self, suffix, **map ) : bname = Scratch( suffix ).bname for key, val in map.items() : if val.startswith( "." ) or val.startswith( "_" ) : val = bname + val self.__setattr__( key, val ) for key, val in self.std_items : if key not in map : self.__setattr__( key, bname + val ) def _run( self, prog ) : ofile = open( self.com, "w" ) try : ofile.write( str( prog ) ) finally : ofile.close() ofile = open( self.inp, "w" ) try : ofile.write( str( prog.input() ) ) finally : ofile.close() if os.path.exists( self.log ) and not os.path.exists( self.err ) : return if self.test : sys.stderr.write( "%-14s" %os.path.basename( os.path.dirname( self.log ) ) ) enter_time = time.time() timer = Timer( self.max_time, self._kill ) try : timer.start() stdin = open( self.inp ) try : try : pipe = subprocess.PIPE args = dict( stdin=stdin, stdout=pipe, stderr=pipe ) args.update( self.args ) self.proc = subprocess.Popen( prog.cmd, **args ) try : try : self._write( self.proc.stdout, self.log, self._accept ) self._write( self.proc.stderr, self.err, lambda x : True ) except : self._kill() raise ZnError( "we should not get here" ) finally : self.proc.stdout.close() self.proc.stderr.close() code = self.proc.wait() if code : raise ZnExecError( code, prog.cmd[0] ) except : raise ZnError( "failed to execute " + prog.cmd[0] ) finally : stdin.close() finally : timer.cancel() timer.join() if self.test : exit_time = time.time() sys.stderr.write( "%9.3f\n" %( exit_time - enter_time ) ) def _write( self, std, name, accept ) : if os.path.exists( name ) : os.remove( name ) line = std.read( self.blck_size ) if not line : return size = len( line ) ofile = open( name, "w" ) try : while line : if size > self.max_size : self._kill() ofile.write( line ) line = std.read( self.blck_size ) size += len( line ) finally : ofile.flush() os.fsync( ofile.fileno() ) ofile.close() def _filtered_write( self, std, name, accept ) : if os.path.exists( name ) : os.remove( name ) line = std.readline( self.blck_size ) if not line : return size = len( line ) ofile = open( name, "w" ) try : while line : if size > self.max_size : self._kill() if accept( line ) : ofile.write( line ) ofile.flush() os.fsync( ofile.fileno() ) line = std.readline( self.blck_size ) size += len( line ) finally : ofile.close() def _kill( self ) : try : self.proc.kill() except : pass else : return try : os.kill( self.proc.pid, signal.SIGKILL ) except : pass else : return raise Exception( "stopping because cannot kill a subprocess" ) exclude = ["User: ", "CPU", "From cif2mtz", " unknown", " Elapsed", "data from CAD"] def _accept( self, line ) : for word in self.exclude : if line.find( word ) >= 0 : return False return True # ------------------------------------------------------------------------------ class ZnError( Exception ) : def __init__( self, msg ) : self.args = (msg,) def format( self ) : return "\n".join( [""," Zanuda: " + self.args[0], ""] ) # ------------------------------------------------------------------------------ class ZnExecError( ZnError ) : def __init__( self, code, command ) : msg = "error while executing command " msg += command + ", return code = " + str(code ) super( type(self), self ).__init__( msg ) # ------------------------------------------------------------------------------ class ZnPath( object ) : @classmethod def setup( cls, own_dir ) : ftn = os.path.join( own_dir, "znd_subs.exe" ) if not os.path.isfile( ftn ) : ftn = os.path.join( own_dir, "znd_subs" ) if os.path.isfile( ftn ) and os.access( ftn, os.X_OK ) : cls.znd_subs = os.path.realpath( ftn ) else : raise ZnError( "cannot find fortran module '" + ftn + "'" ) # ------------------------------------------------------------------------------ class ZnTrimmed( ZnPath, Runnable ) : def __init__( self, pdb ) : self._setup( suffix="p1", pdb=".pdb" ) prog = Program( self.znd_subs ) prog.add_cmd( "XYZIN", pdb ) prog.add_cmd( "XYZOUT", self.pdb ) self._run( prog ) # ------------------------------------------------------------------------------ class ZnEqualised( ZnPath, Runnable ) : def __init__( self, pdb ) : self._setup( suffix="p2", pdb=".pdb", rej=".rej" ) prog = Program( self.znd_subs ) prog.add_cmd( "XYZIN", pdb ) prog.add_cmd( "XYZOUT", self.pdb ) prog.add_cmd( "XYZREJ", self.rej ) self._run( prog ) # ------------------------------------------------------------------------------ class ZnCompareCaa( ZnPath, Runnable ) : def __init__( self, mst, pdb1, pdb2 ) : self._setup( suffix="p6", pdb=".pdb" ) prog = Program( self.znd_subs ) prog.add_cmd( "OPSIN", mst ) prog.add_cmd( "XYZIN1", pdb1 ) prog.add_cmd( "XYZIN2", pdb2 ) prog.add_cmd( "XYZOUT", self.pdb ) self.rmsd = None try : self._run( prog ) ifile = open( self.log ) try : for line in ifile : if line[0:2] == "AA" : self.rmsd = float( line.replace( "F", " " ).replace( "T", " " ).split()[1] ) break finally : ifile.close() except : pass # ------------------------------------------------------------------------------ class ZnTransformCif( ZnPath, Runnable ) : def __init__( self, mst, cif, subgrp_in, subgrp_out, badd, fslim ) : self._setup( suffix="p5", cif=".cif" ) prog = Program( self.znd_subs ) prog.add_cmd( "OPSIN", mst ) prog.add_cmd( "SGIN", subgrp_in ) prog.add_cmd( "SGOUT", subgrp_out ) prog.add_cmd( "CIFIN", cif ) prog.add_cmd( "CIFOUT", self.cif ) prog.add_cmd( "BADD", badd ) prog.add_cmd( "FSLIM", fslim ) self._run( prog ) # ------------------------------------------------------------------------------ class Znd_dmp_to_cif( ZnPath, Runnable ) : def __init__( self, dmp ) : self._setup( suffix="pX", cif=".cif" ) prog = Program( self.znd_subs ) prog.add_cmd( "DMPIN", dmp ) prog.add_cmd( "CIFOUT", self.cif ) self._run( prog ) # ------------------------------------------------------------------------------ class Znd_stat_hkl( Runnable ) : def __init__( self, mtz ) : self._setup( suffix="mtzdump", log=".dmp" ) prog = Program( "mtzdump" ) prog.add_cmd( "HKLIN", mtz ) prog.add_kwd( "go" ) self._run( prog ) ifile = open( self.log ) try : x = ifile.readlines() finally : ifile.close() cou = 0 for line in x : if line.startswith( " * Column Types :" ) : i1 = cou elif line.startswith( " * Space group =" ) : i2 = cou cou += 1 self.free = x[i1+2].find( " I" ) > 0 self.symm = int( x[i2].replace(")"," ").rsplit( None, 1 )[1] ) # ------------------------------------------------------------------------------ class Znd_sort_hkl( Runnable ) : def __init__( self, mtz, symm ) : self._setup( suffix="cad", mtz=".mtz" ) prog = Program( "cad" ) prog.add_cmd( "HKLIN1", mtz ) prog.add_cmd( "HKLOUT", self.mtz ) prog.add_kwd( "labin file 1 allin", "symmetry " + str( symm ), "end" ) self._run( prog ) # ------------------------------------------------------------------------------ class Znd_free_flag( Runnable ) : def __init__( self, mtz ) : self._setup( suffix="freerflag", mtz=".mtz" ) prog = Program( "freerflag" ) prog.add_cmd( "HKLIN", mtz ) prog.add_cmd( "HKLOUT", self.mtz ) prog.add_kwd( "freefr 0.05", "end" ) self._run( prog ) # ------------------------------------------------------------------------------ class Znd_dump_hkl( Runnable ) : def __init__( self, mtz ) : self._setup( suffix="mtzdump", log=".dmp" ) prog = Program( "mtzdump" ) prog.add_cmd( "HKLIN", mtz ) prog.add_kwd( "nref -1", "go" ) self._run( prog ) # ------------------------------------------------------------------------------ class Znd_cif_to_mtz( Runnable ) : def __init__( self, cif ) : self._setup( suffix="cif2mtz", mtz=".mtz" ) prog = Program( "cif2mtz" ) prog.add_cmd( "HKLIN", cif ) prog.add_cmd( "HKLOUT", self.mtz ) prog.add_kwd( "end" ) self._run( prog ) # ------------------------------------------------------------------------------ class Cif_Info( object ) : def __init__( self, cif ) : ifile = open( cif ) try : for line in ifile : if line.startswith( "_reflns.number_obs" ) : word = line.split()[1] if word.isdigit() : self.nrefl = int( word ) break finally : ifile.close() # ------------------------------------------------------------------------------ class Pdb_Info( object ) : def __init__( self, pdb ) : if not pdb : return ifile = open( pdb ) try : for line in ifile : if line.startswith( "CRYST1" ) : self.spacegrp = line[55:65].strip() self.cell = tuple( line[6:55].split() ) finally : ifile.close() # ------------------------------------------------------------------------------ class ZnOperations( ZnPath, Runnable ) : def __init__( self, pdb, mtz, badd, fslim ) : self._setup( suffix="p3", t_pdb="_t.pdb", pdb=".pdb", mst=".mst" ) prog = Program( self.znd_subs ) prog.add_cmd( "XYZIN", pdb ) prog.add_cmd( "XYZOUT", self.t_pdb ) prog.add_cmd( "OPSOUT", self.mst ) self._run( prog ) self._renumber( self.t_pdb, self.pdb ) self.subgrp = self._subgrp_from_pdb( self.pdb ) hklinfo = Znd_stat_hkl( mtz ) if not hklinfo.free : mtz = Znd_free_flag( mtz ).mtz sorted = Znd_sort_hkl( mtz, hklinfo.symm ) cif = Znd_dmp_to_cif( Znd_dump_hkl( sorted.mtz ).log ).cif self.high = ZnTransformCif( self.mst, cif, 0, 1, 0.0, 0.0 ).cif self.low = ZnTransformCif( self.mst, cif, 0, 1, badd, fslim ).cif def _subgrp_from_pdb( self, pdb ) : ifile = open( pdb ) try : line = ifile.readline() finally : ifile.close() if line.startswith( "END" ) : return -1 if line.find( "subgroup_number" ) < 0 : return words = line.split() if len( words ) < 3 or not words[2].isdigit() : return return int( words[2] ) def rigid_groups( self ) : rg = [] ifile = open( self.log ) try : for line in ifile : if line.startswith( "rigid group" ) : rg.append( line.strip() ) finally : ifile.close() return rg def get_list( self, notwin ) : prefix = "group Z" if notwin : prefix = "group ZZ" group_list = [] ifile = open( self.log ) try : for line in ifile : if line.startswith( prefix ) : group_list.append( int( line[17:21] ) ) finally : ifile.close() return group_list def _renumber( self, ipdb, opdb ) : ifile = open( ipdb ) ofile = open( opdb, "w" ) try : iline = ifile.readline() while iline and not ( iline.startswith( "ATOM " ) or iline.startswith( "HETATM" ) ) : ofile.write( iline ) iline = ifile.readline() cou = 0 while iline and ( iline.startswith( "ATOM " ) or iline.startswith( "HETATM" ) ) : cou = cou + 1 ofile.write( iline[0:6] + "%5d" %( cou ) + iline[11:] ) iline = ifile.readline() if cou == 99999 : cou = 0 while iline : ofile.write( iline ) iline = ifile.readline() finally : ifile.close() ofile.close() # ------------------------------------------------------------------------------ class ZnTransform( ZnOperations ) : fmt = "REMARK subgroup_number %5d\n" def __init__( self, data, input, subgrp_out ) : if input.subgrp != self._subgrp_from_pdb( input.pdb ) : raise Exception() suffix = "%s_s%03d" %( "p4", max( 0, subgrp_out ) ) self._setup( suffix=suffix, t_pdb="_t.pdb", pdb=".pdb" ) prog = Program( self.znd_subs ) prog.add_cmd( "OPSIN", data.mst ) prog.add_cmd( "SGOUT", str(subgrp_out) ) prog.add_cmd( "XYZIN", input.pdb ) prog.add_cmd( "XYZOUT", self.t_pdb ) self._run( prog ) self._renumber( self.t_pdb, self.pdb ) self.subgrp = self._subgrp_from_pdb( self.pdb ) if not self.subgrp : raise Exception() if self.subgrp <= 0 and subgrp_out >= 0 : raise Exception() # ------------------------------------------------------------------------------ class RefmacVersion( Runnable ) : def __init__( self, refmac ) : self._setup( suffix="version" ) prog = Program( refmac, "-i" ) prog.add_kwd( "end" ) try : self._run( prog ) except ZnExecError : pass try : ifile = open( self.log ) try : x = ifile.read( 500 ).lower() self.version = x[x.find("version ",100):].split()[1] self.old = int( self.version.replace( ".", "" ) ) < 540030 finally : ifile.close() except : raise ZnError( "cannot identify refmac version.\nCommand used: " + refmac ) # ------------------------------------------------------------------------------ class VirtualRun( object ) : counts_at_crash = None count = 0L @classmethod def setup( cls, crash ) : if crash : cls.counts_at_crash = [] for x in crash.split(",") : cls.counts_at_crash.append( int( x ) ) @classmethod def has_crashed( cls ) : if cls.counts_at_crash is None : return False cls.count += 1 crashed = cls.count in cls.counts_at_crash print "@@@@@@@@ COU", cls.count, crashed return crashed # return cls.count in cls.counts_at_crash # ------------------------------------------------------------------------------ class Refmac( Runnable ) : old_refmac_on_server = "/data/programs/BALBES/BALBES_0.0.1/bin/refmac_linintel" @classmethod def setup( cls, path_scr, own_dir, test=0 ) : if not os.environ.has_key( "CCP4" ) or not os.environ.has_key( "CBIN" ) : raise ZnError( "fatal error, CCP4 is not installed" ) cls.refmac="refmac5" own_refmac = os.path.join( own_dir, cls.refmac ) if os.path.isfile( own_refmac ) and os.access( own_refmac, os.X_OK ) : cls.refmac = os.path.realpath( own_refmac ) if test : print "refmac = ", cls.refmac own_monomers = os.path.join( own_dir, "monomers" ) if os.path.isdir( own_monomers ) and os.access( own_monomers, os.R_OK ) : os.environ["CLIBD_MON"] = os.path.join( os.path.realpath( own_monomers ), "" ) if test : print "monomers = ", os.environ["CLIBD_MON"] rv = RefmacVersion( cls.refmac ) cls.version = rv.version cls.scr = "SCRREF", os.path.join( path_scr, "SCRREF" ) if rv.old : cls.scr = () def _refine( self, pdb, mtz, reformat=True, no_free_ok=False ) : if reformat : self._setup( suffix="refmac", t_pdb="_t.pdb", pdb=".pdb", mtz=".mtz" ) else : self._setup( suffix="refmac", pdb=".pdb", mtz=".mtz" ) self.t_pdb = self.pdb prog = Program( self.refmac ) prog.add_cmd( "XYZIN", pdb ) prog.add_cmd( "HKLIN", mtz ) prog.add_cmd( "XYZOUT", self.t_pdb ) prog.add_cmd( "HKLOUT", self.mtz ) prog.add_cmd( *self.scr ) prog.add_kwd( *self.kwd ) try : self._run( prog ) self.R_over = None self.R_free = None ifile = open( self.log ) try : for line in ifile : if line.startswith( "Overall R factor " ) : self.R_over = float( "0." + line.split( "." )[1] ) elif line.startswith( "Free R factor " ) : self.R_free = float( "0." + line.split( "." )[1] ) finally : ifile.close() if no_free_ok : pass elif self.R_free == None : raise Exception() if reformat : self._reformat( pdb, self.t_pdb, self.pdb ) self.status = 0 if VirtualRun.has_crashed() : raise Exception() except : self.pdb = pdb self.mtz = None self.R_over = None self.R_free = None self.status = 1 def _reformat( self, fpdb, ipdb, opdb ) : try : ffile = open( fpdb ) ifile = open( ipdb ) ofile = open( opdb, "w" ) ilist = list() for iline in ifile: if iline.startswith( "ATOM " ) or iline.startswith( "HETATM" ) : ilist.append(iline) fline = ffile.readline() while fline and not ( fline.startswith( "ATOM " ) or fline.startswith( "HETATM" ) ) : ofile.write( fline ) fline = ffile.readline() cou = 0 while fline and ( fline.startswith( "ATOM " ) or fline.startswith( "HETATM" ) ) : iline = ilist[cou] if not self._compare( iline, fline ) : print iline print fline raise ZnError( "cannot reformat refmac output" ) ofile.write( fline[0:30] + iline[30:66] + fline[66:] ) fline = ffile.readline() cou += 1 while fline != "" : ofile.write( fline ) fline = ffile.readline() finally : ffile.close() ifile.close() ofile.close() def _compare( self, iline, fline ) : if iline[11:16].strip() != fline[11:16].strip() : print iline[11:16].strip() print fline[11:16].strip() return False if iline[16:17] != fline[16:17] : print iline[16:17] print fline[16:17] return False if iline[17:21].strip() != fline[17:21].strip() : print iline[17:21].strip() print fline[17:21].strip() return False if iline[22:30] != fline[22:30] : print iline[22:30] print fline[22:30] return False return True # ------------------------------------------------------------------------------ class Tested( Refmac ) : kwd = ["make hydr no", "make check none", "make link no connectivity no", "ncyc 0", "end"] def __init__( self, xyzin, hklin ) : self._refine( xyzin, hklin, reformat=False, no_free_ok=True ) if self.status : return pdbinfo = Pdb_Info( self.pdb ) self.info_spacegrp = pdbinfo.spacegrp self.info_cell = pdbinfo.cell self.info_reso = "n/a" ifile = open( self.log ) try : for line in ifile : if line.startswith( "Resolution limits " ) : try : self.info_reso = "%5.3f" %( float( line.split( "=" )[1].split()[1] ) ) except : pass break finally : ifile.close() # ------------------------------------------------------------------------------ class Rigid( Refmac ) : kwd = ["make hydr no", "make segid yes", "bfac set 20.0", "refi type rigid", "labin FP=FP SIGFP=SIGFP FREE=FREE"] def __init__( self, pdb, mtz, subgrp, ncyc_rigid, rigid_groups ) : self.subgrp = subgrp self.kwd = self.kwd + rigid_groups + ["rigid ncyc " + str( ncyc_rigid ), "end"] self._refine( pdb, mtz ) # ------------------------------------------------------------------------------ class Restrained( Refmac ) : kwd = ["make segid yes", "make check NONE", "make -"] kwd += ["hydrogen NO -", "hout NO -", "peptide NO -", "cispeptide NO -", "ssbridge YES -"] kwd += ["chain NO -", "symmetry NO -", "sugar NO -", "connectivity NO -", "link NO"] kwd += ["weight auto", "labin FP=FP SIGFP=SIGFP FREE=FREE"] # kwd += ["bfac set 20.0", "scale type bulk", "weight -", "matrix 0.01"] def __init__( self, pdb, mtz, subgrp, ncyc_restr ) : self.subgrp = subgrp self.kwd = self.kwd + ["ncyc " + str( ncyc_restr ), "end"] self._refine( pdb, mtz ) # ------------------------------------------------------------------------------ class MtzHolder( object ) : def __init__( self, data, subgrp, high=True ) : if high : cif_in = data.high else : cif_in = data.low cif_out = ZnTransformCif( data.mst, cif_in, 1, subgrp, 0.0, 0.0 ).cif self.mtz = Znd_cif_to_mtz( cif_out ).mtz # ------------------------------------------------------------------------------ class RefCycle( object ) : rigid = None restr = None score = 999.9 def __init__( self, data, subgroup, subgrp_no, ncyc_rigid, ncyc_restr, flag_save=False ) : self.initial = ZnTransform( data, subgroup, subgrp_no ) current = self.initial if current.subgrp < 0 : return if ncyc_rigid >= 0 : holder = MtzHolder( data, self.initial.subgrp, False ) rgrp = self.initial.rigid_groups() self.rigid = Rigid( current.pdb, holder.mtz, self.initial.subgrp, ncyc_rigid, rgrp ) current = self.rigid if ncyc_restr >= 0 or flag_save : holder = MtzHolder( data, self.initial.subgrp ) if flag_save : Scratch.append( self.initial.subgrp, self.initial.pdb, holder.mtz ) if ncyc_restr >= 0 : self.restr = Restrained( current.pdb, holder.mtz, self.initial.subgrp, ncyc_restr ) current = self.restr if self.restr.R_free : self.score = self.restr.R_free self.pdbinfo = Pdb_Info( current.pdb ) self.compared = ZnCompareCaa( data.mst, data.pdb, current.pdb ) def __str__( self ) : models = self.initial, self.pdbinfo, self.compared, self.rigid, self.restr, self.restr, self table = zip( models, self.keys, self.fmt_val, self.fmt_n_a, self.fmt_err ) if VirtualRun.counts_at_crash is None : table = table[0:len(table)-1] line = "" for model, key, fv, fn, fe in table : if model : value = getattr( model, key ) if value != None : value = fv %( value ) else : value = fe else : value = fn line += value return line keys = ["subgrp", "spacegrp", "rmsd", "R_over", "R_over", "R_free", "score"] fmt_val = "1111 |; P 21 21 21 |;100.0000 |;100.0000 |;100.0000 |;100.0000 |;100.0000 |" fmt_n_a = " -- |; -- |; -- |; -- |; -- |; -- |; -- |" fmt_err = " error |; error |; error |; error |; error |; error |; error |" fmt_val = fmt_val.replace( "1111" , "%4d" ) fmt_val = fmt_val.replace( "P 21 21 21", "%-10s" ) fmt_val = fmt_val.replace( "100.0000" , "%8.4f" ) fmt_val = fmt_val.split( ";" ) fmt_n_a = fmt_n_a.split( ";" ) fmt_err = fmt_err.split( ";" ) # ------------------------------------------------------------------------------ class ZnPrinter( object ) : @classmethod def setup( cls, version, date, title, test=0 ) : cls.title = title cls.test = test print print " zanuda", version, "(", date, ")" time0 = 1292077608.66 time1 = 1292077618.82 time2 = 1292077659.98 time3 = 1292077789.10 time4 = 1292077929.96 def _timef( self, value ) : return time.strftime( "%b %d %H:%M %Z", time.localtime( value ) ) def __init__( self, xyzin, hklin ) : self.xyzin_bname = os.path.basename( xyzin ) self.hklin_bname = os.path.basename( hklin ) def print_step0a( self ) : if self.title : print print " title " + self.title print print " coordinates " + self.xyzin_bname print " data " + self.hklin_bname sys.stdout.flush() def print_step0b( self, tested ) : print " readability test passed (Refmac_" + tested.version + ")" print " resolution " + tested.info_reso print " spacegroup " + tested.info_spacegrp print " cell " + " ".join( tested.info_cell ) sys.stdout.flush() def print_step0c( self, tested ) : print " readability test failed (Refmac_" + tested.version + "):" print if os.path.exists( tested.err ) : ifile = open( tested.err ) try : sys.stdout.write( ifile.read() ) finally : ifile.close() print print " ------------------------------------------" print " Make sure that the following script works:" print print " refmac5 xyzin " + self.xyzin_bname + " hklin " + self.hklin_bname + "<<+" print " " + "\n ".join( tested.kwd ) print " +" print sys.stdout.flush() def estimate_times( self, grp_list, ncyc, nrefl ) : ngrp = len( grp_list ) self.delta1 = ( ( ncyc[0] + ncyc[1]* 2 )* ngrp + ncyc[2] + ncyc[3]* 8 )* nrefl/ 26000 self.coef2 = ( ngrp + 3.0 )/ 2 self.coef3 = 4.0/ ngrp self.ngrp = str( ngrp ) def print_step1( self ) : time0 = time.time() if self.test : time0 = self.time0 timeE = time0 + self.delta1 print print " Step 1." print " R-factors for the starting model." print " Transformation into a supergroup." print print " current time: " + self._timef( time0 ) print " expected end of job (rough estimate): " + self._timef( timeE ) print sys.stdout.flush() def print_step2a( self, cycle, cycle_max, cycle_wrk ) : self.cycle = cycle_wrk if not self.test : self.time1 = time.time() if self.cycle == cycle : arrow = " " elif self.cycle == cycle_max : arrow = "<<" else : raise Exception() print " ---------------------------------------------------------------------" print " | Subgroup | Spacegroup | R.m.s.d. | Refinement in tested group |" print " | | | from the |--------------------------------|" print " | Ref | | starting | Rigid | Restrained |" print " | | | model, A |----------|---------------------|" print " | | | | R | R | R-free |" print " |----------|------------|----------|----------|----------|----------|" print " | >>" + str( cycle ) print " | " + arrow + str( cycle_max ) print " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" print print " Step 2." print " Refinements in subgroups." print " There are " + self.ngrp + " subgroups to test." print print " current time: " + self._timef( self.time1 ) sys.stdout.flush() def print_step2b( self ) : time2 = time.time() if self.test : time2 = self.time2 timeE = time2 + ( time2 - self.time1 )* self.coef2 print " expected end of job: " + self._timef( timeE ) print print " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" print " | >>" + str( self.cycle ) print " ---------------------------------------------------------------------" sys.stdout.flush() def print_cycle( self, cycle ) : print " | " + str( cycle ) sys.stdout.flush() def print_step3a( self ) : print " ---------------------------------------------------------------------" def print_step3b( self, cycle ) : time3 = time.time() if self.test : time3 = self.time3 timeE = time3 + ( time3 - self.time1 )* self.coef3 print " | <<" + str( cycle ) print " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" print print " Step 3." print " Refinement of the best model." print " Candidate symmetry elements are added one by one." print print " current time: " + self._timef( time3 ) print " expected end of job: " + self._timef( timeE ) print print " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" print " | >>" + str( cycle ) print " ---------------------------------------------------------------------" sys.stdout.flush() def print_results( self, the_same, cycle ) : time4 = time.time() if self.test : time4 = self.time4 print " ---------------------------------------------------------------------" print " | <<" + str( cycle ) print " ---------------------------------------------------------------------" print if the_same : print " R-factor in the original subgroup is (almost) the best." print " The original spacegroup assignment seems to be correct." else : print " R-factor in the original subgroup is NOT the best." print " The original spacegroup assignment seems to be incorrect." print print " end of job: " + self._timef( time4 ) print sys.stdout.flush() # ------------------------------------------------------------------------------ class ZnMain( object ) : ncyc = [ 24, 8, 8, 8 ] xyzout = None hklout = None @classmethod def setup_cycles( cls, *ncyc ) : cls.ncyc = list( ncyc ) def __init__( self, xyzin, hklin, badd, fslim, notwin, aver ) : tolerance = 0.02 printer = ZnPrinter( xyzin, hklin ) printer.print_step0a() trimmed = ZnTrimmed( xyzin ) tested = Tested( trimmed.pdb, hklin ) if not tested.status : printer.print_step0b( tested ) else : printer.print_step0c( tested ) raise ZnError( "cannot read input data" ) data = ZnOperations( ZnEqualised( tested.pdb ).pdb, tested.mtz, badd, fslim ) grp_list = data.get_list( notwin ) printer.estimate_times( grp_list, self.ncyc, Cif_Info( data.high ).nrefl ) printer.print_step1() c0n = RefCycle( data, data, 0, -1, 0 ) c0a = RefCycle( data, data, 999, -1, -1 ) c1 = c0n if aver : c1 = c0a printer.print_step2a( c0n, c0a, c1 ) first = True for subgrp_no in grp_list : c2 = RefCycle( data, c1.initial, subgrp_no, self.ncyc[0], self.ncyc[1], True ) if first : first = False printer.print_step2b() best2 = c2 elif c2.score <= best2.score : best2 = c2 printer.print_cycle( c2 ) printer.print_step3a() if self.ncyc[2] < 0 or self.ncyc[3] < 0 : return elif not best2.rigid.status : selected2 = best2.rigid elif not best2.restr.status : selected2 = best2.restr else : raise Exception() printer.print_step3b( best2 ) best3 = RefCycle( data, selected2, 1, self.ncyc[2], self.ncyc[3] ) if best3.restr.status : printer.print_cycle( best3 ) best3 = best2 c3 = best3 count = 1 while c3.initial.subgrp > 0 : printer.print_cycle( c3 ) if c3.restr.status : raise Exception() if c3.score - best3.score > tolerance : break count += 1 if count > 7 : raise Exception() best3 = c3 c3 = RefCycle( data, c3.restr, -100, -1, self.ncyc[3] ) the_same = best3.initial.subgrp == c0n.initial.subgrp printer.print_results( the_same, best3 ) self.xyzout = best3.restr.pdb self.hklout = best3.restr.mtz # ------------------------------------------------------------------------------ class ZnOptions( Printable ) : myname = "zanuda" usage = " \\ \n ".join(( "Usage:\n " + myname, "xyzin .pdb hklin .mtz", "[xyzout .pdb hklout .mtz | output | sgdir ]", "[aver] [notwin] [badd ] [fslim ] [title ]", "[v] [tmpdir <directory>]", "[stdin]" )) def __init__( self ) : self.xyzin = None self.hklin = None self.xyzout = None self.hklout = None self.output = None self.sgdir = None self.aver = False self.notwin = False self.badd = None self.fslim = None self.title = None self.v = False self.tmpdir = None self.stdin = False self.crash = None # For emulation of refmac crashes self.twin = False # YSBL server (not used) self.slow = False # YSBL server (currently used as a footprint) self.mp = False # reserved option self.outdir = None # reserved option # YSBL server: if not self.tmpdir and self.slow : try : self.tmpdir = "/tmp/" + self.myname + "_" + str( os.getpid() ) except : raise ZnError( "working directory" ) self.alias = os.path.abspath( sys.argv[0] ) self.zanuda = os.path.realpath( self.alias ) self.owndir = os.path.realpath( os.path.dirname( self.alias ) ) self._parse_( sys.argv[1:] ) if self.stdin : for line in sys.stdin : words = line.split() if len( words ) > 0 : key = words[0].upper() lk4 = len( key ) >= 4 lw1 = len( words ) == 1 lw2 = len( words ) == 2 if "TITLE".startswith( key ) and lk4 : self.title = " ".join( words[1:] ) + "\n" elif "NOTWIN" == key and lw1 : self.notwin = True elif "AVERAGE".startswith( key ) and lw1 and lk4 : self.aver = True elif "BADD" == key and lw2 : self.badd = words[1] elif "FSLIM".startswith( key ) and lw2 and lk4 : self.fslim = words[1] elif "END" == key and lw1 : break elif len( words ) > 0 : print "WARNING: unrecognised keyword '" + line + "'" output_defined = False if self.output or self.xyzout and self.hklout : output_defined = True self._set_path( "xyzin", old=True, type="file" ) self._set_path( "hklin", old=True, type="file" ) self._set_path( "output", default = self.myname ) self._set_path( "xyzout", default = self.output + ".pdb", type="file" ) self._set_path( "hklout", default = self.output + ".mtz", type="file" ) self._set_path( "tmpdir", default = self.output + "_wrk", type="dir" ) if not output_defined : self.xyzout = None self.hklout = None if( self.sgdir ) : self._set_path( "sgdir", type="dir" ) self._set_real( "badd", 60.0 ) self._set_real( "fslim", 10.0 ) del self.output if self.v : print self sys.stdout.flush() def _set_path( self, attr, type="path", old=False, default=None ) : val = getattr( self, attr ) if not val : val = default if not val : raise ZnError( self.usage ) val = os.path.realpath( val ) if os.path.exists( val ) : if type is "file" : if not os.path.isfile( val ) : raise ZnError( attr + " is not a file" ) elif type is "dir" : if not os.path.isdir( val ) : raise ZnError( attr + " is not a directory" ) else : if old : raise ZnError( attr + " does not exist" ) dir = os.path.dirname( val ) if not os.path.isdir( dir ) : raise ZnError( dir + " does not exist" ) setattr( self, attr, val ) def _set_real( self, attr, default ) : val = getattr( self, attr ) if val : try : val = float( val ) except : raise ZnError( attr + " is not a number" ) else : val = default setattr( self, attr, val ) def _parse_( self, args ) : map = self.__dict__ key = None for word in args : if key : map[ key ] = word key = None else : key = word.lower() if not map.has_key( key ) : raise ZnError( self.usage ) val = map[ key ] if val : raise ZnError( self.usage ) if type( val ) is bool : map[ key ] = True key = None if key : raise ZnError( self.usage ) # ------------------------------------------------------------------------------ def main() : version = "1.09" date = "03 Jun 2015" if len(sys.argv) == 2 and sys.argv[1] == '--version': print version exit(0) status = 0 try : try : max_time = 1800.0 max_size = 300* 1000* 1000 blck_size = 4096 stopf = None opt = ZnOptions() # YSBL server: if opt.slow : stopf = "FINISHED" ZnPrinter.setup( version, date, opt.title, test=opt.v ) Scratch.setup( opt.tmpdir, "z", opt.sgdir, test=opt.v ) Runnable.setup( max_time=max_time, max_size=max_size, blck_size=blck_size, test=opt.v ) Refmac.setup( opt.tmpdir, opt.owndir, test=opt.v ) ZnPath.setup( opt.owndir ) VirtualRun.setup( opt.crash ) # CCP4I will create correct default names if all output files from yet running jobs exist if opt.xyzout and opt.hklout : open( opt.xyzout, "w" ).close() open( opt.hklout, "w" ).close() if opt.sgdir and not ( opt.xyzout and opt.hklout ) : ZnMain.setup_cycles( -1, -1, -1, -1 ) znd = ZnMain( opt.xyzin, opt.hklin, opt.badd, opt.fslim, opt.notwin, opt.aver ) if opt.xyzout and opt.hklout : shutil.copy( znd.xyzout, opt.xyzout ) shutil.copy( znd.hklout, opt.hklout ) except ZnError, e : sys.stdout.write( e.format() ) status = 1 except : sys.stdout.write( ZnError( "fatal error, cannot continue." ).format() ) status = 1 finally : Scratch.clear() # YSBL server: if stopf and not os.path.lexists( stopf ) : os.mkdir( stopf ) sys.exit( status ) # ------------------------------------------------------------------------------ if __name__ == "__main__" : main()