Files
2026-08-03 18:42:47 +08:00

191 lines
6.2 KiB
Python

from pymol.wizard import Wizard
from pymol import cmd
import pymol
import traceback
sele_prefix = "_pf_s_"
sele_prefix_len = len(sele_prefix)
dist_prefix = "_pf_d_"
indi_sele = "_indicate_pf"
class Pair_fit(Wizard):
def __init__(self,_self=cmd):
Wizard.__init__(self,_self)
self.memory = 0
self.n_pair = 0
self.status = 0 # 0 no atoms selections, 1 atom selected
self.message = None
self.selection_mode = cmd.get_setting_int("mouse_selection_mode")
cmd.set("mouse_selection_mode",0) # set selection mode to atomic
cmd.deselect() # disable the active selection (if any)
def get_panel(self):
return [
[ 1, 'Pair Fitting',''],
[ 2, 'Fit %d Pairs'%self.n_pair,'cmd.get_wizard().fit()'],
[ 2, 'Delete Last Pair','cmd.get_wizard().remove_last()'],
[ 2, 'Redraw','cmd.get_wizard().update_dashes()'],
[ 2, 'Clear','cmd.get_wizard().clear()'],
[ 2, 'Done','cmd.set_wizard()'],
]
def cleanup(self):
self.clear()
cmd.set("mouse_selection_mode",self.selection_mode) # restore selection mode
def clear(self):
cmd.delete(sele_prefix+"*")
cmd.delete(dist_prefix+"*")
cmd.delete(indi_sele)
lst = cmd.get_names('selections')
self.n_pair = 0
self.status = 0
self.message = None
cmd.unpick()
cmd.refresh_wizard()
def get_prompt(self):
self.prompt = None
if self.status==0:
self.prompt = [ 'Pick the mobile atom...']
elif self.status==1:
self.prompt = [ 'Pick the target atom...' ]
if self.message is not None:
self.prompt.append(self.message)
return self.prompt
def set_status(self,status):
self.status = status
cmd.refresh_wizard()
def get_sele_list(self,mode='all'):
lst = cmd.get_names('selections')
lst = [x for x in lst if x[0:sele_prefix_len]==sele_prefix]
lst.sort()
if mode == 'mobile': # mobile
lst=[x for x in lst if x[-1:]=='b']
elif mode == 'target': # target
lst=[x for x in lst if x[-1:]=='a']
return lst
def fit(self):
# build up the pair-wise list of selections
cmd.delete(dist_prefix+"*")
lst = self.get_sele_list()
c = 0
args = []
while 1:
if not len(lst): break
a = lst.pop()
if not len(lst): break
b = lst.pop()
args.append(a)
args.append(b)
# do the fit
if len(args):
cmd.push_undo(args[0])
dist = cmd.pair_fit(*args)
self.message = "RMS over %d pairs = %5.3f"%(self.n_pair,dist)
cmd.refresh_wizard()
self.update_dashes()
def remove_last(self):
# build up the pair-wise list of selections
cmd.delete(dist_prefix+"*")
lst = self.get_sele_list()
if len(lst):
cmd.delete(lst.pop())
if len(lst):
cmd.delete(lst.pop())
self.n_pair = self.n_pair - 1
self.update_dashes()
self.status=0
cmd.refresh_wizard()
def update_dashes(self):
cmd.delete(dist_prefix+"*")
lst = self.get_sele_list()
c = 0
while 1:
if not len(lst): break
a = lst.pop()
if not len(lst): break
b = lst.pop()
name = dist_prefix+str(c)
cmd.dist(name,a,b,width=7,length=0.05,gap=0.05)
cmd.hide('label',name)
cmd.enable(name)
c = c + 1
def check_same_object(self,lst,sele):
if not len(lst):
return 1
else:
if cmd.count_atoms("((byobj %s) and %s)"%(lst[0],sele),quiet=1):
return 1
return 0
def check_different_object(self,lst,sele):
if not len(lst):
return 1
else:
if not cmd.count_atoms("((byobj %s) and %s)"%(lst[0],sele),quiet=1):
return 1
return 0
def do_select(self,name): # map selects into picks
cmd.unpick()
try:
cmd.edit(name + " and not " + sele_prefix + "*") # note, using new object name wildcards
cmd.delete(name)
self.do_pick(0)
except pymol.CmdException:
traceback.print_exc()
pass
def do_pick(self,bondFlag):
if bondFlag:
self.message = "Error: please select an atom, not a bond."
print(self.message)
else:
if self.status==0:
lst = self.get_sele_list(mode='mobile')
if not self.check_same_object(lst,"(pk1)"):
self.message = "Error: must select an atom in the same object as before."
print(self.message)
else:
name = sele_prefix + "%02db"%self.n_pair # mobile end in 'b'
cmd.select(name,"(pk1)")
cmd.unpick()
cmd.select(indi_sele,name)
cmd.enable(indi_sele)
self.status = 1
self.message = None
elif self.status==1:
lst = self.get_sele_list(mode='target')
if not self.check_same_object(lst,"(pk1)"):
self.message = "Error: must select an atom in the same object as before."
print(self.message)
else:
lst = self.get_sele_list(mode='mobile')
if not self.check_different_object(lst,"(pk1)"):
self.message = "Error: target atom must be in a distinct object."
print(self.message)
else:
name = sele_prefix + "%02da"%self.n_pair # target end in 'a'
cmd.select(name,"(pk1)")
cmd.unpick()
cmd.select(indi_sele,name)
cmd.enable(indi_sele)
self.n_pair = self.n_pair + 1
self.status = 0
self.update_dashes()
cmd.refresh_wizard()