def align_conserved(self, start=0, stop=None):
        """
        Try all possible conserved alignments, or optionally a slice of the
        total possibilities for use with multiprocessing. Does not preserve
        residue order, and not all atoms can be matched so it will typical
        exclude many atoms.

        Note: ignores local_segment.
        """
        # It's inefficient to calculate this separately for each
        # process, but reduces the data that needs to be sent via IPC
        # and this is not a significant portion of the total work for
        # soups of typical size.
        total, it = iter_residues_for_conserved_alignment(self.atoms1, self.atoms2)
        if start > 0 or stop is not None:
            it = itertools.islice(it, start, stop)

        local_best = None
        for res1bytype, res2bytype in it:
            # flatten tuples, they are list of list by type
            res1 = [r for rstype in res1bytype for r in rstype]
            res2 = [r for rstype in res2bytype for r in rstype]
            s = self._rmsd_rot_res(res1, res2)
            if local_best is None or s.score < local_best.score:
                s.strategy = ("conserved", start, stop)
                local_best = s
        if self.best is None or local_best.score < self.best.score:
            self.best = local_best
        return local_best
def _main():
    args = parse_args()

    pdb1_path = _pdbpath(args.pdb1)
    pdb2_path = _pdbpath(args.pdb2)
    download_pdbs(pdb1_path, pdb2_path)

    soup1 = pdbatoms.Soup(pdb1_path)
    soup2 = pdbatoms.Soup(pdb2_path)
    sa = StructuralAlign(soup1, soup2, args.local_segment)
    best_contiguous = sa.align_contiguous()
    best_contiguous.print_multiline()
    if args.random_attempts:
        best_random = sa.align_random(args.random_attempts)
        best_random.print_multiline()
    if args.conserved:
        ncpus = multiprocessing.cpu_count()
        total, it = iter_residues_for_conserved_alignment(sa.atoms1, sa.atoms2)
        per_job = int(math.ceil(float(total) / ncpus))
        jobs = [(sa, start, start + per_job) for start in xrange(0, total, per_job)]
        assert len(jobs) == ncpus
        pool = multiprocessing.Pool(ncpus)
        results = pool.map(_job_align_conserved, jobs)
        best_conserved = None
        for result in results:
            result.print_multiline()
            if best_conserved is None or result.score < best_conserved.score:
                best_conserved = result
        if best_conserved.score < sa.best.score:
            sa.best = best_conserved

    print "======== best =========="
    sa.best.print_multiline()

    if args.pdb1_transform_out:
        soup1x = sa.get_transformed_soup1()
        pdb1_outpath = _pdbpath(args.pdb1_transform_out)
        soup1x.write_pdb(pdb1_outpath)
        if args.png_out:
            pymol_cartoon(pdb1_outpath, pdb2_path, args.png_out)
    elif args.pdb2_transform_out:
        soup2x = sa.get_transformed_soup2()
        pdb2_outpath = _pdbpath(args.pdb2_transform_out)
        soup2x.write_pdb(pdb2_outpath)
        if args.png_out:
            pymol_cartoon(pdb1_path, pdb2_outpath, args.png_out)