""" python/ui/Crystal.py: CCP4MG Molecular Graphics Program Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009-2010 University of York Copyright (C) 2012 STFC This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, modified in accordance with the provisions of the license to address the requirements of UK law. You should have received a copy of the modified GNU Lesser General Public License along with this library. If not, copies may be downloaded from http://www.ccp4.ac.uk/ccp4license.php This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. """ import os from global_definitions import * import sys,GUI,dataobj #------------------------------------------------------------------ #------------------------------------------------------------------ #------------------------------------------------------------------ class CrystalData(dataobj.DataObj): #------------------------------------------------------------------ #------------------------------------------------------------------ #------------------------------------------------------------------ #----------------------------------------------------------------------- def __init__(self,name='CrystalData',dataparams={},restore_from_version=0,**kw): #----------------------------------------------------------------------- dataobj.DataObj.__init__(self,'CrystalData',name=name,module='Crystal') self.name_label='Crystals' #------------------------------------------------------------------------ def delete(self): #------------------------------------------------------------------------ dataobj.DataObj.delete(self) del self #----------------------------------------------------------------- def add_object(self,**keywords): #----------------------------------------------------------------- return Crystal(parent=self.name,visible=1) #------------------------------------------------------------------ def dataparams(self,all=1): #------------------------------------------------------------------ datapar = {} #for item in ['MolData_status','MapData_status']: # datapar[item]=getattr(self,item) return datapar #------------------------------------------------------------------ def getCrystal(self,source): #------------------------------------------------------------------ # Remove any crystal with the parameters from source for obj in self.objinsts: if obj.source == source: return obj.name return '' #------------------------------------------------------------------ #------------------------------------------------------------------ #------------------------------------------------------------------ class Crystal(dataobj.DispObj): #------------------------------------------------------------------ #------------------------------------------------------------------ #------------------------------------------------------------------ style_menu = ['Symmetry off','Continuous crystal', 'Contents one unit cell','Crystal contacts'] # 'Biological unit','User defined symmetry'] style_alias = ['OFF','CONTINUOUS','UNITCELL','CONTACT'] style_alias_icons = {'OFF':'nosymmetry.svg','CONTINUOUS':'continuoussymmetry.svg','UNITCELL':'unitcellsymmetry.svg','CONTACT':'continuoussymmetry.svg'} # 'BIOLOGICAL','USER'] class_dependents = {} Crystal_initialisation = { 'source': '', 'style' : 'OFF', 'symm_diff_colour' : 1, 'cell_edges': 0, 'atom_symm_radius': 75, 'symmetry_labels': 0, 'unit_cell_shift':[0,0,0] } counter = 0 #-------------------------------------------------------------------- def __init__(self,parent=None,name='',visible=1,source='', style='', params={}, restore_from_version=0, **kw): #-------------------------------------------------------------------- ''' source is name of map/model from which xtl data taken mapname_list/molname_list are lists of names of maps and models which are in the crystal All other data is derived ''' #print 'Crystal.init',params pars = {} pars.update(Crystal.Crystal_initialisation) pars.update(params) self.mode = 0 self.draw_unit_cell = 0 self.draw_contacts = 0 self.source = '' # **** Before restoring ********** Crystal.counter = Crystal.counter+1 if not name: name = 'crystal'+str(Crystal.counter) dataobj.DispObj.__init__(self,'Crystal',name=name,parent=parent,params=pars) #print 'Crystal.init after dataobj.DispObj.__init__' self.cellptr = None self.cell = [] # a,b,c,alpha,beta,gama self.sg = '' # Make sure the source is tagged as being in this xtl if not source: source = params.get('source','') if source: self.set_source(source) #print 'Crystal.init after set_source' # Switch on/off the continuous crystal self.set_style(style=self.style,force=1) #print 'Crystal.init after set_style' # Restored data may have list of models in crystal if getattr(self,'models_in_crystal',[]): for mod in self.models_in_crystal: molobj_list = get_dataobj(name = mod) if molobj_list: molobj_list[0].setMasterCrystal(self.name) del self.models_in_crystal #------------------------------------------------------------------------- def set_source(self,source): #------------------------------------------------------------------------- dataobj_list = get_dataobj(name=source) #print "Crystal.set_source",source,dataobj_list if dataobj_list: dataobj = dataobj_list[0] # Do setup based on initialisation parameters # beware originalSymmetry = [ cell,sg,status] where status=0 if all OK if hasattr(dataobj,'originalSymmetry') and not dataobj.originalSymmetry.get('status',1): self.source = source self.cell = [] self.cell.extend(dataobj.originalSymmetry.get('cell')) import copy self.sg = copy.deepcopy(dataobj.originalSymmetry.get('sg')) #print "Crystal.set_source",self.cell ,self.sg return 0 else: return 1 #------------------------------------------------------------------------- def updateContents(self): #------------------------------------------------------------------------- dataobj_list = get_dataobj(object_type='MolData') for obj in dataobj_list: if obj.masterCrystal == self.name: obj.setMasterCrystal(self.name,force=1) #-------------------------------------------------------------------- def handle_align(self,align_style='',**keywords): #-------------------------------------------------------------------- #print "Crystal.handle_align",align_style import pygl_coord mollist = [] for mol in get_dataobj(object_type='MolData'): if mol.masterCrystal == self.name: mollist.append(mol) for mol in mollist: for obj in mol.objinsts: if obj.graphmod: if align_style == "ab": q = obj.graphmod.obj.GetUnitCellAlignmentRotation("C") elif align_style == "ac": q = obj.graphmod.obj.GetUnitCellAlignmentRotation("B") elif align_style == "bc": q = obj.graphmod.obj.GetUnitCellAlignmentRotation("A") else: q = '' #print "Crystal.handle_align DONT WORK",q if q: MAINWINDOW().glWidgets[0].setQuat(q) # Pre-2.0 code was.. #if q: BUILD().glthread.SetRotation(pygl_coord.QuatPtr(q)) return # Only need to do one orientation .... #----------------------------------------------------------------------- def delete(self): #----------------------------------------------------------------------- for mol in get_dataobj(object_type='MolData'): if mol.masterCrystal == self.name: mol.setMasterCrystal() #print "MolData_status delete", self.parent.MolData_status dataobj.DispObj.delete(self) del self #-------------------------------------------------------------------- def params(self,all=1): #-------------------------------------------------------------------- pars = {} models_in_crystal = [] for mol in get_dataobj(object_type='MolData'): if getattr(mol,'masterCrystal','') == self.name: models_in_crystal.append(mol.name) pars['models_in_crystal'] = models_in_crystal for key in Crystal.Crystal_initialisation.keys(): if all or getattr(self,key,'') != Crystal.Crystal_initialisation[key]: pars[key] = getattr(self,key,'') #print 'Crystal.params',pars return pars #-------------------------------------------------------------------- def update_data_status(self,shadowdisp): #-------------------------------------------------------------------- rv = 0 pars = shadowdisp.params if pars['source'] != self.source: rv = 1 self.source=pars['source'] rv=max(rv, self.set_style(style=pars['style'], symm_diff_colour=pars['symm_diff_colour'], cell_edges=pars['cell_edges'], x_shift=pars['unit_cell_shift'][0], y_shift=pars['unit_cell_shift'][1], z_shift=pars['unit_cell_shift'][2] ) ) models_in_crystal = pars.get('models_in_crystal',[]) for mol in get_dataobj(object_type='MolData'): if models_in_crystal.count(mol.name): if mol.masterCrystal != self.name: mol.setMasterCrystal(self.name) else: if mol.masterCrystal == self.name: mol.setMasterCrystal() rv = max(rv,dataobj.DispObj.update_data_status0(self,shadowdisp)) if rv: return [[self.name,'DispObj','update']] else: return [] #----------------------------------------------------------------------- def set_xtl_params(self,a='',b='',c='', \ alpha='',beta='',gamma='',space_group='',**keywords): #----------------------------------------------------------------------- update = 0 #if source and source != self.source: # self.set_source(source) # update = 1 # Returned from edit_xtl GUI if space_group: self.sg = space_group update = 1 if a and b and c and alpha and beta and gamma: self.cell = [float(a),float(b),float(c),float(alpha),float(beta),float(gamma)] update = 1 else: GUI.insts.WarningMessage('Incomplete crystal data ignored') return if update: for mol in get_dataobj(object_type='MolData'): if mol.masterCrystal == self.name: mol.setMasterCrystal(self.name,force=1) #--------------------------------------------------------------------- def set_style(self,style='',force=0,symm_diff_colour='', cell_edges='', extend_x='',extend_y='',extend_z='', radius='',symmetry_labels='',**keywords): #--------------------------------------------------------------------- ''' Handle input from Crystal style menu ''' # flag if need to update graphics parameters update = 0 #print "style",style if force or (style and style != self.style): self.style = style self.style_label = Crystal.style_menu[Crystal.style_alias.index(self.style)] update = 1 if symmetry_labels !='' and int(symmetry_labels) != self.symmetry_labels: self.symmetry_labels = symmetry_labels update = 1 if radius: self.atom_symm_radius = radius update = 1 if symm_diff_colour !='' and int(symm_diff_colour) != self.symm_diff_colour: self.symm_diff_colour = int(symm_diff_colour) #GUI.insts.graphics_thread.symm_diff_colour = int(symm_diff_colour) update = 1 if cell_edges !='' and int(cell_edges) != self.cell_edges: self.cell_edges = int(cell_edges) update = 1 if extend_x != '' and int(extend_x) != self.unit_cell_shift[0]: self.unit_cell_shift[0] = int(extend_x) update = 1 if extend_y != '' and int(extend_y) != self.unit_cell_shift[1]: self.unit_cell_shift[1] = int(extend_y) update = 1 if extend_z != '' and int(extend_z) != self.unit_cell_shift[2]: self.unit_cell_shift[2] = int(extend_z) update = 1 self.mode = ['CONTINUOUS','UNITCELL','CONTACT'].count(self.style) self.draw_unit_cell = ['UNITCELL'].count(self.style) self.draw_contacts = ['CONTACT'].count(self.style) if update: for obj in get_dispobj(object_type='MolDisp'): obj.updateCrystal() for obj in get_dispobj(object_type='SurfaceDispobj'): obj.updateCrystal() return update def get_style_icon(self): if self.style in Crystal.style_alias_icons: if os.path.exists(os.path.join(os.environ['CCP4MG'],'qticons','disptab','style',Crystal.style_alias_icons[self.style])): return os.path.join(os.environ['CCP4MG'],'qticons','disptab','style',Crystal.style_alias_icons[self.style]) return None #--------------------------------------------------------------------- def get_style_label(self): #--------------------------------------------------------------------- return Crystal.style_menu[Crystal.style_alias.index(self.style)] def get_selection_label(self): lab = "Crystal " + self.source return lab #------------------------------------------------------------------ #------------------------------------------------------------------ #------------------------------------------------------------------ class CrystalData_list(CrystalData): #------------------------------------------------------------------ #------------------------------------------------------------------ #------------------------------------------------------------------ def __init__(self): CrystalData.__init__(self)