1#A* -------------------------------------------------------------------
2#B* This file contains source code for the PyMOL computer program
3#C* Copyright (c) Schrodinger, LLC.
4#D* -------------------------------------------------------------------
5#E* It is unlawful to modify or remove this copyright notice.
6#F* -------------------------------------------------------------------
7#G* Please see the accompanying LICENSE file for further information.
8#H* -------------------------------------------------------------------
9#I* Additional authors of this source file include:
10#-*
11#-*
12#-*
13#Z* -------------------------------------------------------------------
14
15from __future__ import print_function
16
17import sys
18if sys.version_info[0] == 2:
19    _next_method_name = 'next'
20else:
21    _next_method_name = '__next__'
22
23cmd = __import__("sys").modules["pymol.cmd"]
24import pymol
25from pymol import movie
26# legacy mappings, remove in PyMOL 2.0
27
28mload = movie.load
29mrock = movie.rock
30mroll = movie.roll
31
32# should match the list in layer1/Color.c:
33_color_cycle = [
34    26   , # /* carbon */
35    5    , # /* cyan */
36    154  , # /* lightmagenta */
37    6    , # /* yellow */
38    9    , # /* salmon */
39    29   , # /* hydrogen */
40    11   , # /* slate */
41    13   , # /* orange */
42    10   , # /* lime */
43    5262 , # /* deepteal */
44    12   , # /* hotpink */
45    36   , # /* yelloworange */
46    5271 , # /* violetpurple */
47    124  , # /* grey70 */
48    17   , # /* marine */
49    18   , # /* olive */
50    5270 , # /* smudge */
51    20   , # /* teal */
52    5272 , # /* dirtyviolet */
53    52   , # /* wheat */
54    5258 , # /* deepsalmon */
55    5274 , # /* lightpink */
56    5257 , # /* aquamarine */
57    5256 , # /* paleyellow */
58    15   , # /* limegreen */
59    5277 , # /* skyblue */
60    5279 , # /* warmpink */
61    5276 , # /* limon */
62    53   , # /* violet */
63    5278 , # /* bluewhite */
64    5275 , # /* greencyan */
65    5269 , # /* sand */
66    22   , # /* forest */
67    5266 , # /* lightteal */
68    5280 , # /* darksalmon */
69    5267 , # /* splitpea */
70    5268 , # /* raspberry */
71    104  , # /* grey50 */
72    23   , # /* deepblue */
73    51   , # /* brown */
74    ]
75
76_color_cycle_len = len(_color_cycle)
77
78class _verbose_cmd_proxy:
79    def __init__(self, cmd):
80        self.cmd = cmd
81    def __getattr__(self, name):
82        return getattr(self.cmd, name)
83    def set(self, name, value=1):
84        return self.cmd.set(name, value, quiet=0)
85
86def color_by_area(sele, mode="molecular", state=0, palette='rainbow', _self=cmd):
87    """
88DESCRIPTION
89
90    Colors molecule by surface area
91
92ARGUMENTS
93
94    sele = str: atom selection
95
96    mode = str: "molecular" {default} or "solvent"
97    """
98    asa = 1 if mode=="solvent" else 0
99
100    tmpObj = _self.get_unused_name("_tmp")
101    tmpSel = _self.get_unused_name("_sel")
102    orgSel = _self.get_unused_name("_org")
103
104    orgN = _self.select(orgSel, sele, 0)
105    _self.create(tmpObj, "byobj ?%s & ! solvent" % (orgSel), zoom=0)
106    tmpN = _self.select(tmpSel, '?%s in ?%s' % (tmpObj, orgSel), 0)
107
108    try:
109        if orgN != tmpN:
110            raise pymol.CmdException('color_by_area failed')
111
112        _self.set("dot_solvent", asa, tmpObj)
113        _self.set("dot_density", 3, tmpObj)
114
115        l = []
116        _self.get_area(tmpSel, load_b=1)
117        _self.spectrum("b", palette, tmpSel)
118        _self.iterate(tmpSel, "l_a(color)", space={'l_a': l.append})
119        _self.alter(orgSel, "color=l_n()", space={'l_n': getattr(iter(l), _next_method_name)})
120
121        _self.recolor(orgSel)
122    finally:
123        _self.delete(tmpSel)
124        _self.delete(tmpObj)
125        _self.delete(orgSel)
126
127def find_surface_residues(sele, name='', _self=cmd):
128    """
129DESCRIPTION
130
131    Finds those residues on the surface of a protein
132    that have at least 'surface_residue_cutoff' (setting)
133    exposed A**2 surface area.
134
135    Returns the name of the selection.
136
137ARGUMENTS
138
139    sele = str: the object or selection in which to find exposed residues
140
141    name = str: name of selection to create {default: exposed??}
142    """
143    from collections import defaultdict
144
145    tmpObj = _self.get_unused_name("__tmp")
146    selName = name or _self.get_unused_name("exposed")
147
148    _self.select(selName, sele)
149    _self.create(tmpObj, "(byobj ?%s) & ! solvent" % (selName), zoom=0)
150    _self.select(selName, '?%s in ?%s' % (tmpObj, selName))
151
152    _self.set("dot_solvent", 1, tmpObj);
153    _self.get_area(selName, load_b=1)
154
155    # threshold on what one considers an "exposed" atom (in A**2):
156    surface_residue_cutoff = _self.get_setting_float("surface_residue_cutoff")
157
158    res_area = defaultdict(int)
159    _self.iterate(selName, "res_area[segi, chain, resi] += b", space=locals())
160
161    _self.select(selName, 'none')
162    _self.delete(tmpObj)
163
164    for (k, v) in res_area.items():
165        if v < surface_residue_cutoff:
166            continue
167        _self.select(selName, 'segi %s & chain %s & resi %s' % k, merge=1)
168
169    return selName
170
171
172def find_surface_atoms(sele, name='', cutoff=-1, _self=cmd):
173    """
174DESCRIPTION
175
176    Finds those atoms on the surface of a protein
177    that have at least 'cutoff' (argument) or 'surface_residue_cutoff'
178    (setting) exposed A**2 surface area.
179
180    Returns the name of the selection.
181
182ARGUMENTS
183
184    sele = str: the object or selection in which to find exposed residues
185
186    name = str: name of selection to create {default: exposed??}
187    """
188    tmpObj = _self.get_unused_name("_tmp")
189    tmpSel = _self.get_unused_name("_sel")
190
191    _self.select(tmpSel, sele, 0)
192    _self.create(tmpObj, "(byobj ?%s) & ! solvent" % (tmpSel), zoom=0)
193
194    selName = name or _self.get_unused_name("exposed")
195    _self.select(selName, '?%s in ?%s' % (tmpObj, tmpSel))
196
197    _self.set("dot_solvent", 1, tmpObj);
198    _self.get_area(selName, load_b=1)
199
200    cutoff = float(cutoff)
201    if cutoff < 0.0:
202        cutoff = _self.get_setting_float("surface_residue_cutoff")
203
204    _self.select(selName, '?%s in (?%s and b > %f)' % (tmpSel, selName, cutoff))
205    _self.delete(tmpObj)
206    _self.delete(tmpSel)
207
208    return selName
209
210
211def get_area(sele, state=-1, dot_solvent=0, dot_density=5, quiet=1, _self=cmd):
212    '''
213DESCRIPTION
214
215    Wrapper for cmd.get_area that works on a copy of the selected object
216    to set dot_solvent and dot_density.
217
218SEE ALSO
219
220    get_area command, dot_solvent and dot_density settings
221    '''
222    state, dot_density, quiet = int(state), int(dot_density), int(quiet)
223
224    tmpSel = _self.get_unused_name("_sel")
225    _self.select(tmpSel, sele, 0)
226
227    if state < 1:
228        state = _self.get_selection_state(tmpSel)
229
230    tmpObj = _self.get_unused_name("_tmp")
231    _self.create(tmpObj, "(byobj ?%s) & ! solvent" % (tmpSel), state, zoom=0)
232    _self.select(tmpSel, '?%s in ?%s' % (tmpObj, tmpSel), 0)
233
234    _self.set("dot_solvent", dot_solvent, tmpObj);
235    if dot_density > -1:
236        _self.set('dot_density', dot_density, tmpObj)
237
238    r = _self.get_area(tmpSel, quiet=int(quiet))
239
240    _self.delete(tmpSel)
241    _self.delete(tmpObj)
242
243    return r
244
245
246def get_sasa(sele, state=-1, dot_density=5, quiet=1, _self=cmd):
247    '''
248DESCRIPTION
249
250    Get solvent accesible surface area
251
252SEE ALSO
253
254    get_area command, dot_solvent and dot_density settings
255    '''
256    return get_area(sele, state, 1, dot_density, quiet, _self)
257
258
259def mass_align(target,enabled_only=0,max_gap=50,_self=cmd):
260    cmd=_self
261    list = cmd.get_names("public_objects",int(enabled_only))
262    [x for x in list if cmd.get_type(x)!="object:molecule"]
263    if enabled_only:
264        aln_object = 'aln_enabled_to'+target
265    else:
266        aln_object = 'aln_all_to_'+target
267    cmd.delete(aln_object)
268    for name in list:
269        if name!=target:
270            if cmd.count_atoms("(%s) and (%s)"%(target,name))==0:
271                cmd.align('polymer and name CA and (%s)'%name,
272                'polymer and name CA and (%s)'%target,max_gap=max_gap,quiet=0,
273                          object=aln_object)
274
275def sum_formal_charges(selection="(all)",quiet=1,_self=cmd):
276    _util_sum_fc = [0]
277    _self.iterate(selection, "_util_sum_fc[0] += formal_charge", space=locals())
278    result = _util_sum_fc[0]
279    if not int(quiet):
280        print(" util.sum_formal_charges: %d" % result)
281    return result
282
283def sum_partial_charges(selection="(all)",quiet=1,_self=cmd):
284    _util_sum_pc = [0.0]
285    _self.iterate(selection, "_util_sum_pc[0] += partial_charge", space=locals())
286    result = _util_sum_pc[0]
287    if not int(quiet):
288        print(" util.sum_partial_charges: sum = %0.4f"%result)
289    return result
290
291def compute_mass(selection="(all)",state=-1,implicit=False,quiet=1,_self=cmd):
292    """
293DESCRIPTION
294
295    "compute_mass" calculates the atomic mass of a selection
296    (in atomic mass units).
297
298USAGE
299
300    compute_mass [ selection [, state [, implicit [, quiet ]]]]
301
302ARGUMENTS
303
304   selection = selection, defaults to '(all)'
305
306   state = object state, defaults to current state for each given
307           object. See notes.
308
309   implicit = if false then only calculate masses exactly as
310              in the objects; if true, then add hydrogens were
311	      possible before calculating mass
312
313EXAMPLES
314
315  print util.compute_mass("all")
316
317  m = util.compute_mass("organic",state=4,implicit=True)
318
319NOTES
320
321  If the state argument is specified and an object does not exist
322  in that state, the 0 atoms will be counted for that object,
323  thus resulting in a zero mass for that object.
324
325  """
326    result = 0.0
327    for obj in _self.get_object_list(selection):
328        if state==-1:
329            state = _self.get("state",obj)
330        m = _self.get_model(selection + " and " + obj,state)
331        if len(m.atom)==0:
332            print(" Warning: No atoms in state %d for object %s" % (state,obj))
333        if implicit!=False:
334            result += m.get_implicit_mass()
335        else:
336            result += m.get_mass()
337    if not quiet:
338        print(" util.compute_mass: mass = %0.4f u"%result)
339    return result
340
341def protein_assign_charges_and_radii(obj_name,_self=cmd):
342    cmd=_self
343
344    from chempy.champ import assign
345
346    # apply a few kludges
347
348    # convent Seleno-methionine to methionine
349
350    cmd.alter(obj_name+"///MSE/SE","elem='S';name='SD'",quiet=1)
351    cmd.alter(obj_name+"///MSE/","resn='MET'",quiet=1)
352    cmd.flag("ignore",obj_name,"clear")
353
354    # remove alternate conformers
355
356    cmd.remove(obj_name+" and not alt ''+A")
357    cmd.alter(obj_name,"alt=''")
358    cmd.sort(obj_name)
359    cmd.fix_chemistry(obj_name,obj_name,1)
360
361    # make sure all atoms are included...
362    cmd.alter(obj_name,"q=1.0",quiet=1)
363
364    print(" Util: Fixing termini and assigning formal charges...")
365
366    assign.missing_c_termini(obj_name,quiet=1,_self=_self)
367
368    while not assign.formal_charges(obj_name,quiet=1,_self=_self):
369        print(" WARNING: unrecognized or incomplete residues are being deleted:")
370        cmd.iterate("(byres ("+obj_name+" and flag 23)) and flag 31",
371                        'print("  "+model+"/"+segi+"/"+chain+"/"+resn+"`"+resi+"/")',quiet=1)
372        cmd.remove("byres ("+obj_name+" and flag 23)") # get rid of residues that weren't assigned
373        assign.missing_c_termini(obj_name,quiet=1,_self=_self)
374
375    print(" Util: Assigning Amber 99 charges and radii...")
376
377    cmd.h_add(obj_name)
378    if not assign.amber99(obj_name,quiet=1,_self=_self):
379        print(" WARNING: some unassigned atoms are being deleted:")
380        cmd.iterate("byres ("+obj_name+" and flag 23)",
381                        'print("  "+model+"/"+segi+"/"+chain+"/"+resn+"`"+resi+"/"+name+"? ["+elem+"]")',quiet=1)
382        cmd.remove(obj_name+" and flag 23") # get rid of any atoms that weren't assigned
383
384    # show the user what the net charges are...
385
386    formal = sum_formal_charges(obj_name,quiet=0,_self=_self)
387    partial = sum_partial_charges(obj_name,quiet=0,_self=_self)
388    if round(formal)!=round(partial):
389        print(" WARNING: formal and partial charge sums don't match -- there is a problem!")
390
391def protein_vacuum_esp(selection, mode=2, border=10.0, quiet = 1, _self=cmd):
392    cmd=_self
393
394    if (selection.split() != [selection] or
395         selection not in cmd.get_names('objects')):
396        print(" Error: must provide an object name")
397        raise cmd.QuietException
398    obj_name = selection + "_e_chg"
399    map_name = selection + "_e_map"
400    pot_name = selection + "_e_pot"
401    cmd.disable(selection)
402    cmd.delete(obj_name)
403    cmd.delete(map_name)
404    cmd.delete(pot_name)
405    cmd.create(obj_name,"((polymer and ("+selection+
406               ") and (not resn A+C+T+G+U)) or ((bymol (polymer and ("+
407               selection+"))) and resn NME+NHE+ACE)) and (not hydro)")
408         # try to just get protein...
409
410    protein_assign_charges_and_radii(obj_name,_self=_self)
411
412    ext = cmd.get_extent(obj_name)
413    max_length = max(abs(ext[0][0] - ext[1][0]),abs(ext[0][1] - ext[1][1]),abs(ext[0][2]-ext[1][2])) + 2*border
414
415    # compute an grid with a maximum dimension of 50, with 10 A borders around molecule, and a 1.0 A minimum grid
416
417    sep = max_length/50.0
418    if sep<1.0: sep = 1.0
419    print(" Util: Calculating electrostatic potential...")
420    if mode==0: # absolute, no cutoff
421        cmd.map_new(map_name,"coulomb",sep,obj_name,border)
422    elif mode==1: # neutral, no cutoff
423        cmd.map_new(map_name,"coulomb_neutral",sep,obj_name,border)
424    else: # local, with cutoff
425        cmd.map_new(map_name,"coulomb_local",sep,obj_name,border)
426
427    cmd.ramp_new(pot_name, map_name, selection=obj_name,zero=1)
428    cmd.hide("everything",obj_name)
429    cmd.show("surface",obj_name)
430    cmd.set("surface_color",pot_name,obj_name)
431    cmd.set("surface_ramp_above_mode",1,obj_name)
432
433def color_carbon(color,selection="(all)",_self=cmd):
434    cmd=_self
435    selection = str(selection)
436    cmd.color(color,"(%s) and elem C"%selection)
437
438def cbss(selection="(all)",helix_color="red",sheet_color="yellow",loop_color="green",quiet=1,_self=cmd):
439    cmd=_self
440    sel = str(selection)
441    h = str(helix_color)
442    s = str(sheet_color)
443    l = str(loop_color)
444    cmd.color(h,"(ss H and ("+sel+"))",quiet=quiet)
445    cmd.color(s,"(ss S and ("+sel+"))",quiet=quiet)
446    cmd.color(l,"((not (ss S+H)) and ("+sel+"))",quiet=quiet)
447
448def cbag(selection="(all)",quiet=1,_self=cmd):
449    '''Wrapper around "color atomic"'''
450    cmd=_self
451    s = str(selection)
452    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
453    cmd.color("carbon","(elem C and ("+s+"))",quiet=quiet)
454
455def cbac(selection="(all)",quiet=1,_self=cmd):
456    '''Wrapper around "color atomic"'''
457    cmd=_self
458    s = str(selection)
459    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
460    cmd.color("cyan","(elem C and ("+s+"))",quiet=quiet)
461
462def cbam(selection="(all)",quiet=1,_self=cmd):
463    '''Wrapper around "color atomic"'''
464    cmd=_self
465    s = str(selection)
466    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
467    cmd.color("lightmagenta","(elem C and ("+s+"))",quiet=quiet)
468
469def cbay(selection="(all)",quiet=1,_self=cmd):
470    '''Wrapper around "color atomic"'''
471    cmd=_self
472    s = str(selection)
473    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
474    cmd.color("yellow","(elem C and ("+s+"))",quiet=quiet)
475
476def cbas(selection="(all)",quiet=1,_self=cmd):
477    '''Wrapper around "color atomic"'''
478    cmd=_self
479    s = str(selection)
480    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
481    cmd.color("salmon","(elem C and ("+s+"))",quiet=quiet)
482
483def cbaw(selection="(all)",quiet=1,_self=cmd):
484    '''Wrapper around "color atomic"'''
485    cmd=_self
486    s = str(selection)
487    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
488    cmd.color("hydrogen","(elem C and ("+s+"))",quiet=quiet)
489
490def cbab(selection="(all)",quiet=1,_self=cmd):
491    '''Wrapper around "color atomic"'''
492    cmd=_self
493    s = str(selection)
494    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
495    cmd.color("slate","(elem C and ("+s+"))",quiet=quiet)
496
497def cbao(selection="(all)",quiet=1,_self=cmd):
498    '''Wrapper around "color atomic"'''
499    cmd=_self
500    s = str(selection)
501    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
502    cmd.color("brightorange","(elem C and ("+s+"))",quiet=quiet)
503
504def cbap(selection="(all)",quiet=1,_self=cmd):
505    '''Wrapper around "color atomic"'''
506    cmd=_self
507    s = str(selection)
508    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
509    cmd.color("purple","(elem C and ("+s+"))",quiet=quiet)
510
511def cbak(selection="(all)",quiet=1,_self=cmd):
512    '''Wrapper around "color atomic"'''
513    cmd=_self
514    s = str(selection)
515    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
516    cmd.color("pink","(elem C and ("+s+"))",quiet=quiet)
517
518def cnc(selection="(all)",quiet=1,_self=cmd):
519    '''Wrapper around "color atomic"'''
520    cmd=_self
521    s = str(selection)
522    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
523
524def cba(color,selection="(all)",quiet=1,_self=cmd):
525    '''Wrapper around "color atomic"'''
526    cmd=_self
527    s = str(selection)
528    cmd.color("atomic","(("+s+") and not elem C)",quiet=quiet)
529    cmd.color(color,"(elem C and ("+s+"))",quiet=quiet)
530    cmd.color(color,s,flags=1,quiet=quiet)
531
532def cbh(color,selection="(all)",quiet=1,_self=cmd):
533    '''Wrapper around "color atomic"'''
534    cmd=_self
535    s = str(selection)
536    cmd.color("atomic","(("+s+") and not elem H)",quiet=quiet)
537    cmd.color(color,"(elem H and ("+s+"))",quiet=quiet)
538    cmd.color(color,s,flags=1,quiet=quiet)
539
540def enable_all_shaders(_self=cmd):
541    """
542    Turns on shaders for all representations
543    """
544    cmd=_self
545    cmd.set("use_shaders",1)
546    cmd.set("cartoon_use_shader",1)
547    cmd.set("cgo_use_shader",1)
548    cmd.set("dash_use_shader",1)
549    cmd.set("dot_use_shader",1)
550    cmd.set("line_use_shader",1)
551    cmd.set("mesh_use_shader",1)
552    cmd.set("nb_spheres_use_shader", 1)
553    cmd.set("nonbonded_use_shader",1)
554    cmd.set("ribbon_use_shader", 1)
555    cmd.set("sphere_use_shader", 1)
556    cmd.set("stick_use_shader",1)
557    cmd.set("surface_use_shader",1)
558
559def modernize_rendering(mode,_self=cmd):
560    """
561    Turns on shaders for all representations and
562    updates settings to improve rendering speed
563    and quality.
564    """
565    cmd = _verbose_cmd_proxy(_self)
566
567    cmd.set("max_ups",0)
568
569    enable_all_shaders(cmd)
570
571    cmd.set("stick_ball", 0)
572    cmd.set("stick_as_cylinders", 1)
573    cmd.set("sphere_mode", 9)
574
575    cmd.do("_ rebuild")
576
577def performance(mode,_self=cmd):
578    cmd = _verbose_cmd_proxy(_self)
579    mode = int(mode)
580    if mode==0: # maximum quality
581        cmd.set('line_smooth',1)
582        cmd.set('depth_cue',1)
583        cmd.set('specular',1)
584        cmd.set('surface_quality',1)
585        cmd.set('cartoon_sampling',14)
586        cmd.set('ribbon_sampling',10)
587        cmd.set('transparency_mode',2)
588        # new rendering
589        if cmd.get_setting_int("use_shaders")==1:
590            enable_all_shaders(cmd)
591            # as cylinderss
592            cmd.set("render_as_cylinders", 1)
593            cmd.set("alignment_as_cylinders", 1)
594            cmd.set("cartoon_nucleic_acid_as_cylinders", 1)
595            cmd.set("dash_as_cylinders", 1)
596            cmd.set("line_as_cylinders", 1)
597            cmd.set("mesh_as_cylinders", 1)
598            cmd.set("nonbonded_as_cylinders", 1)
599            cmd.set("ribbon_as_cylinders", 1)
600            cmd.set("stick_as_cylinders", 1)
601            # as spheres
602            cmd.set("dot_as_spheres", 1)
603
604            # special settings
605            # sticks
606            cmd.set("stick_ball", 0)
607            # spheres
608            cmd.set("sphere_mode", 9)
609            # nb_spheres
610            cmd.set("nb_spheres_quality", 3)
611
612        # old rendering
613        if cmd.get_setting_int("use_shaders")==0:
614            cmd.set('stick_quality',15)
615            cmd.set('sphere_quality',2)
616            cmd.set('stick_ball',1)
617    elif mode==33:
618        cmd.set('line_smooth',1)
619        cmd.set('depth_cue',1)
620        cmd.set('specular',1)
621        cmd.set('surface_quality',0)
622        cmd.set('cartoon_sampling',7)
623        cmd.set('ribbon_sampling',1)
624        cmd.set('transparency_mode',2)
625        # new rendering
626        if cmd.get_setting_int("use_shaders")==1:
627            enable_all_shaders(cmd)
628            # as cylinderss
629            cmd.set("render_as_cylinders", 1)
630            cmd.set("alignment_as_cylinders", 1)
631            cmd.set("cartoon_nucleic_acid_as_cylinders", 1)
632            cmd.set("dash_as_cylinders", 1)
633            cmd.set("line_as_cylinders", 1)
634            cmd.set("mesh_as_cylinders", 1)
635            cmd.set("nonbonded_as_cylinders", 1)
636            cmd.set("ribbon_as_cylinders", 1)
637            cmd.set("stick_as_cylinders", 1)
638            # as spheres
639            cmd.set("dot_as_spheres", 1)
640
641            # special settings
642            # sticks
643            cmd.set("stick_ball", 0)
644            # spheres
645            cmd.set("sphere_mode", 9)
646            # nb_spheres
647            cmd.set("nb_spheres_quality", 3)
648
649        # old rendering
650        if cmd.get_setting_int("use_shaders")==0:
651            cmd.set('stick_quality',8)
652            cmd.set('sphere_quality',1)
653            cmd.set('stick_ball',1)
654
655    elif mode==66: # good perfomance
656        cmd.set('line_smooth',0)
657        cmd.set('depth_cue',0)
658        cmd.set('specular',1)
659        cmd.set('surface_quality',0)
660        cmd.set('cartoon_sampling',6)
661        cmd.set('ribbon_sampling',1)
662        cmd.set('transparency_mode',2)
663        # new rendering
664        if cmd.get_setting_int("use_shaders")==1:
665            enable_all_shaders(cmd)
666            # as cylinderss
667            cmd.set("render_as_cylinders", 1)
668            cmd.set("alignment_as_cylinders", 0)
669            cmd.set("cartoon_nucleic_acid_as_cylinders", 0)
670            cmd.set("dash_as_cylinders", 0)
671            cmd.set("line_as_cylinders", 0)
672            cmd.set("mesh_as_cylinders", 0)
673            cmd.set("nonbonded_as_cylinders", 0)
674            cmd.set("ribbon_as_cylinders", 0)
675            cmd.set("stick_as_cylinders", 1)
676            # as spheres
677            cmd.set("dot_as_spheres", 0)
678
679            # special settings
680            # sticks
681            cmd.set("stick_ball", 0)
682            # spheres
683            cmd.set("sphere_mode", 9)
684            # nb_spheres
685            cmd.set("nb_spheres_quality", 3)
686        # old rendering
687        if cmd.get_setting_int("use_shaders")==0:
688            cmd.set('stick_quality',8)
689            cmd.set('sphere_quality',1)
690            cmd.set('stick_ball',0)
691
692    else: # maximum performance
693        cmd.set('line_smooth',0)
694        cmd.set('depth_cue',0)
695        cmd.set('specular',0)
696        cmd.set('surface_quality',-1) # new
697        cmd.set('stick_quality',5)
698        cmd.set('sphere_quality',0)
699        cmd.set('ribbon_sampling',1)
700        cmd.set('cartoon_sampling',3)
701        cmd.set('transparency_mode',0)
702        cmd.set('max_ups',0)
703        # new rendering
704        if cmd.get_setting_int("use_shaders")==1:
705            enable_all_shaders(cmd)
706            # as cylinderss
707            cmd.set("render_as_cylinders", 1)
708            cmd.set("alignment_as_cylinders", 0)
709            cmd.set("cartoon_nucleic_acid_as_cylinders", 0)
710            cmd.set("dash_as_cylinders", 0)
711            cmd.set("line_as_cylinders", 0)
712            cmd.set("mesh_as_cylinders", 0)
713            cmd.set("nonbonded_as_cylinders", 0)
714            cmd.set("ribbon_as_cylinders", 0)
715            cmd.set("stick_as_cylinders", 1)
716            # as spheres
717            cmd.set("dot_as_spheres", 0)
718        # old rendering
719        if cmd.get_setting_int("use_shaders")==0:
720            cmd.set('stick_quality',5)
721            cmd.set('sphere_quality',0)
722            cmd.set('stick_ball',0)
723
724    cmd.do("rebuild")
725
726
727def label_chains(sele="all",_self=cmd):
728    pymol=_self._pymol
729    cmd=_self
730    pymol.stored._cs = []
731    last = None
732    save = ()
733    list = []
734    cmd.iterate(sele,"stored._cs.append((model,chain,index))")
735    for a in pymol.stored._cs:
736        if (a[0:2]!=save):
737            list.append(last)
738            list.append(a)
739            save = a[0:2]
740        last = a
741    if len(list):
742        list.append(last)
743    list = [_f for _f in list if _f]
744    for a in list:
745        if(a[1]==''):
746            cmd.label("%s`%d"%(a[0],a[2]),'''"chain ''"''',quiet=1)
747        elif(a[1]==' '):
748            cmd.label("%s`%d"%(a[0],a[2]),'''"chain ' '"''',quiet=1)
749        else:
750            cmd.label("%s`%d"%(a[0],a[2]),"'chain '+chain",quiet=1)
751
752def label_segments(sele="all",_self=cmd):
753    pymol=_self._pymol
754    cmd=_self
755    pymol.stored._cs = []
756    last = None
757    save = ()
758    list = []
759    cmd.iterate(sele,"stored._cs.append((model,segi,index))")
760    for a in pymol.stored._cs:
761        if (a[0:2]!=save):
762            list.append(last)
763            list.append(a)
764            save = a[0:2]
765        last = a
766    if len(list):
767        list.append(last)
768    list = [_f for _f in list if _f]
769    for a in list:
770        if(a[1]==''):
771            cmd.label("%s`%d"%(a[0],a[2]),'''"segi ''"''',quiet=1)
772        elif(a[1]==' '):
773            cmd.label("%s`%d"%(a[0],a[2]),'''"segi ' '"''',quiet=1)
774        else:
775            cmd.label("%s`%d"%(a[0],a[2]),"'segi '+segi",quiet=1)
776
777def cbc(selection='(all)',first_color=7,quiet=1,legacy=0,_self=cmd):
778    '''
779    Color all chains a different color
780    '''
781    legacy = int(legacy)
782    for c, a in enumerate(_self.get_chains(selection)):
783        if len(a.split()) != 1:
784            a = '"' + a + '"'
785        if legacy:
786            color = c + int(first_color)
787        else:
788            color = _color_cycle[c % _color_cycle_len]
789        if not quiet:
790            print(" util.cbc: color %s, (chain %s)" % (color, a))
791        _self.color(color, "(chain %s and (%s))" % (a, selection), quiet=quiet)
792
793def color_objs(selection='(all)',quiet=1,_self=cmd):
794    cmd=_self
795    '''
796    Color all chains a different color
797    '''
798    c = 0
799    for a in cmd.get_names('public_nongroup_objects',selection=selection):
800        if (selection!='all') and (selection!='(all)'):
801            cmd.color(_color_cycle[c],"(?%s and (%s))"%(a,selection),quiet=quiet)
802        else:
803            cmd.color(_color_cycle[c],"(?%s)"%(a),quiet=quiet)
804        c = (c + 1) % _color_cycle_len
805
806def color_deep(color, name='all', quiet=1, _self=cmd):
807    '''
808    Unset all object and atom level (not global) color settings and
809    apply given color.
810    '''
811    print(' util.color_deep: Deprecated, use cmd.color_deep() instead')
812    _self.color_deep(color, name, quiet)
813
814def chainbow(selection='(all)', palette="rainbow", quiet=1, _self=cmd):
815    '''
816    Color all chains in rainbow
817    '''
818    for model in _self.get_object_list('(' + selection + ')'):
819        for a in _self.get_chains('model %s & (%s)' % (model, selection)) or ['']:
820            _self.spectrum('count', palette,
821                    "(chain '%s' & model %s & (%s))" % (a, model, selection),
822                    byres=1, quiet=quiet)
823
824color_chains = cbc
825
826def ray_shadows(mode,_self=cmd):
827    cmd = _verbose_cmd_proxy(_self)
828    # adjustment factors for new lighting model in 0.99
829    if mode=='none':
830        cmd.set('ray_shadow',0)
831    else:
832        cmd.set('ray_shadow',1)
833    if mode=='light':
834        cmd.set('light_count',2)
835        cmd.set("light","[-0.4,-0.4,-1.0]")
836        cmd.set('ambient',0.14)
837        cmd.set('direct',0.65)
838        cmd.set('reflect',0.25)
839        cmd.set('shininess',40)
840        cmd.set('power',1.0)
841        cmd.set('specular_intensity',0.5)
842        cmd.set('spec_direct',0)
843        cmd.set('spec_count',-1)
844        cmd.set('ray_shadow_decay_factor',0)
845    elif mode=='matte':
846        cmd.set('light_count',4)
847        cmd.set("light","[-0.4,-0.4,-1.0]")
848        cmd.set("light2","[-0.3,-0.4,-1.0]")
849        cmd.set("light3","[-0.3,-0.3,-1.0]")
850        cmd.set("light4","[-0.4,-0.3,-1.0]")
851        cmd.set('ambient',0.14)
852        cmd.set('direct',0.45)
853        cmd.set('reflect',0.45)
854        cmd.set('shininess',25)
855        cmd.set('power',1.25)
856        cmd.set('spec_count',-1)
857        cmd.set('specular_intensity',0.2)
858        cmd.set('spec_direct',0)
859        cmd.set('ray_shadow_decay_factor',0)
860    elif mode=='soft':
861        cmd.set('light_count',10)
862        cmd.set("light","[-0.4,-0.4,-1.0]")
863        cmd.set("light2","[-0.3,-0.4,-1.0]")
864        cmd.set("light3","[-0.3,-0.3,-1.0]")
865        cmd.set("light4","[-0.4,-0.3,-1.0]")
866        cmd.set("light5","[-0.4,-0.5,-1.0]")
867        cmd.set("light6","[-0.5,-0.5,-1.0]")
868        cmd.set("light7","[-0.5,-0.4,-1.0]")
869        cmd.set("light8","[-0.5,-0.3,-1.0]")
870        cmd.set("light9","[-0.3,-0.5,-1.0]")
871        cmd.set('ambient',0.14)
872        cmd.set('direct',0.40)
873        cmd.set('reflect',0.50)
874        cmd.set('specular_intensity',0.5)
875        cmd.set('spec_count',1)
876        cmd.set('shininess',55)
877        cmd.set('power',1.0)
878        cmd.set('spec_direct',0)
879        cmd.set('ray_shadow_decay_factor',0.1)
880        cmd.set('ray_shadow_decay_range',1.8)
881    elif mode=='occlusion':
882        cmd.set('light_count',9)
883        cmd.set("light" ,"[-0.2,-0.2,-1.0]")
884        cmd.set("light2","[-0.2, 0.0,-1.0]")
885        cmd.set("light3","[-0.2, 0.2,-1.0]")
886        cmd.set("light4","[ 0.0, 0.2,-1.0]")
887        cmd.set("light5","[ 0.2, 0.2,-1.0]")
888        cmd.set("light6","[ 0.2, 0.0,-1.0]")
889        cmd.set("light7","[ 0.2,-0.2,-1.0]")
890        cmd.set("light8","[ 0.0,-0.2,-1.0]")
891        cmd.set('ambient',0.18)
892        cmd.set('direct',0.10)
893        cmd.set('reflect',0.80)
894        cmd.set('shininess',10)
895        cmd.set('spec_count',-1)
896        cmd.set('power',1.0)
897        cmd.set('specular_intensity',0)
898        cmd.set('spec_direct',0.25)
899        cmd.set('ray_shadow_decay_factor',0.1)
900        cmd.set('ray_shadow_decay_range',5.0)
901    elif mode=="occlusion2":
902        cmd.set('light_count',2)
903        cmd.set("light","[-0.4,-0.4,-1.0]")
904        cmd.set('ambient',0.14)
905        cmd.set('direct',0.45)
906        cmd.set('reflect',0.45)
907        cmd.set('shininess',55)
908        cmd.set('spec_count',-1)
909        cmd.set('power',1.0)
910        cmd.set('specular_intensity',0.5)
911        cmd.set('spec_direct',0)
912        cmd.set('ray_shadow_decay_factor',0)
913        cmd.set('ambient_occlusion_mode', 1)
914    elif mode=='medium':
915        cmd.set('light_count',2)
916        cmd.set("light","[-0.4,-0.4,-1.0]")
917        cmd.set('ambient',0.14)
918        cmd.set('direct',0.45)
919        cmd.set('reflect',0.45)
920        cmd.set('shininess',55)
921        cmd.set('spec_count',-1)
922        cmd.set('power',1.0)
923        cmd.set('specular_intensity',0.5)
924        cmd.set('spec_direct',0)
925        cmd.set('ray_shadow_decay_factor',0)
926    elif mode=='heavy':
927        cmd.set('light_count',2)
928        cmd.set("light","[-0.4,-0.4,-1.0]")
929        cmd.set('ambient',0.05)
930        cmd.set('direct',0.20)
931        cmd.set('reflect',0.85)
932        cmd.set('spec_count',-1)
933        cmd.set('shininess',90)
934        cmd.set('power',1.0)
935        cmd.set('specular_intensity',0.5)
936        cmd.set('spec_direct',0)
937        cmd.set('ray_shadow_decay_factor',0)
938    elif mode=='black': # best for light backgrounds
939        cmd.set('light_count',2)
940        cmd.set("light","[-0.4,-0.4,-1.0]")
941        cmd.set('ambient',0.001)
942        cmd.set('direct',0.0)
943        cmd.set('reflect',1.1)
944        cmd.set('spec_count',-1)
945        cmd.set('power',1.0)
946        cmd.set('shininess',90)
947        cmd.set('specular_intensity',0.5)
948        cmd.set('spec_direct',0)
949        cmd.set('ray_shadow_decay_factor',0)
950
951def ff_copy(src,dst,_self=cmd):
952    pymol=_self._pymol
953    cmd=_self # NOT THREAD SAFE
954    pymol._rcopy = pymol.Scratch_Storage()
955    pymol._rcopy.pc={}
956    pymol._rcopy.tt={}
957    cmd.iterate("(%s)"%src,"_rcopy.pc[name]=partial_charge")
958    cmd.alter("(%s)"%dst,"partial_charge=_rcopy.pc[name]")
959    cmd.iterate("(%s)"%src,"_rcopy.tt[name]=text_type")
960    cmd.alter("(%s)"%dst,"text_type=_rcopy.tt[name]")
961    del pymol._rcopy
962
963def b2vdw(selection='all', _self=cmd):
964    # use B values to create RMS VDW spheres
965    # rms = sqrt(b/(8*(PI^2)))
966    _self.alter(selection, "vdw=(b/78.9568352087)**0.5")
967
968def phipsi(selection="(pk1)",_self=cmd):
969    cmd=_self # NOT THREAD SAFE
970    n_sele =   "((byres (%s)) & name N)"%selection
971    c_sele =   "((byres (%s)) & name C)"%selection
972    ca_sele =  "((byres (%s)) & name CA)"%selection
973    cm_sele = "((neighbor (%s)) and not (byres (%s)))"%(n_sele,n_sele)
974    np_sele = "((neighbor (%s)) and not (byres (%s)))"%(c_sele,c_sele)
975    cmd.feedback("push")
976    cmd.feedback("disable","selector","everythin")
977    cm_cnt = cmd.select("_pp_cm",cm_sele)
978    n_cnt = cmd.select("_pp_n",n_sele)
979    c_cnt = cmd.select("_pp_c",c_sele)
980    ca_cnt = cmd.select("_pp_ca",ca_sele)
981    np_cnt = cmd.select("_pp_np",np_sele)
982    if(cm_cnt and n_cnt and ca_cnt and c_cnt):
983        phi = cmd.get_dihedral("_pp_c","_pp_ca","_pp_n","_pp_cm")
984    else:
985        phi = None
986    if(n_cnt and ca_cnt and c_cnt and np_cnt):
987        psi = cmd.get_dihedral("_pp_np","_pp_c","_pp_ca","_pp_n")
988    else:
989        psi = None
990    cmd.feedback("pop")
991    cmd.delete("_pp_cm")
992    cmd.delete("_pp_n")
993    cmd.delete("_pp_c")
994    cmd.delete("_pp_ca")
995    cmd.delete("_pp_np")
996    return (phi,psi)
997
998def rainbow(selection="(name CA and alt ''+A)",reverse=0,_self=cmd):
999    '''
1000    Legacy spectrum coloring routine. Don't use.
1001
1002    Use instead: spectrum
1003    '''
1004    print(' util.rainbow: Deprecated, use cmd.spectrum() instead')
1005    list = [
1006        (0,0,255),
1007        (0,0,255),
1008        (0,128,255),
1009        (0,255,255),
1010        (0,255,128),
1011        (0,255,0),
1012        (128,255,0),
1013        (255,255,0),
1014        (255,128,0),
1015        (255,0,0),
1016        (255,0,0)
1017        ]
1018    if reverse:
1019        list.reverse()
1020    list = ['0x%02x%02x%02x' % rgb for rgb in list]
1021    _self.spectrum('count', ' '.join(list), selection)
1022
1023
1024def ss(selection="(name CA and alt '',A)",state=1,_self=cmd):
1025    '''
1026    Legacy secondary structure assignment routine. Don't use.
1027
1028    Use instead: dss
1029    '''
1030    print(' util.ss: Deprecated, use cmd.dss() instead')
1031    _self.dss(selection, state)
1032
1033
1034def colors(scheme="",_self=cmd):
1035    cmd=_self
1036    if scheme=="jmol":
1037        cmd.set("auto_color",0)
1038        cmd.set_color("hydrogen",[1.000,1.000,1.000])
1039        cmd.set_color("carbon",[0.567,0.567,0.567])
1040        cmd.set_color("nitrogen",[0.189,0.315,0.976])
1041        cmd.set_color("oxygen",[1.000,0.051,0.051])
1042        cmd.set_color("fluorine",[0.567,0.882,0.314])
1043        cmd.set_color("sulfur",[1.000,1.000,0.189])
1044        cmd.color("carbon","elem C")
1045        cmd.recolor()
1046
1047
1048def interchain_distances(name, selection, cutoff=None, mode=None, label=0, reset=1, _self=cmd):
1049    '''
1050DESCRIPTION
1051
1052    Find distances between all chains in selection
1053    '''
1054    import itertools
1055
1056    if int(reset):
1057        _self.distance(name, 'none', 'none', 1.0, reset=1)
1058
1059    chains = _self.get_chains(selection)
1060
1061    for c1, c2 in itertools.combinations(chains, 2):
1062        s1 = '(%s) & chain "%s"' % (selection, c1)
1063        s2 = '(%s) & chain "%s"' % (selection, c2)
1064        _self.distance(name, s1, s2, cutoff, mode, label=label)
1065
1066    _self.enable(name)
1067
1068
1069def get_sasa_relative(selection='all', state=1, vis=-1, var='b', quiet=1, outfile='', _self=cmd):
1070    '''
1071DESCRIPTION
1072
1073    Calculates the relative per-residue solvent accessible surface area
1074    and optionally labels and colors residues. The value is relative to
1075    full exposure of the residue, calculated by removing all other
1076    residues except its two next neighbors, if present.
1077
1078    Loads a value beteween 0.0 (fully buried) and 1.0 (fully exposed)
1079    into the b-factor property, available in "iterate", "alter" and
1080    "label" as "b".
1081
1082USAGE
1083
1084    get_sasa_relative [ selection [, state [, vis [, var ]]]]
1085
1086ARGUMENTS
1087
1088    selection = str: atom selection {default: all}
1089
1090    state = int: object state {default: 1}
1091
1092    vis = 0/1: show labels and do color by exposure {default: !quiet}
1093
1094    var = str: name of property to assign {default: b}
1095
1096    quiet = 0/1: print results to log window
1097
1098    outfile = str: filename, write to file instead of log window {default: }
1099
1100EXAMPLE
1101
1102    fetch 1ubq, async=0
1103    get_sasa_relative polymer
1104
1105PYTHON API
1106
1107    cmd.get_sasa_relative(...) -> dict
1108
1109SEE ALSO
1110
1111    get_area with "load_b=1" argument.
1112    '''
1113    import collections
1114
1115    state, vis, quiet = int(state), int(vis), int(quiet)
1116    if vis == -1:
1117        vis = not quiet
1118
1119    sele = _self.get_unused_name('_sele')
1120    tripepname = _self.get_unused_name('_tripep')
1121
1122    _self.select(sele, selection, 0)
1123
1124    dot_solvent = _self.get_setting_boolean('dot_solvent')
1125    _self.set('dot_solvent', 1, updates=0)
1126
1127    try:
1128        for model in _self.get_object_list(sele):
1129            _self.get_area('?%s & ?%s' % (sele, model), state, load_b=1)
1130
1131        resarea = collections.defaultdict(float)
1132        _self.iterate(sele, 'resarea[model,segi,chain,resi] += b', space=locals())
1133
1134        for key in resarea:
1135            _self.create(tripepname, 'byres (/%s/%s/%s/`%s extend 1)' % key, state, 1, zoom=0)
1136            _self.get_area(tripepname, 1, load_b=1)
1137
1138            resarea_exposed = [0.0]
1139            _self.iterate('/' + tripepname + '/%s/%s/`%s' % key[1:],
1140                    'resarea_exposed[0] += b', space=locals())
1141            _self.delete(tripepname)
1142
1143            if resarea_exposed[0] == 0.0:
1144                continue
1145
1146            resarea[key] /= resarea_exposed[0]
1147
1148        _self.alter(sele,
1149                var + ' = resarea[model,segi,chain,resi]', space=locals())
1150
1151        handle = open(outfile, 'w') if outfile else None
1152
1153        def callback(key, area):
1154            w = len(key[0]) + 15
1155            per10 = int(10 * area)
1156            s = ('/%s/%s/%s/%s`%s ' % key).ljust(w)
1157            s += '%3.0f' % (area * 100) + '% '
1158            s += '|' + '=' * per10 + ' ' * (10 - per10) + '|'
1159            print(s, file=handle)
1160
1161        if not quiet or outfile:
1162            _self.iterate('?%s & guide' % sele,
1163                    'callback((model, segi, chain, resn, resi), ' + var + ')',
1164                    space=locals())
1165
1166        if outfile:
1167            handle.close()
1168            print(" Written results to %s" % (outfile))
1169
1170        if vis:
1171            _self.label('?%s & guide' % (sele), '"%.1f" % ' + var)
1172            _self.spectrum(var, 'white blue', sele, minimum=0., maximum=1.)
1173
1174    finally:
1175        _self.set('dot_solvent', dot_solvent, updates=0)
1176        _self.delete(sele)
1177
1178    return resarea
1179
1180
1181def ligand_zoom(step=1, _self=cmd):
1182    '''
1183DESCRIPTION
1184
1185    Zoom to the next organic molecule (by residue identifier)
1186
1187    Bound to CTRL-L key.
1188    '''
1189    global _current_ligand
1190
1191    s = {'ligand_set': set()}
1192    if _self.iterate('organic', 'ligand_set.add((model,segi,chain,resi))',
1193            space=s) < 1:
1194        return
1195
1196    ligands = sorted(s["ligand_set"])
1197
1198    try:
1199        i = ligands.index(_current_ligand)
1200    except (ValueError, NameError):
1201        i = -1
1202
1203    i = (i + int(step)) % len(ligands)
1204    _current_ligand = ligands[i]
1205
1206    # use "do" for feedback
1207    _self.do('zoom /%s/%s/%s & resi %s, animate=1, buffer=2' % ligands[i])
1208