Exemplo n.º 1
0
        /// <summary>
        /// Outputs a structure that is a fusion of the chains indicated by the sequence alignments. In the case of a cycle (wherein the last structure
        /// is a copy of the first at a different position), only one set of chains for the two endpoint structures is included.
        /// </summary>
        /// <param name="structures">structures to fuse</param>
        /// <param name="alignments">the sequence positions at which to fuse</param>
        /// <param name="ncDirections">the directionality of the alignment: true -> the first structure is N-terminal, false -> C-terminal</param>
        /// <param name="cycle">whether the structure forms a cycle, in which case the first and last fusions affect both ends</param>
        /// <param name="partialChain">a partial chain has been created due to cyclization whose entirety will be restored only through asu pattering</param>
        /// <returns></returns>
        public static IStructure GetStructure(IStructure[] structures, SequenceAlignment[] alignments, bool[] ncDirections, bool cycle, out IChain partialChain)
        {
            partialChain = null;

            // Note: The fusion product's middle residue from the alignment range comes from the N-terminal chain, i.e the N-term range is [0, Middle] and C-term is [Middle + 1, Len-1]
            Trace.Assert(structures != null && alignments != null && ncDirections != null);
            Trace.Assert(structures.Length > 0);
            Trace.Assert(structures.Length == alignments.Length + 1);
            Trace.Assert(alignments.Length == ncDirections.Length);

            // Data for the cyclization case - the chain that the final fusion should be joined with fused back onto fusion products of the first chain should be tracked so that the last chain can be fused back onto that chain
            IChain cycleDoubleFusedChain = null;                                                                     // Track what chain the first fusion chain ends up in
            bool   isCycleDoubleFused    = cycle && alignments.First().ChainIndex1 == alignments.Last().ChainIndex2; // Whether the first chain is fused both to the next chain and to the last/prior (wrap-around) chain
            Matrix cycleAlignment        = isCycleDoubleFused? Rmsd.GetRmsdTransform(structures.First()[0][0], structures.Last()[0][0]) : Matrix.Identity;


            // Mark which aas to remove without actually removing them, so that their indices remain unchanged while
            // those to be removed are being computed
            Selection remove = new Selection();

            for (int alignmentIndex = 0; alignmentIndex < alignments.Length; alignmentIndex++)
            {
                bool ncDirection              = ncDirections[alignmentIndex];
                SequenceAlignment alignment   = alignments[alignmentIndex];
                SequenceAlignment ncAlignment = ncDirection? alignment : SequenceAlignment.Reversed(alignment); // N as chain1
                IStructure        structureN  = ncDirection ? structures[alignmentIndex] : structures[alignmentIndex + 1];
                IStructure        structureC  = ncDirection ? structures[alignmentIndex + 1] : structures[alignmentIndex];
                IChain            chainN      = structureN[ncAlignment.ChainIndex1];
                IChain            chainC      = structureC[ncAlignment.ChainIndex2];
                remove.Aas.UnionWith(chainN[ncAlignment.Range1.Middle + 1, chainN.Count - 1]);
                remove.Aas.UnionWith(chainC[0, ncAlignment.Range2.Middle]);

                // If a cycle exists, then for each chain in the first and last structure (which are identical, modulo a transform), only one copy should be
                // preserved. If that copy is fused on both sides, then it must be trimmed according to both the first and final sequence alignments. In such a
                // case, remove the entire last structure.
                // Cycle and fusion is to the same chain on both sides:
                // -> remove all of the second copy
                // -> transform the second copy neighbor chain onto the first
                // Cycle and fusion is to separate chains on either side:
                // -> remove all of the second copy except for the fused chain
                // -> remove from the first copy the chain that was fused on the second copy
                if (cycle && alignmentIndex == alignments.Length - 1)
                {
                    if (isCycleDoubleFused)
                    {
                        // Mark all chains from second copy for deletion
                        foreach (IChain chain in structures[structures.Length - 1])
                        {
                            remove.Aas.UnionWith(chain);
                        }

                        // Mark the first structure residues for deletion on one side of the fusion point
                        IChain chain0 = structures[0][alignment.ChainIndex2];
                        if (ncDirection)
                        {
                            remove.Aas.UnionWith(chain0[0, alignment.Range2.Middle]);
                        }
                        else
                        {
                            remove.Aas.UnionWith(chain0[alignment.Range2.Middle + 1, chain0.Count - 1]);
                        }
                    }
                    else
                    {
                        // Mark all chains from the second copy for deletion, except the one being fused
                        IChain keep = structures[alignmentIndex + 1][alignment.ChainIndex2];
                        foreach (IChain chain in structures[alignmentIndex + 1])
                        {
                            if (chain != keep)
                            {
                                remove.Aas.UnionWith(chain);
                            }
                        }

                        // For the one being fused, remove that index from the first structure
                        remove.Aas.UnionWith(structures[0][alignment.ChainIndex2]);
                    }
                }
            }

            // Remove them
            for (int alignmentIndex = 0; alignmentIndex < alignments.Length; alignmentIndex++)
            {
                SequenceAlignment alignment  = alignments[alignmentIndex];
                IStructure        structure1 = structures[alignmentIndex];
                IStructure        structure2 = structures[alignmentIndex + 1];
                IChain            chain1     = structure1[alignment.ChainIndex1];
                IChain            chain2     = structure2[alignment.ChainIndex2];

                for (int i = chain1.Count - 1; i >= 0; i--)
                {
                    IAa aa = chain1[i];
                    if (remove.Aas.Contains(aa))
                    {
                        Matrix desired = aa.TotalTransform;
                        chain1.RemoveAt(i);
                        aa.Transform(desired * Matrix.Invert(aa.TotalTransform));
#if DEBUG_TRANSFORMS
                        Debug.Assert((desired - aa.TotalTransform).Translation.Length() < 0.1);
#endif
                    }
                }

                for (int i = chain2.Count - 1; i >= 0; i--)
                {
                    IAa aa = chain2[i];
                    if (remove.Aas.Contains(aa))
                    {
                        Matrix desired = aa.TotalTransform;
                        chain2.RemoveAt(i);
                        aa.Transform(desired * Matrix.Invert(aa.TotalTransform));
#if DEBUG_TRANSFORMS
                        Debug.Assert((desired - aa.TotalTransform).Translation.Length() < 0.1);
#endif
                    }
                }

                if (cycle && alignmentIndex == 0)
                {
                    foreach (IChain chain in structure1)
                    {
                        for (int i = chain.Count - 1; i >= 0; i--)
                        {
                            IAa aa = chain[i];
                            if (remove.Aas.Contains(aa))
                            {
                                Matrix desired = aa.TotalTransform;
                                chain.RemoveAt(i);
                                aa.Transform(desired * Matrix.Invert(aa.TotalTransform));
#if DEBUG_TRANSFORMS
                                Debug.Assert((desired - aa.TotalTransform).Translation.Length() < 0.1);
#endif
                            }
                        }
                    }
                }

                if (cycle && alignmentIndex == alignments.Length - 1)
                {
                    foreach (IChain chain in structure2)
                    {
                        for (int i = chain.Count - 1; i >= 0; i--)
                        {
                            IAa aa = chain[i];
                            if (remove.Aas.Contains(aa))
                            {
                                Matrix desired = aa.TotalTransform;
                                chain.RemoveAt(i);
                                aa.Transform(desired * Matrix.Invert(aa.TotalTransform));
#if DEBUG_TRANSFORMS
                                Debug.Assert((desired - aa.TotalTransform).Translation.Length() < 0.1);
#endif
                            }
                        }
                    }
                }
            }

            // Join the chains and allocate the result to the second structure so as to preserve the indexes for the next fusion step
            for (int alignmentIndex = 0; alignmentIndex < alignments.Length; alignmentIndex++)
            {
                bool ncDirection             = ncDirections[alignmentIndex];
                SequenceAlignment alignment  = alignments[alignmentIndex];
                IStructure        structure1 = structures[alignmentIndex];
                IStructure        structure2 = structures[alignmentIndex + 1];
                IChain            chain1     = structure1[alignment.ChainIndex1];
                IChain            chain2     = structure2[alignment.ChainIndex2];

                if (ncDirection)
                {
#if DEBUG_MIRRORS
                    foreach (IAa aa2 in chain2.ToArray())
                    {
                        chain1.AddInPlace(aa2);
                    }
#else
                    chain1.AddArraySourceInPlace(chain2);
#endif
                    structure2[alignment.ChainIndex2, true] = chain1;
                }
                else
                {
#if DEBUG_MIRRORS
                    foreach (IAa aa1 in chain1.ToArray())
                    {
                        chain2.AddInPlace(aa1);
                    }
#else
                    chain2.AddArraySourceInPlace(chain1);
#endif
                }

                // Track which chain contains the first chain in the cycle so that the final chain in the cycle can fuse to it
                if (isCycleDoubleFused && (alignmentIndex == 0 || chain1 == cycleDoubleFusedChain || chain2 == cycleDoubleFusedChain))
                {
                    cycleDoubleFusedChain = ncDirection? chain1 : chain2;
                }

                if (isCycleDoubleFused && alignmentIndex == alignments.Length - 1)
                {
                    // If it's a cycle on the same chain, move the chain back to where it fuses to the first structure
                    IChain combined = ncDirection ? chain1 : chain2;
                    combined.Transform(cycleAlignment);

                    if (combined == cycleDoubleFusedChain)
                    {
                        // If the structure[0] fusion chain has been fused all the way through, there is no need to move the
                        // current chain to meet the first, since they're already joined
                        partialChain = cycleDoubleFusedChain;
                    }
                    else
                    {
                        if (ncDirection)
                        {
                            combined.AddArraySourceInPlace(cycleDoubleFusedChain);
                            IStructure cycleDoubleFusedParent = (IStructure)cycleDoubleFusedChain.Parent;
                        }
                        else
                        {
                            cycleDoubleFusedChain.AddArraySourceInPlace(combined);
                        }
                    }
                }
            }

            // Add all unique chains to a new structure
            Structure total = new Structure();
            structures.SelectMany(s => s).Distinct().Where(c => c.Count > 0).ToList().ForEach(c => total.AddInPlace(c));
            return(total);
        }