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
17if True:
18
19        cmd = __import__("sys").modules["pymol.cmd"]
20        from .cmd import _cmd,lock,unlock
21        from . import selector
22        import os
23        import pymol
24
25        from .cmd import _cmd,lock,unlock,Shortcut, \
26            DEFAULT_ERROR, DEFAULT_SUCCESS, _raising, is_ok, is_error
27
28
29        def cealign(target, mobile, target_state=1, mobile_state=1, quiet=1,
30                    guide=1, d0=3.0, d1=4.0, window=8, gap_max=30, transform=1,
31                    object=None, _self=cmd):
32                '''
33DESCRIPTION
34
35    "cealign" aligns two proteins using the CE algorithm.
36
37USAGE
38
39    cealign target, mobile [, target_state [, mobile_state [, quiet [,
40        guide [, d0 [, d1 [, window [, gap_max, [, transform ]]]]]]]]]
41
42NOTES
43
44    If "guide" is set PyMOL will align using only alpha carbons, which is the
45    default behavior. Otherwise, PyMOL will use all atoms. If "quiet" is set
46    to -1, PyMOL will print the rotation matrix as well.
47
48    Reference: Shindyalov IN, Bourne PE (1998) Protein structure alignment by
49    incremental combinatorial extension (CE) of the optimal path.  Protein
50    Engineering 11(9) 739-747.
51
52EXAMPLES
53
54    cealign protA////CA, protB////CA
55
56    # fetch two proteins and align them
57    fetch 1rlw 1rsy, async=0
58    cealign 1rlw, 1rsy
59
60SEE ALSO
61
62    align, pair_fit, fit, rms, rms_cur, intra_rms, intra_rms_cur, super
63                '''
64                quiet = int(quiet)
65                window = int(window)
66                guide = "" if int(guide)==0 else "and guide"
67
68                mobile = "(%s) %s" % (mobile,guide)
69                target = "(%s) %s" % (target,guide)
70
71                # handle PyMOL's macro /// notation
72                mobile = selector.process(mobile)
73                target = selector.process(target)
74
75                # make the lists for holding coordinates and IDs
76                mod1 = _self.get_model(target, state=target_state)
77                mod2 = _self.get_model(mobile, state=mobile_state)
78                sel1 = mod1.get_coord_list()
79                sel2 = mod2.get_coord_list()
80                ids1 = [a.id for a in mod1.atom]
81                ids2 = [a.id for a in mod2.atom]
82
83                if len(sel1) < 2 * window:
84                        print("CEalign-Error: Your target selection is too short.")
85                        raise pymol.CmdException
86                if len(sel2) < 2 * window:
87                        print("CEalign-Error: Your mobile selection is too short.")
88                        raise pymol.CmdException
89                if window < 3:
90                        print("CEalign-Error: window size must be an integer greater than 2.")
91                        raise pymol.CmdException
92                if int(gap_max) < 0:
93                        print("CEalign-Error: gap_max must be a positive integer.")
94                        raise pymol.CmdException
95
96                r = DEFAULT_ERROR
97
98                try:
99                        _self.lock(_self)
100
101                        # call the C function
102                        r = _cmd.cealign( _self._COb, sel1, sel2, float(d0), float(d1), int(window), int(gap_max) )
103
104                        (aliLen, RMSD, rotMat, i1, i2) = r
105                        if quiet==-1:
106                                import pprint
107                                print("RMSD %f over %i residues" % (float(RMSD), int(aliLen)))
108                                print("TTT Matrix:")
109                                pprint.pprint(rotMat)
110                        elif quiet==0:
111                                print("RMSD %f over %i residues" % (float(RMSD), int(aliLen)))
112
113                        if int(transform):
114                            for model in _self.get_object_list("(" + mobile + ")"):
115                                _self.transform_object(model, rotMat, state=0)
116
117                        if object is not None:
118                            obj1 = _self.get_object_list("(" + target + ")")
119                            obj2 = _self.get_object_list("(" + mobile + ")")
120                            if len(obj1) > 1 or len(obj2) > 1:
121                                print(' CEalign-Error: selection spans multiple' + \
122                                        ' objects, cannot create alignment object')
123                                raise pymol.CmdException
124                            tmp1 = _self.get_unused_name('_1')
125                            tmp2 = _self.get_unused_name('_2')
126                            _self.select_list(tmp1, obj1[0], [ids1[j] for i in i1 for j in range(i, i+window)])
127                            _self.select_list(tmp2, obj2[0], [ids2[j] for i in i2 for j in range(i, i+window)])
128                            _self.rms_cur(tmp2, tmp1, cycles=0, matchmaker=4, object=object)
129                            _self.delete(tmp1)
130                            _self.delete(tmp2)
131                except SystemError:
132                    # findBest might return NULL, which raises SystemError
133                    print(" CEalign-Error: alignment failed")
134                finally:
135                        _self.unlock(r,_self)
136                if _self._raising(r,_self): raise pymol.CmdException
137                return ( {"alignment_length": aliLen, "RMSD" : RMSD, "rotation_matrix" : rotMat } )
138
139        def extra_fit(selection='(all)', reference='', method='align', zoom=1,
140                quiet=0, _self=cmd, **kwargs):
141            '''
142DESCRIPTION
143
144    Like "intra_fit", but for multiple objects instead of
145    multiple states.
146
147ARGUMENTS
148
149    selection = string: atom selection of multiple objects {default: all}
150
151    reference = string: reference object name {default: first object in selection}
152
153    method = string: alignment method (command that takes "mobile" and "target"
154    arguments, like "align", "super", "cealign" {default: align}
155
156    ... extra arguments are passed to "method"
157
158SEE ALSO
159
160    align, super, cealign, intra_fit, util.mass_align
161            '''
162            zoom, quiet = int(zoom), int(quiet)
163            sele_name = _self.get_unused_name('_')
164            _self.select(sele_name, selection, 0)
165            models = _self.get_object_list(sele_name)
166
167            if not reference:
168                reference = models[0]
169                models = models[1:]
170            elif reference in models:
171                models.remove(reference)
172            else:
173                _self.select(sele_name, reference, merge=1)
174
175            if _self.is_string(method):
176                if method in _self.keyword:
177                    method = _self.keyword[method][0]
178                else:
179                    raise pymol.CmdException(method, 'Unknown method')
180
181            for model in models:
182                x = method(mobile='?%s & ?%s' % (sele_name, model),
183                        target='?%s & ?%s' % (sele_name, reference), **kwargs)
184                if not quiet:
185                    if _self.is_sequence(x):
186                        print('%-20s RMSD = %8.3f (%d atoms)' % (model, x[0], x[1]))
187                    elif isinstance(x, float):
188                        print('%-20s RMSD = %8.3f' % (model, x))
189                    elif isinstance(x, dict) and 'RMSD' in x:
190                        natoms = x.get('alignment_length', 0)
191                        suffix = (' (%s atoms)' % natoms) if natoms else ''
192                        print('%-20s RMSD = %8.3f' % (model, x['RMSD']) + suffix)
193                    else:
194                        print('%-20s' % (model,))
195
196            if zoom:
197                _self.zoom(sele_name)
198            _self.delete(sele_name)
199
200
201        def alignto(target='', method="cealign", selection='', quiet=1, _self=cmd, **kwargs):
202                """
203DESCRIPTION
204
205        "alignto" aligns all other loaded objects to the target
206        using the specified alignment algorithm.
207
208USAGE
209
210        alignto target [, method [, quiet ]]
211
212NOTES
213
214        Available alignment methods are "align", "super" and "cealign".
215
216EXAMPLE
217
218        # fetch some calmodulins
219        fetch 1cll 1sra 1ggz 1k95, async=0
220
221        # align them to 1cll using cealign
222        alignto 1cll, method=cealign
223        alignto 1cll, object=all_to_1cll
224
225SEE ALSO
226
227        extra_fit, align, super, cealign, fit, rms, rms_cur, intra_fit
228                """
229                if not selection:
230                    names = _self.get_names("public_objects", 1)
231                    if not names:
232                        raise pymol.CmdException('no public objects')
233                    selection = '%' + ' %'.join(names)
234                return extra_fit(selection, target, method, 0, quiet, _self, **kwargs)
235
236
237
238        def super(mobile, target, cutoff=2.0, cycles=5,
239                          gap=-1.5, extend=-0.7, max_gap=50, object=None,
240                          matrix="BLOSUM62", mobile_state=0, target_state=0,
241                          quiet=1, max_skip=0, transform=1, reset=0,
242                          seq=0.0, radius=12.0, scale=17.0, base=0.65,
243                          coord=0.0, expect=6.0, window=3, ante=-1.0,
244                          _self=cmd):
245
246                '''
247DESCRIPTION
248
249        "super" performs a residue-based pairwise alignment followed by a
250        structural superposition, and then carries out zero or more cycles
251        of refinement in order to reject outliers.
252
253USAGE
254
255        super mobile, target [, object=name ]
256
257NOTES
258
259        By adjusting various parameters, the nature of the initial
260        alignment can be modified to include or exclude various factors
261        including sequence similarity, main chain path, secondary &
262        tertiary structure, and current coordinates.
263
264EXAMPLE
265
266        super protA////CA, protB////CA, object=supeAB
267
268SEE ALSO
269
270        align, pair_fit, fit, rms, rms_cur, intra_rms, intra_rms_cur
271        '''
272                r = DEFAULT_ERROR
273                mobile = selector.process(mobile)
274                target = selector.process(target)
275                if object is None: object=''
276                matrix = str(matrix)
277                if matrix.lower() in ['none', '']:
278                        mfile = ''
279                elif os.path.exists(matrix):
280                        mfile = matrix
281                else:
282                        mfile = cmd.exp_path("$PYMOL_DATA/pymol/matrices/"+matrix)
283                # delete existing alignment object (if asked to reset it)
284                try:
285                        _self.lock(_self)
286
287                        r = _cmd.align(_self._COb,mobile,"("+target+")",float(cutoff),
288                                                   int(cycles),float(gap),float(extend),int(max_gap),
289                                                   str(object),str(mfile),
290                                                   int(mobile_state)-1,int(target_state)-1,
291                                                   int(quiet),int(max_skip),int(transform),
292                                                   int(reset),float(seq),
293                                                   float(radius),float(scale),float(base),
294                                                   float(coord),float(expect),int(window),
295                                                   float(ante))
296
297                finally:
298                        _self.unlock(r,_self)
299                if _self._raising(r,_self): raise pymol.CmdException
300                return r
301
302        def align(mobile, target, cutoff=2.0, cycles=5, gap=-10.0,
303                          extend=-0.5, max_gap=50, object=None,
304                          matrix="BLOSUM62", mobile_state=0, target_state=0,
305                          quiet=1, max_skip=0, transform=1, reset=0, _self=cmd):
306
307                '''
308DESCRIPTION
309
310    "align" performs a sequence alignment followed by a structural
311    superposition, and then carries out zero or more cycles of
312    refinement in order to reject structural outliers found during
313    the fit. "align" does a good job on proteins with decent sequence
314    similarity (identity >30%). For comparing proteins with lower
315    sequence identity, the "super" and "cealign" commands perform
316    better.
317
318USAGE
319
320    align mobile, target [, cutoff [, cycles
321        [, gap [, extend [, max_gap [, object
322        [, matrix [, mobile_state [, target_state
323        [, quiet [, max_skip [, transform [, reset ]]]]]]]]]]]]]
324
325ARGUMENTS
326
327    mobile = string: atom selection of mobile object
328
329    target = string: atom selection of target object
330
331    cutoff = float: outlier rejection cutoff in Angstrom {default: 2.0}
332
333    cycles = int: maximum number of outlier rejection cycles {default: 5}
334
335    gap, extend, max_gap: sequence alignment parameters
336
337    object = string: name of alignment object to create {default: (no
338    alignment object)}
339
340    matrix = string: file name of substitution matrix for sequence
341    alignment {default: BLOSUM62}
342
343    mobile_state = int: object state of mobile selection {default: 0 = all states}
344
345    target_state = int: object state of target selection {default: 0 = all states}
346
347    transform = 0/1: do superposition {default: 1}
348
349NOTES
350
351    If object is specified, then align will create an object which
352    indicates paired atoms and supports visualization of the alignment
353    in the sequence viewer.
354
355    The RMSD of the aligned atoms (after outlier rejection!) is reported
356    in the text output. The all-atom RMSD can be obtained by setting
357    cycles=0 and thus not doing any outlier rejection.
358
359EXAMPLE
360
361    align protA////CA, protB////CA, object=alnAB
362
363SEE ALSO
364
365    super, cealign, pair_fit, fit, rms, rms_cur, intra_rms, intra_rms_cur
366                '''
367                r = DEFAULT_ERROR
368                mobile = selector.process(mobile)
369                target = selector.process(target)
370                matrix = str(matrix)
371                if matrix.lower() in ['none', '']:
372                        mfile = ''
373                elif os.path.exists(matrix):
374                        mfile = matrix
375                else:
376                        mfile = cmd.exp_path("$PYMOL_DATA/pymol/matrices/"+matrix)
377                if object is None: object=''
378                # delete existing alignment object (if asked to reset it)
379                try:
380                        _self.lock(_self)
381                        r = _cmd.align(_self._COb,mobile,"("+target+")",
382                                                   float(cutoff),int(cycles),float(gap),
383                                                   float(extend),int(max_gap),str(object),str(mfile),
384                                                   int(mobile_state)-1,int(target_state)-1,
385                                                   int(quiet),int(max_skip),int(transform),int(reset),
386                                                   -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0)
387                finally:
388                        _self.unlock(r,_self)
389                if _self._raising(r,_self): raise pymol.CmdException
390                return r
391
392        def intra_fit(selection, state=1, quiet=1, mix=0, _self=cmd):
393                '''
394DESCRIPTION
395
396        "intra_fit" fits all states of an object to an atom selection
397        in the specified state.  It returns the rms values to python
398        as an array.
399
400USAGE
401
402        intra_fit selection [, state]
403
404ARGUMENTS
405
406        selection = string: atoms to fit
407
408        state = integer: target state
409
410PYMOL API
411
412        cmd.intra_fit( string selection, int state )
413
414EXAMPLES
415
416        intra_fit ( name CA )
417
418PYTHON EXAMPLE
419
420        from pymol import cmd
421        rms = cmd.intra_fit("(name CA)",1)
422
423SEE ALSO
424
425        fit, rms, rms_cur, intra_rms, intra_rms_cur, pair_fit
426                '''
427                # preprocess selection
428                selection = selector.process(selection)
429                #
430                r = DEFAULT_ERROR
431                state = int(state)
432                mix = int(mix)
433                try:
434                        _self.lock(_self)
435                        r = _cmd.intrafit(_self._COb,"("+str(selection)+")",int(state)-1,2,int(quiet),int(mix))
436                finally:
437                        _self.unlock(r,_self)
438                if not isinstance(r, list):
439                        r = DEFAULT_ERROR
440                elif not quiet:
441                        st = 1
442                        for a in r:
443                                if a>=0.0:
444                                        if mix:
445                                                print(" cmd.intra_fit: %5.3f in state %d vs mixed target"%(a,st))
446                                        else:
447                                                print(" cmd.intra_fit: %5.3f in state %d vs state %d"%(a,st,state))
448                                st = st + 1
449                if _self._raising(r,_self): raise pymol.CmdException
450                return r
451
452        def intra_rms(selection, state=0, quiet=1, _self=cmd):
453                '''
454DESCRIPTION
455
456        "intra_rms" calculates rms fit values for all states of an object
457        over an atom selection relative to the indicated state.
458        Coordinates are left unchanged.  The rms values are returned as a
459        python array.
460
461EXAMPLE
462
463        from pymol import cmd
464        rms = cmd.intra_rms("(name CA)",1)
465        print rms
466
467PYMOL API
468
469        cmd.intra_rms(string selection, int state)
470
471SEE ALSO
472
473        fit, rms, rms_cur, intra_fit, intra_rms_cur, pair_fit
474                '''
475                # preprocess selection
476                selection = selector.process(selection)
477                #
478                r = DEFAULT_ERROR
479                state = int(state)
480                try:
481                        _self.lock(_self)
482                        r = _cmd.intrafit(_self._COb,"("+str(selection)+")",int(state)-1,1,int(quiet),int(0))
483                finally:
484                        _self.unlock(r,_self)
485                if not isinstance(r, list):
486                        r = DEFAULT_ERROR
487                elif not quiet:
488                        st = 1
489                        for a in r:
490                                if a>=0.0:
491                                        print(" cmd.intra_rms: %5.3f in state %d vs state %d"%(a,st,state))
492                                st = st + 1
493                if _self._raising(r,_self): raise pymol.CmdException
494                return r
495
496        def intra_rms_cur(selection, state=0, quiet=1, _self=cmd):
497                '''
498DESCRIPTION
499
500        "intra_rms_cur" calculates rms values for all states of an object
501        over an atom selection relative to the indicated state without
502        performing any fitting.  The rms values are returned
503        as a python array.
504
505PYMOL API
506
507        cmd.intra_rms_cur( string selection, int state)
508
509PYTHON EXAMPLE
510
511        from pymol import cmd
512        rms = cmd.intra_rms_cur("(name CA)",1)
513
514SEE ALSO
515
516        fit, rms, rms_cur, intra_fit, intra_rms, pair_fit
517                '''
518                # preprocess selection
519                selection = selector.process(selection)
520                #
521                r = DEFAULT_ERROR
522                state = int(state)
523                try:
524                        _self.lock(_self)
525                        r = _cmd.intrafit(_self._COb,"("+str(selection)+")",int(state)-1,0,int(quiet),int(0))
526                finally:
527                        _self.unlock(r,_self)
528                if not isinstance(r, list):
529                    r = DEFAULT_ERROR
530                elif not quiet:
531                    st = 1
532                    for a in r:
533                        if a>=0.0:
534                            print(" cmd.intra_rms_cur: %5.3f in state %d vs state %d"%(a,st,state))
535                        st = st + 1
536                if _self._raising(r,_self): raise pymol.CmdException
537                return r
538
539        def fit(mobile, target, mobile_state=0, target_state=0,
540		quiet=1, matchmaker=0, cutoff=2.0, cycles=0, object=None, _self=cmd):
541            '''
542DESCRIPTION
543
544    "fit" superimposes the model in the first selection on to the model
545    in the second selection. Only matching atoms in both selections will
546    be used for the fit.
547
548USAGE
549
550    fit mobile, target [, mobile_state [, target_state [, quiet
551        [, matchmaker [, cutoff [, cycles [, object ]]]]]]]
552
553ARGUMENTS
554
555    mobile = string: atom selection
556
557    target = string: atom selection
558
559    mobile_state = integer: object state {default=0, all states)
560
561    target_state = integer: object state {default=0, all states)
562
563    matchmaker = integer: how to match atom pairs {default: 0}
564        -1:  assume that atoms are stored in the identical order
565        0/1: match based on all atom identifiers (segi,chain,resn,resi,name,alt)
566        2:   match based on ID
567        3:   match based on rank
568        4:   match based on index (same as -1 ?)
569
570    cutoff = float: outlier rejection cutoff (only if cycles>0) {default: 2.0}
571
572    cycles = integer: number of cycles in outlier rejection refinement {default: 0}
573
574    object = string: name of alignment object to create {default: None}
575
576EXAMPLES
577
578	fit protA, protB
579
580NOTES
581
582	Since atoms are matched based on all of their identifiers
583	(including segment and chain identifiers), this command is only
584	helpful when comparing very similar structures.
585
586SEE ALSO
587
588	align, super, pair_fit, rms, rms_cur, intra_fit, intra_rms, intra_rms_cur
589            '''
590            r = DEFAULT_ERROR
591            a=str(mobile)
592            b=str(target)
593            # preprocess selections
594            a = selector.process(a)
595            b = selector.process(b)
596            #
597            if object is None: object=''
598            if int(matchmaker)==0:
599                sele1 = "((%s) in (%s))" % (str(a),str(b))
600                sele2 = "((%s) in (%s))" % (str(b),str(a))
601            else:
602                sele1 = str(a)
603                sele2 = str(b)
604            try:
605                _self.lock(_self)
606                r = _cmd.fit(_self._COb,sele1,sele2,2,
607                        int(mobile_state)-1,int(target_state)-1,
608                        int(quiet),int(matchmaker),float(cutoff),
609                        int(cycles),str(object))
610            finally:
611                _self.unlock(r,_self)
612            if r < -0.5:
613                raise pymol.CmdException
614            return r
615
616        def rms(mobile, target, mobile_state=0, target_state=0, quiet=1,
617			  matchmaker=0, cutoff=2.0, cycles=0, object=None, _self=cmd):
618            '''
619DESCRIPTION
620
621	"rms" computes a RMS fit between two atom selections, but does not
622	tranform the models after performing the fit.
623
624USAGE
625
626	rms (selection), (target-selection)
627
628EXAMPLES
629
630	fit ( mutant and name CA ), ( wildtype and name CA )
631
632SEE ALSO
633
634	fit, rms_cur, intra_fit, intra_rms, intra_rms_cur, pair_fit
635            '''
636            r = DEFAULT_ERROR
637            a=str(mobile)
638            b=str(target)
639            # preprocess selections
640            a = selector.process(a)
641            b = selector.process(b)
642            #
643            if object is None: object=''
644            if int(matchmaker)==0:
645                sele1 = "((%s) in (%s))" % (str(a),str(b))
646                sele2 = "((%s) in (%s))" % (str(b),str(a))
647            else:
648                sele1 = str(a)
649                sele2 = str(b)
650            try:
651                _self.lock(_self)
652                r = _cmd.fit(_self._COb,sele1,sele2,1,
653                        int(mobile_state)-1,int(target_state)-1,
654                        int(quiet),int(matchmaker),float(cutoff),
655                        int(cycles),str(object))
656            finally:
657                _self.unlock(r,_self)
658            if r < -0.5:
659                raise pymol.CmdException
660            return r
661
662        def rms_cur(mobile, target, mobile_state=0, target_state=0,
663				quiet=1, matchmaker=0, cutoff=2.0, cycles=0,
664				object=None, _self=cmd):
665
666            '''
667DESCRIPTION
668
669	"rms_cur" computes the RMS difference between two atom
670	selections without performing any fitting.
671
672USAGE
673
674	rms_cur (selection), (selection)
675
676SEE ALSO
677
678	fit, rms, intra_fit, intra_rms, intra_rms_cur, pair_fit
679            '''
680            r = DEFAULT_ERROR
681            a=str(mobile)
682            b=str(target)
683            # preprocess selections
684            a = selector.process(a)
685            b = selector.process(b)
686            #
687            if object is None: object=''
688            if int(matchmaker)==0:
689                sele1 = "((%s) in (%s))" % (str(a),str(b))
690                sele2 = "((%s) in (%s))" % (str(b),str(a))
691            else:
692                sele1 = str(a)
693                sele2 = str(b)
694            try:
695                _self.lock(_self)
696                r = _cmd.fit(_self._COb,sele1,sele2,0,
697                        int(mobile_state)-1,int(target_state)-1,
698                        int(quiet),int(matchmaker),float(cutoff),
699                        int(cycles),str(object))
700            finally:
701                _self.unlock(r,_self)
702            if r < -0.5:
703                raise pymol.CmdException
704            return r
705
706        def pair_fit(*arg, **kw):
707            '''
708DESCRIPTION
709
710	"pair_fit" fits matched sets of atom pairs between two objects.
711
712USAGE
713
714	pair_fit selection, selection, [ selection, selection [ ... ]]
715
716EXAMPLES
717
718	# superimpose protA residues 10-25 and 33-46 to protB residues 22-37 and 41-54:
719
720	pair_fit protA/10-25+33-46/CA, protB/22-37+41-54/CA
721
722	# superimpose ligA atoms C1, C2, and C4 to ligB atoms C8, C4, and C10, respectively:
723
724	pair_fit ligA////C1, ligB////C8, ligA////C2, ligB////C4, ligA////C3, ligB////C10
725
726NOTES
727
728	So long as the atoms are stored in PyMOL with the same order
729	internally, you can provide just two selections.  Otherwise, you
730	may need to specify each pair of atoms separately, two by two, as
731	additional arguments to pair_fit.
732
733	Script files are usually recommended when using this command.
734
735SEE ALSO
736
737	fit, rms, rms_cur, intra_fit, intra_rms, intra_rms_cur
738            '''
739            _self = kw.pop('_self',cmd)
740            quiet = int(kw.pop('quiet', 0))
741
742            if kw:
743                raise pymol.CmdException('unexpected keyword arguments: ' + str(list(kw)))
744
745            r = DEFAULT_ERROR
746            if len(arg) < 2:
747                raise pymol.CmdException('need at least 2 selection')
748            if len(arg) % 2:
749                raise pymol.CmdException('need even number of selections')
750            new_arg = list(map(selector.process, arg))
751            try:
752                _self.lock(_self)
753                r = _cmd.fit_pairs(_self._COb,new_arg, quiet)
754            finally:
755                _self.unlock(r,_self)
756            if r < -0.5:
757                raise pymol.CmdException
758            return r
759