Ejemplo n.º 1
0
        /* Algorithm:
         * 1. Calculate all of the interatomic distances between the proteins in one structure
         * and lable these Dij, Eij for the other
         * 2. Wij = 1 - ((min(Dij, Eij) / Doff)^2) if min(Dij, Eij) < Doff
         * Wij = 0 if min(Dij, Eij) >= Doff
         * 3. Score function:
         * Q = Sum(Wij * exp(-k|Dij - Eij|)) / sum(Wij) (k = 0.5)
         * Q is close to 1 if two structures are similar.
         */
        /// <summary>
        /// weighted Q function
        /// Input: two structures with exactly same sequences
        /// but may exist missing residues
        /// Output: weighted Q score
        /// </summary>
        /// <param name="interChain1"></param>
        /// <param name="interChain2"></param>
        public double WeightQFunc(ChainContact interfaceChain1, ChainContact interfaceChain2)
        {
            // match residue sequence numbers
            // in case there are missing residues in coordinates in a protein
            double weightDistSum = 0.0;
            double weightSum     = 0.0;
            Dictionary <string, AtomPair> atomContactHash1 = interfaceChain1.ChainContactInfo.atomContactHash;
            Dictionary <string, AtomPair> atomContactHash2 = interfaceChain2.ChainContactInfo.atomContactHash;

            foreach (string conKey in atomContactHash1.Keys)
            {
                AtomPair atomPair = (AtomPair)atomContactHash1[conKey];
                double   dist1    = atomPair.distance;

                if (atomContactHash2.ContainsKey(conKey))
                {
                    double dist2 = ((AtomPair)atomContactHash2[conKey]).distance;

                    double weightTemp = Math.Pow((Math.Min(dist1, dist2) / AppSettings.parameters.contactParams.cutoffResidueDist), 2);
                    double weight     = Math.Pow(1 - weightTemp, 2);
                    weightSum     += weight;
                    weightDistSum += weight * Math.Exp(Math.Abs(dist1 - dist2) * -0.5);
                }
            }
            if (weightSum == 0)
            {
                return(-1.0);
            }
            return(weightDistSum / weightSum);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// check the interactions between protein chain and DNA/RNA interactions
        /// </summary>
        /// <param name="pdbId"></param>
        /// <param name="pfamLigandTable"></param>
        private void RetrieveChainDnaRnaInteractionsInAsu(string pdbId, string[] protChainNames, string[] dnaRnaChainNames)
        {
            string gzCoordXmlFile = Path.Combine(ProtCidSettings.dirSettings.coordXmlPath, pdbId + ".xml.gz");

            if (!File.Exists(gzCoordXmlFile))
            {
                ProtCidSettings.progressInfo.progStrQueue.Enqueue(pdbId + ".xml.gz file not exist");
                return;
            }
            string coordXmlFile = ParseHelper.UnZipFile(gzCoordXmlFile, ProtCidSettings.tempDir);
            // read data from crystal xml file
            XmlSerializer xmlSerializer    = new XmlSerializer(typeof(EntryCrystal));
            FileStream    xmlFileStream    = new FileStream(coordXmlFile, FileMode.Open);
            EntryCrystal  thisEntryCrystal = (EntryCrystal)xmlSerializer.Deserialize(xmlFileStream);

            xmlFileStream.Close();
            File.Delete(coordXmlFile);

            // no coordinates for waters
            ChainAtoms[] chains = thisEntryCrystal.atomCat.ChainAtomList;

            foreach (string dnaRnaChain in dnaRnaChainNames)
            {
                AtomInfo[] dnaRnaAtoms = GetChainAtoms(chains, dnaRnaChain);
                foreach (string protChainName in protChainNames)
                {
                    AtomInfo[] protChainAtoms = GetChainAtoms(chains, protChainName);

                    ChainContactInfo contactInfo = atomContact.GetAllChainContactInfo(dnaRnaAtoms, protChainAtoms);
                    if (contactInfo == null)
                    {
                        continue;
                    }
                    foreach (string seqPair in contactInfo.atomContactHash.Keys)
                    {
                        string[] seqIds         = seqPair.Split('_');
                        AtomPair atomPair       = (AtomPair)contactInfo.atomContactHash[seqPair];
                        double   distance       = atomPair.distance;
                        DataRow  chainDnaRnaRow = chainDnaRnaTable.NewRow();
                        chainDnaRnaRow["PdbID"]               = pdbId;
                        chainDnaRnaRow["BuID"]                = "0";
                        chainDnaRnaRow["AsymID"]              = dnaRnaChain;
                        chainDnaRnaRow["SymmetryString"]      = "1_555";
                        chainDnaRnaRow["ChainAsymID"]         = protChainName;
                        chainDnaRnaRow["ChainSymmetryString"] = "1_555";
                        chainDnaRnaRow["SeqID"]               = seqIds[0];
                        chainDnaRnaRow["ChainSeqID"]          = seqIds[1];
                        chainDnaRnaRow["Distance"]            = distance;
                        chainDnaRnaRow["Atom"]                = atomPair.firstAtom.atomName;
                        chainDnaRnaRow["ChainAtom"]           = atomPair.secondAtom.atomName;
                        chainDnaRnaRow["Residue"]             = atomPair.firstAtom.residue;
                        chainDnaRnaRow["ChainResidue"]        = atomPair.secondAtom.residue;
                        chainDnaRnaTable.Rows.Add(chainDnaRnaRow);
                    }
                }
            }
            dbInsert.InsertDataIntoDBtables(ProtCidSettings.buCompConnection, chainDnaRnaTable);
            chainDnaRnaTable.Clear();
        }
Ejemplo n.º 3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="pdbId"></param>
        /// <param name="buId"></param>
        /// <param name="buHash"></param>
        /// <param name="protChains"></param>
        /// <param name="dnaRnaChains"></param>
        private void RetrieveProtDnaRnaInteractions(string pdbId, string buId, Dictionary <string, AtomInfo[]> buHash, string[] protChains, string[] dnaRnaChains)
        {
            string[] dnaRnaChainsWithSymOp = GetChainsWithSymOps(dnaRnaChains, buHash);
            string[] protChainsWithSymOp   = GetChainsWithSymOps(protChains, buHash);


            foreach (string dnaRnaChainSymOp in dnaRnaChainsWithSymOp)
            {
                AtomInfo[] dnaRnaAtoms            = buHash[dnaRnaChainSymOp];
                string[]   dnaRnaChainSymOpFields = GetChainSymOpFields(dnaRnaChainSymOp);
                foreach (string protChainSymOp in protChainsWithSymOp)
                {
                    string[] protChainSymOpFields = GetChainSymOpFields(protChainSymOp);

                    AtomInfo[] protAtoms = (AtomInfo[])buHash[protChainSymOp];

                    ChainContactInfo contactInfo = atomContact.GetAllChainContactInfo(dnaRnaAtoms, protAtoms);
                    if (contactInfo == null)
                    {
                        continue;
                    }
                    foreach (string seqPair in contactInfo.atomContactHash.Keys)
                    {
                        string[] seqIds         = seqPair.Split('_');
                        AtomPair atomPair       = (AtomPair)contactInfo.atomContactHash[seqPair];
                        double   distance       = atomPair.distance;
                        DataRow  chainDnaRnaRow = chainDnaRnaTable.NewRow();
                        chainDnaRnaRow["PdbID"]               = pdbId;
                        chainDnaRnaRow["BuID"]                = buId;
                        chainDnaRnaRow["AsymID"]              = dnaRnaChainSymOpFields[0];
                        chainDnaRnaRow["SymmetryString"]      = dnaRnaChainSymOpFields[1];
                        chainDnaRnaRow["ChainAsymID"]         = protChainSymOpFields[0];
                        chainDnaRnaRow["ChainSymmetryString"] = protChainSymOpFields[1];
                        chainDnaRnaRow["SeqID"]               = seqIds[0];
                        chainDnaRnaRow["ChainSeqID"]          = seqIds[1];
                        chainDnaRnaRow["Distance"]            = distance;
                        chainDnaRnaRow["Atom"]                = atomPair.firstAtom.atomName;
                        chainDnaRnaRow["ChainAtom"]           = atomPair.secondAtom.atomName;
                        chainDnaRnaRow["Residue"]             = atomPair.firstAtom.residue;
                        chainDnaRnaRow["ChainResidue"]        = atomPair.secondAtom.residue;
                        chainDnaRnaTable.Rows.Add(chainDnaRnaRow);
                    }
                }
            }
            dbInsert.InsertDataIntoDBtables(ProtCidSettings.buCompConnection, chainDnaRnaTable);
            chainDnaRnaTable.Clear();
        }
Ejemplo n.º 4
0
        public static string FormatInteractionOutput(string pdbId, List <AtomPair> interactionsList, FormatInternationOutputStyle formatInternationOutputStyle = FormatInternationOutputStyle.DefaultStyle)
        {
            var sb = new StringBuilder();

            sb.AppendLine("List of atom-atom interactions across protein-protein proteinInterface           ");
            sb.AppendLine("---------------------------------------------------------------           ");
            sb.AppendLine("                                                                          ");
            sb.AppendLine("                 PDB code: " + pdbId + "                                           ");
            sb.AppendLine("                 ------------------------------                           ");
            sb.AppendLine("                                                                          ");
            sb.AppendLine("                                                                          ");
            sb.AppendLine("       <----- A T O M   1 ----->       <----- A T O M   2 ----->          ");
            sb.AppendLine("                                                                          ");
            sb.AppendLine("       Atom Atom Res  Res              Atom Atom Res  Res                 ");
            sb.AppendLine("        no. name name no.  Chain        no. name name no.  Chain  Distance");

            for (int interactionIndex = 0; interactionIndex < interactionsList.Count; interactionIndex++)
            {
                AtomPair interactingPair = interactionsList[interactionIndex];


                string line = (interactionIndex + 1).ToString().PadLeft(3) + ". " +
                              interactingPair.Atom1.serial.FieldValue.PadLeft(6) + "  " + interactingPair.Atom1.name.FieldValue.PadRight(4) + interactingPair.Atom1.resName.FieldValue.PadLeft(3) + interactingPair.Atom1.resSeq.FieldValue.PadLeft(5) + "    " + interactingPair.Atom1.chainID.FieldValue +
                              "   <-->" +
                              interactingPair.Atom2.serial.FieldValue.PadLeft(6) + "  " + interactingPair.Atom2.name.FieldValue.PadRight(4) + interactingPair.Atom2.resName.FieldValue.PadLeft(3) + interactingPair.Atom2.resSeq.FieldValue.PadLeft(5) + "    " + interactingPair.Atom2.chainID.FieldValue +
                              Math.Round(interactingPair.Distance, 2).ToString("0.00").PadLeft(10);

                sb.AppendLine(line);
            }

            sb.AppendLine("                                                                          ");
            sb.AppendLine("Number of interactions:          " + interactionsList.Count.ToString().PadLeft(3) + "                                      ");
            sb.AppendLine("                                                                          ");
            sb.AppendLine("                                                                          ");

            return(sb.ToString());
        }
Ejemplo n.º 5
0
        private bool FusionPointInversion(AtomPair pair)
        {
            // not candidates for inversion
            // > 3 bonds
            if (pair.bndAt.Count != 3)
            {
                return(false);
            }
            // we want *!@*@*!@*
            if (!pair.bndAt[0].IsInRing || pair.bndAt[1].IsInRing || pair.bndAt[2].IsInRing)
            {
                return(false);
            }
            // non-terminals
            if (adjList[pair.fst].Length > 1 || adjList[pair.snd].Length > 1)
            {
                return(false);
            }

            IAtom fst = atoms[pair.fst];

            // choose which one to invert, preffering hydrogens
            stackBackup.Clear();
            if (fst.AtomicNumber == 1)
            {
                stackBackup.Push(pair.fst);
            }
            else
            {
                stackBackup.Push(pair.snd);
            }

            Reflect(stackBackup, pair.bndAt[0].Begin, pair.bndAt[0].End);
            congestion.Update(stackBackup.xs, stackBackup.len);
            return(true);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Stretch all bonds in the shortest path between a pair of atoms in an
        /// attempt to resolve the overlap. The stretch that produces the minimum
        /// congestion is stored in the provided stack and coordinates with the congestion
        /// score returned.
        /// </summary>
        /// <param name="pair">congested atom pair</param>
        /// <param name="stack">best result vertices</param>
        /// <param name="coords">best result coordinates</param>
        /// <param name="firstVisit">visit map to avoid repeating work</param>
        /// <returns>congestion score of best result</returns>
        private double Stretch(AtomPair pair, IntStack stack, Vector2[] coords, Dictionary <IBond, AtomPair> firstVisit)
        {
            stackBackup.Clear();

            var score = congestion.Score();
            var min   = score;

            foreach (var bond in pair.bndAt)
            {
                // don't stretch ring bonds
                if (bond.IsInRing)
                {
                    continue;
                }
                if (bfix.Contains(bond))
                {
                    continue;
                }

                // has this bond already been tested as part of another pair
                if (!firstVisit.TryGetValue(bond, out AtomPair first))
                {
                    firstVisit[bond] = first = pair;
                }
                if (first != pair)
                {
                    continue;
                }

                var beg         = bond.Begin;
                var end         = bond.End;
                var begIdx      = idxs[beg];
                var endIdx      = idxs[end];
                var begPriority = beg.GetProperty <int>(AtomPlacer.Priority);
                var endPriority = end.GetProperty <int>(AtomPlacer.Priority);

                Arrays.Fill(visited, false);
                if (begPriority < endPriority)
                {
                    stack.len = Visit(visited, stack.xs, endIdx, begIdx, 0);
                }
                else
                {
                    stack.len = Visit(visited, stack.xs, begIdx, endIdx, 0);
                }

                BackupCoords(backup, stack);
                if (begPriority < endPriority)
                {
                    Stretch(stack, end, beg, pair.attempt * StrechStep);
                }
                else
                {
                    Stretch(stack, beg, end, pair.attempt * StrechStep);
                }

                congestion.Update(visited, stack.xs, stack.len);

                if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold && congestion.Score() < min)
                {
                    BackupCoords(coords, stack);
                    min = congestion.Score();
                    stackBackup.CopyFrom(stack);
                }

                RestoreCoords(stack, backup);
                congestion.Update(visited, stack.xs, stack.len);
                congestion.score = score;
            }

            stack.CopyFrom(stackBackup);

            return(min);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Bend all bonds in the shortest path between a pair of atoms in an attempt
        /// to resolve the overlap. The bend that produces the minimum congestion is
        /// stored in the provided stack and coords with the congestion score
        /// returned.
        /// </summary>
        /// <param name="pair">congested atom pair</param>
        /// <param name="stack">best result vertices</param>
        /// <param name="coords">best result coords</param>
        /// <param name="firstVisit">visit map to avoid repeating work</param>
        /// <returns>congestion score of best result</returns>
        private double Bend(AtomPair pair, IntStack stack, Vector2[] coords, Dictionary <IBond, AtomPair> firstVisit)
        {
            stackBackup.Clear();

            Trace.Assert(stack.len == 0);
            double score = congestion.Score();
            double min   = score;

            // special case: if we have an even length path where the two
            // most central bonds are cyclic but the next two aren't we bend away
            // from each other
            if (pair.bndAt.Count > 4 && (pair.bndAtCode & 0x1F) == 0x6)
            {
                var bndA = pair.bndAt[2];
                var bndB = pair.bndAt[3];

                if (bfix.Contains(bndA) || bfix.Contains(bndB))
                {
                    return(int.MaxValue);
                }

                var pivotA = GetCommon(bndA, pair.bndAt[1]);
                var pivotB = GetCommon(bndB, pair.bndAt[0]);

                if (pivotA == null || pivotB == null)
                {
                    return(int.MaxValue);
                }

                Arrays.Fill(visited, false);
                int split = Visit(visited, stack.xs, idxs[pivotA], idxs[bndA.GetOther(pivotA)], 0);
                stack.len = Visit(visited, stack.xs, idxs[pivotB], idxs[bndB.GetOther(pivotB)], split);

                // perform bend one way
                BackupCoords(backup, stack);
                Bend(stack.xs, 0, split, pivotA, BendStep);
                Bend(stack.xs, split, stack.len, pivotB, -BendStep);

                congestion.Update(stack.xs, stack.len);

                if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold)
                {
                    BackupCoords(coords, stack);
                    stackBackup.CopyFrom(stack);
                    min = congestion.Score();
                }

                // now bend the other way
                RestoreCoords(stack, backup);
                Bend(stack.xs, 0, split, pivotA, -BendStep);
                Bend(stack.xs, split, stack.len, pivotB, BendStep);
                congestion.Update(stack.xs, stack.len);
                if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold && congestion.Score() < min)
                {
                    BackupCoords(coords, stack);
                    stackBackup.CopyFrom(stack);
                    min = congestion.Score();
                }

                // restore original coordinates and reset score
                RestoreCoords(stack, backup);
                congestion.Update(stack.xs, stack.len);
                congestion.score = score;
            }
            // general case: try bending acyclic bonds in the shortest
            // path from inside out
            else
            {
                // try bending all bonds and accept the best one
                foreach (var bond in pair.bndAt)
                {
                    if (bond.IsInRing)
                    {
                        continue;
                    }
                    if (bfix.Contains(bond))
                    {
                        continue;
                    }

                    // has this bond already been tested as part of another pair
                    if (!firstVisit.TryGetValue(bond, out AtomPair first))
                    {
                        firstVisit[bond] = first = pair;
                    }
                    if (first != pair)
                    {
                        continue;
                    }

                    var beg         = bond.Begin;
                    var end         = bond.End;
                    var begPriority = beg.GetProperty <int>(AtomPlacer.Priority);
                    var endPriority = end.GetProperty <int>(AtomPlacer.Priority);

                    Arrays.Fill(visited, false);
                    if (begPriority < endPriority)
                    {
                        stack.len = Visit(visited, stack.xs, idxs[beg], idxs[end], 0);
                    }
                    else
                    {
                        stack.len = Visit(visited, stack.xs, idxs[end], idxs[beg], 0);
                    }

                    BackupCoords(backup, stack);

                    // bend one way
                    if (begPriority < endPriority)
                    {
                        Bend(stack.xs, 0, stack.len, beg, pair.attempt * BendStep);
                    }
                    else
                    {
                        Bend(stack.xs, 0, stack.len, end, pair.attempt * BendStep);
                    }
                    congestion.Update(visited, stack.xs, stack.len);

                    if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold &&
                        congestion.Score() < min)
                    {
                        BackupCoords(coords, stack);
                        stackBackup.CopyFrom(stack);
                        min = congestion.Score();
                    }

                    // bend other way
                    if (begPriority < endPriority)
                    {
                        Bend(stack.xs, 0, stack.len, beg, pair.attempt * -BendStep);
                    }
                    else
                    {
                        Bend(stack.xs, 0, stack.len, end, pair.attempt * -BendStep);
                    }
                    congestion.Update(visited, stack.xs, stack.len);

                    if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold && congestion.Score() < min)
                    {
                        BackupCoords(coords, stack);
                        stackBackup.CopyFrom(stack);
                        min = congestion.Score();
                    }

                    RestoreCoords(stack, backup);
                    congestion.Update(visited, stack.xs, stack.len);
                    congestion.score = score;
                }
            }

            stack.CopyFrom(stackBackup);

            return(min);
        }
Ejemplo n.º 8
0
        // For substituents attached to macrocycles we may be able to point these in/out
        // of the ring
        private bool MacroCycleInversion(AtomPair pair)
        {
            foreach (var v in pair.seqAt)
            {
                IAtom atom = mol.Atoms[v];
                if (!atom.IsInRing || adjList[v].Length == 2)
                {
                    continue;
                }
                if (atom.GetProperty <object>(MacroCycleLayout.MACROCYCLE_ATOM_HINT) == null)
                {
                    continue;
                }
                var acyclic = new List <IBond>(2);
                var cyclic  = new List <IBond>(2);
                foreach (var w in adjList[v])
                {
                    IBond bond = bondMap[v, w];
                    if (bond.IsInRing)
                    {
                        cyclic.Add(bond);
                    }
                    else
                    {
                        acyclic.Add(bond);
                    }
                }
                if (cyclic.Count > 2)
                {
                    continue;
                }

                foreach (var bond in acyclic)
                {
                    if (bfix.Contains(bond))
                    {
                        continue;
                    }
                    Arrays.Fill(visited, false);
                    stackBackup.len = Visit(visited, stackBackup.xs, v, idxs[bond.GetOther(atom)], 0);

                    Vector2 a = atom.Point2D.Value;
                    Vector2 b = bond.GetOther(atom).Point2D.Value;

                    Vector2 perp = new Vector2(b.X - a.X, b.Y - a.Y);
                    perp = Vector2.Normalize(perp);
                    double score = congestion.Score();
                    BackupCoords(backup, stackBackup);

                    Reflect(stackBackup, new Vector2(a.X - perp.Y, a.Y + perp.X), new Vector2(a.X + perp.Y, a.Y - perp.X));
                    congestion.Update(visited, stackBackup.xs, stackBackup.len);

                    if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold)
                    {
                        return(true);
                    }

                    RestoreCoords(stackBackup, backup);
                }
            }
            return(false);
        }
Ejemplo n.º 9
0
        /// <summary>
        ///     This method finds interactions between detected proteinInterfaces.  It is specific to dimers with exactly two chains.  [Chain A
        ///     ProteinInterface Index, Chain B ProteinInterface Index]
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <param name="pdbFilename"></param>
        /// <param name="pdbFileChains"></param>
        /// <param name="chainInteractingAtomLists"></param>
        /// <param name="fullClusteringResult"></param>
        /// <param name="proteinInterfacesClusteringResult"></param>
        /// <param name="detectedFinalStageIndexes"></param>
        /// <param name="pdbIdChainIdList"></param>
        /// <returns></returns>
        public static InteractionBetweenProteinInterfacesListContainer FindInteractionsBetweenAnyProteinInterfaces(
            CancellationToken cancellationToken,
            decimal maxAtomInterationDistance,
            string pdbFilename,
            Dictionary<string, List<string>> pdbIdChainIdList,
            ProteinChainListContainer pdbFileChains,
            ProteinChainListContainer chainInteractingAtomLists,
            ClusteringFullResultListContainer fullClusteringResult,
            ClusteringFullResultListContainer proteinInterfacesClusteringResult,
            int[] detectedFinalStageIndexes)
        {
            if (string.IsNullOrWhiteSpace(pdbFilename))
            {
                throw new ArgumentOutOfRangeException(nameof(pdbFilename));
            }

            if (!File.Exists(pdbFilename))
            {
                throw new FileNotFoundException("File not found", pdbFilename);
            }

            if (ParameterValidation.IsProteinChainListContainerNullOrEmpty(chainInteractingAtomLists))
            {
                throw new ArgumentOutOfRangeException(nameof(chainInteractingAtomLists));
            }

            if (ParameterValidation.IsClusteringFullResultListContainerNullOrEmpty(fullClusteringResult))
            {
                throw new ArgumentOutOfRangeException(nameof(fullClusteringResult));
            }

            if (ParameterValidation.IsClusteringFullResultListContainerNullOrEmpty(proteinInterfacesClusteringResult))
            {
                throw new ArgumentOutOfRangeException(nameof(proteinInterfacesClusteringResult));
            }

            if (ParameterValidation.IsIntArrayNullOrEmpty(detectedFinalStageIndexes))
            {
                throw new ArgumentOutOfRangeException(nameof(detectedFinalStageIndexes));
            }

            string proteinId = ProteinDataBankFileOperations.PdbIdFromPdbFilename(pdbFilename);

            var interactionBetweenProteinInterfacesListContainer = new InteractionBetweenProteinInterfacesListContainer();

            List<AtomPair> interactionList;

            if (pdbFileChains != null && pdbFileChains.ChainList != null && pdbFileChains.ChainList.Count > 0)
            {
                interactionList = SearchInteractions.FindInteractions(cancellationToken, maxAtomInterationDistance, proteinId, pdbIdChainIdList, pdbFileChains); //, false, -1, pdbFileChains);
            }
            else
            {
                interactionList = SearchInteractions.FindInteractions(cancellationToken, maxAtomInterationDistance, pdbFilename, pdbIdChainIdList);
            }

            var interactionInsideProteinInterfaceArray = new bool[interactionList.Count];

            ////////Console.WriteLine("");
            ////////Console.WriteLine("");
            ////////Console.WriteLine("------------------ START ------------------");
            //int c = 0;

            for (int chainIndexA = 0; chainIndexA < proteinInterfacesClusteringResult.ChainList.Count; chainIndexA++)
            {
                for (int chainIndexB = 0; chainIndexB < proteinInterfacesClusteringResult.ChainList.Count; chainIndexB++)
                {
                    if (chainIndexA == chainIndexB || chainIndexB < chainIndexA)
                    {
                        continue;
                    }

                    List<ClusteringFullResultListContainer.Chain.Stage.Cluster> proteinInterfaceListA = proteinInterfacesClusteringResult.ChainList[chainIndexA].StageList[detectedFinalStageIndexes[chainIndexA]].ClusterList;
                    List<ClusteringFullResultListContainer.Chain.Stage.Cluster> proteinInterfaceListB = proteinInterfacesClusteringResult.ChainList[chainIndexB].StageList[detectedFinalStageIndexes[chainIndexB]].ClusterList;

                    int realProteinInterfaceIndexA = -1;

                    for (int proteinInterfaceIndexA = 0; proteinInterfaceIndexA < proteinInterfaceListA.Count; proteinInterfaceIndexA++)
                    {
                        int realProteinInterfaceIndexB = -1;
                        List<int> proteinInterfaceMemberIndexListA = proteinInterfaceListA[proteinInterfaceIndexA].AtomIndexList;
                        List<ATOM_Record> proteinInterfaceAtomListA = proteinInterfaceMemberIndexListA.Select(proteinInterfaceMemberIndexA => chainInteractingAtomLists.ChainList[chainIndexA].AtomList[proteinInterfaceMemberIndexA]).ToList();
                        proteinInterfaceAtomListA = proteinInterfaceAtomListA.OrderBy(a => ProteinDataBankFileOperations.NullableTryParseInt32(a.resSeq.FieldValue)).ToList();
                        if (proteinInterfaceAtomListA.Count > 0)
                        {
                            realProteinInterfaceIndexA++;
                        }
                        else
                        {
                            continue;
                        }

                        for (int proteinInterfaceIndexB = 0; proteinInterfaceIndexB < proteinInterfaceListB.Count; proteinInterfaceIndexB++)
                        {
                            List<int> proteinInterfaceMemberIndexListB = proteinInterfaceListB[proteinInterfaceIndexB].AtomIndexList;
                            List<ATOM_Record> proteinInterfaceAtomListB = proteinInterfaceMemberIndexListB.Select(proteinInterfaceMemberIndexB => chainInteractingAtomLists.ChainList[chainIndexB].AtomList[proteinInterfaceMemberIndexB]).ToList();
                            proteinInterfaceAtomListB = proteinInterfaceAtomListB.OrderBy(b => ProteinDataBankFileOperations.NullableTryParseInt32(b.resSeq.FieldValue)).ToList();
                            if (proteinInterfaceAtomListB.Count > 0)
                            {
                                realProteinInterfaceIndexB++;
                            }
                            else
                            {
                                continue;
                            }

                            for (int proteinInterfaceAtomListIndexA = 0; proteinInterfaceAtomListIndexA < proteinInterfaceAtomListA.Count; proteinInterfaceAtomListIndexA++)
                            {
                                ATOM_Record atomA = proteinInterfaceAtomListA[proteinInterfaceAtomListIndexA];

                                for (int proteinInterfaceAtomListIndexB = 0; proteinInterfaceAtomListIndexB < proteinInterfaceAtomListB.Count; proteinInterfaceAtomListIndexB++)
                                {
                                    ATOM_Record atomB = proteinInterfaceAtomListB[proteinInterfaceAtomListIndexB];

                                    //c++;
                                    ////////Console.WriteLine(c.ToString().PadLeft(5) +
                                    //                  " Chain " + chainIndexA + " (" + proteinInterfaceListA.Count(a => a.AtomIndexList.Count > 0) + " proteinInterfaces) ProteinInterface " + realProteinInterfaceIndexA + " (" + proteinInterfaceAtomListA.Count + " atoms) <--->" +
                                    //                  " Chain " + chainIndexB + " (" + proteinInterfaceListB.Count(a => a.AtomIndexList.Count > 0) + " proteinInterfaces) ProteinInterface " + realProteinInterfaceIndexB + " (" + proteinInterfaceAtomListB.Count + " atoms)  --->" +
                                    //                  " chainID " + atomA.chainID.FieldValue + " resName " + atomA.resName.FieldValue + " resSeq " + atomA.resSeq.FieldValue + " <--->" +
                                    //                  " chainID " + atomB.chainID.FieldValue + " resName " + atomB.resName.FieldValue + " resSeq " + atomB.resSeq.FieldValue);

                                    for (int interactionIndex = 0; interactionIndex < interactionList.Count; interactionIndex++)
                                    {
                                        AtomPair interaction = interactionList[interactionIndex];

                                        if ((interaction.Atom1 == atomA && interaction.Atom2 == atomB) || (interaction.Atom1 == atomB && interaction.Atom2 == atomA))
                                        {
                                            interactionInsideProteinInterfaceArray[interactionIndex] = true;

                                            var interactionBetweenProteinInterfaces = new InteractionBetweenProteinInterfaces();
                                            interactionBetweenProteinInterfacesListContainer.InteractionBetweenProteinInterfacesList.Add(interactionBetweenProteinInterfaces);

                                            interactionBetweenProteinInterfaces.Atom1.Atom = atomA;
                                            interactionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinId = proteinId;
                                            interactionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ChainId = chainIndexA;
                                            interactionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinInterfaceId = realProteinInterfaceIndexA;

                                            interactionBetweenProteinInterfaces.Atom2.Atom = atomB;
                                            interactionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinId = proteinId;
                                            interactionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ChainId = chainIndexB;
                                            interactionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinInterfaceId = realProteinInterfaceIndexB;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for (int interactionIndex = 0; interactionIndex < interactionInsideProteinInterfaceArray.Length; interactionIndex++)
            {
                bool interactionInsideProteinInterface = interactionInsideProteinInterfaceArray[interactionIndex];

                if (!interactionInsideProteinInterface)
                {
                    var interactionBetweenNonProteinInterfaces = new InteractionBetweenProteinInterfaces();
                    interactionBetweenProteinInterfacesListContainer.InteractionBetweenNonProteinInterfacesList.Add(interactionBetweenNonProteinInterfaces);

                    interactionBetweenNonProteinInterfaces.Atom1.Atom = interactionList[interactionIndex].Atom1;
                    interactionBetweenNonProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinId = proteinId;
                    interactionBetweenNonProteinInterfaces.Atom1.FullProteinInterfaceId.ChainId = interactionList[interactionIndex].Atom1FullProteinInterfaceId.ChainId;
                    interactionBetweenNonProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinInterfaceId = -1;

                    interactionBetweenNonProteinInterfaces.Atom2.Atom = interactionList[interactionIndex].Atom2;
                    interactionBetweenNonProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinId = proteinId;
                    interactionBetweenNonProteinInterfaces.Atom2.FullProteinInterfaceId.ChainId = interactionList[interactionIndex].Atom2FullProteinInterfaceId.ChainId;
                    interactionBetweenNonProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinInterfaceId = -1;
                }
            }

            ////////Console.WriteLine("------------------ END ------------------");

            // ensure sorted order
            interactionBetweenProteinInterfacesListContainer.InteractionBetweenProteinInterfacesList = interactionBetweenProteinInterfacesListContainer.InteractionBetweenProteinInterfacesList
                .OrderBy(a => a.Atom1.FullProteinInterfaceId.ChainId)
                .ThenBy(a => a.Atom1.FullProteinInterfaceId.ProteinInterfaceId)
                .ThenBy(a => ProteinDataBankFileOperations.NullableTryParseInt32(a.Atom1.Atom.resSeq.FieldValue))
                .ThenBy(a => a.Atom2.FullProteinInterfaceId.ChainId)
                .ThenBy(a => a.Atom2.FullProteinInterfaceId.ProteinInterfaceId)
                .ThenBy(a => ProteinDataBankFileOperations.NullableTryParseInt32(a.Atom2.Atom.resSeq.FieldValue))
                .ToList();

            interactionBetweenProteinInterfacesListContainer.InteractionBetweenNonProteinInterfacesList = interactionBetweenProteinInterfacesListContainer.InteractionBetweenNonProteinInterfacesList
                .OrderBy(a => a.Atom1.FullProteinInterfaceId.ChainId)
                .ThenBy(a => a.Atom1.FullProteinInterfaceId.ProteinInterfaceId)
                .ThenBy(a => ProteinDataBankFileOperations.NullableTryParseInt32(a.Atom1.Atom.resSeq.FieldValue))
                .ThenBy(a => a.Atom2.FullProteinInterfaceId.ChainId)
                .ThenBy(a => a.Atom2.FullProteinInterfaceId.ProteinInterfaceId)
                .ThenBy(a => ProteinDataBankFileOperations.NullableTryParseInt32(a.Atom2.Atom.resSeq.FieldValue))
                .ToList();

            // remove duplicates (as the list is sorted, duplicates will always be together in the list)
            for (int index = interactionBetweenProteinInterfacesListContainer.InteractionBetweenProteinInterfacesList.Count - 1; index > 0; index--)
            {
                InteractionBetweenProteinInterfaces lastInteractionBetweenProteinInterfaces = interactionBetweenProteinInterfacesListContainer.InteractionBetweenProteinInterfacesList[index - 1];
                InteractionBetweenProteinInterfaces thisInteractionBetweenProteinInterfaces = interactionBetweenProteinInterfacesListContainer.InteractionBetweenProteinInterfacesList[index];

                if (lastInteractionBetweenProteinInterfaces == null || thisInteractionBetweenProteinInterfaces == null)
                {
                    continue;
                }

                if (thisInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinId == lastInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinId &&
                    thisInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ChainId == lastInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ChainId &&
                    thisInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinInterfaceId == lastInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinInterfaceId &&
                    thisInteractionBetweenProteinInterfaces.Atom1.Atom == lastInteractionBetweenProteinInterfaces.Atom1.Atom &&
                    thisInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinId == lastInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinId &&
                    thisInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ChainId == lastInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ChainId &&
                    thisInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinInterfaceId == lastInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinInterfaceId &&
                    thisInteractionBetweenProteinInterfaces.Atom2.Atom == lastInteractionBetweenProteinInterfaces.Atom2.Atom)
                {
                    interactionBetweenProteinInterfacesListContainer.InteractionBetweenProteinInterfacesList.RemoveAt(index - 1);
                    //////Console.WriteLine("removed duplicate");
                }
            }

            for (int index = interactionBetweenProteinInterfacesListContainer.InteractionBetweenNonProteinInterfacesList.Count - 1; index > 0; index--)
            {
                InteractionBetweenProteinInterfaces lastInteractionBetweenProteinInterfaces = interactionBetweenProteinInterfacesListContainer.InteractionBetweenNonProteinInterfacesList[index - 1];
                InteractionBetweenProteinInterfaces thisInteractionBetweenProteinInterfaces = interactionBetweenProteinInterfacesListContainer.InteractionBetweenNonProteinInterfacesList[index];

                if (lastInteractionBetweenProteinInterfaces == null || thisInteractionBetweenProteinInterfaces == null)
                {
                    continue;
                }

                if (thisInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinId == lastInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinId &&
                    thisInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ChainId == lastInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ChainId &&
                    thisInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinInterfaceId == lastInteractionBetweenProteinInterfaces.Atom1.FullProteinInterfaceId.ProteinInterfaceId &&
                    thisInteractionBetweenProteinInterfaces.Atom1.Atom == lastInteractionBetweenProteinInterfaces.Atom1.Atom &&
                    thisInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinId == lastInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinId &&
                    thisInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ChainId == lastInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ChainId &&
                    thisInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinInterfaceId == lastInteractionBetweenProteinInterfaces.Atom2.FullProteinInterfaceId.ProteinInterfaceId &&
                    thisInteractionBetweenProteinInterfaces.Atom2.Atom == lastInteractionBetweenProteinInterfaces.Atom2.Atom)
                {
                    interactionBetweenProteinInterfacesListContainer.InteractionBetweenNonProteinInterfacesList.RemoveAt(index - 1);
                    //////Console.WriteLine("removed duplicate");
                }
            }

            return interactionBetweenProteinInterfacesListContainer;
        }
        public static List <AtomPair> FindInteractions(CancellationToken cancellationToken, decimal maxAtomInterationDistance /*= 8.0m*/, string proteinId, Dictionary <string, List <string> > pdbIdChainIdList, ProteinChainListContainer proteinFileChains, bool breakWhenFirstInteractionFound = false, int totalThreads = -1, bool sort = true, int requiredChains = -1)
        {
            //const decimal maxInterationDistance = 8.0m;
            bool useCache = false;

            if (useCache && !string.IsNullOrWhiteSpace(proteinId))
            {
                var cachedInteractions = InteractionsCache.LoadPdbInteractionCache(proteinId, requiredChains);

                if (cachedInteractions != null)
                {
                    return(cachedInteractions);
                }
            }

            // check required number of chains are found
            if (proteinFileChains == null || proteinFileChains.ChainList == null || (requiredChains > -1 && proteinFileChains.ChainList.Count != requiredChains))
            {
                return(null);
            }

            // check that all chains have atoms
            if (proteinFileChains.ChainList.Any(chain => chain.AtomList == null || chain.AtomList.Count == 0))
            {
                return(null);
            }

            // Make list of 3D positions of atoms.
            var positions = new List <Point3D> [proteinFileChains.ChainList.Count];

            for (int chainIndex = 0; chainIndex < proteinFileChains.ChainList.Count; chainIndex++)
            {
                positions[chainIndex] = Clustering.AtomRecordListToPoint3DList(proteinFileChains.ChainList[chainIndex]);
            }

            var tasks = new List <Task <List <AtomPair> > >();

            for (int chainIndexA = 0; chainIndexA < proteinFileChains.ChainList.Count; chainIndexA++)
            {
                for (int chainIndexB = 0; chainIndexB < proteinFileChains.ChainList.Count; chainIndexB++)
                {
                    if (chainIndexB == chainIndexA || chainIndexB < chainIndexA)
                    {
                        continue;
                    }

                    WorkDivision <List <AtomPair> > workDivision = new WorkDivision <List <AtomPair> >(proteinFileChains.ChainList[chainIndexA].AtomList.Count, totalThreads);

                    bool breakOut     = false;
                    var  lockBreakOut = new object();

                    for (int threadIndex = 0; threadIndex < workDivision.ThreadCount; threadIndex++)
                    {
                        int localThreadIndex = threadIndex;
                        int localChainIndexA = chainIndexA;
                        int localChainIndexB = chainIndexB;
                        WorkDivision <List <AtomPair> > localWorkDivision = workDivision;

                        Task <List <AtomPair> > task = Task.Run(() =>
                        {
                            var taskResult = new List <AtomPair>();

                            for (int atomIndexA = localWorkDivision.ThreadFirstIndex[localThreadIndex]; atomIndexA <= localWorkDivision.ThreadLastIndex[localThreadIndex]; atomIndexA++)
                            {
                                if (breakOut)
                                {
                                    break;
                                }

                                for (int atomIndexB = 0; atomIndexB < proteinFileChains.ChainList[localChainIndexB].AtomList.Count; atomIndexB++)
                                {
                                    if (breakOut || (breakWhenFirstInteractionFound && taskResult.Count > 0))
                                    {
                                        lock (lockBreakOut)
                                        {
                                            breakOut = true;
                                        }

                                        break;
                                    }

                                    if ((!positions[localChainIndexA][atomIndexA].ParseOK) || (!positions[localChainIndexB][atomIndexB].ParseOK))
                                    {
                                        continue;
                                    }

                                    decimal atomicDistanceAngstroms3D = Point3D.Distance3D(positions[localChainIndexA][atomIndexA], positions[localChainIndexB][atomIndexB], true);

                                    // Chemical proteinInterface bonds found at 5 angstrom or less.
                                    if (atomicDistanceAngstroms3D <= 0.0m || atomicDistanceAngstroms3D > maxAtomInterationDistance)
                                    {
                                        continue;
                                    }

                                    var atomPair = new AtomPair(
                                        proteinId,
                                        proteinFileChains.ChainList[localChainIndexA].AtomList[atomIndexA],
                                        localChainIndexA,
                                        proteinId,
                                        localChainIndexB,
                                        proteinFileChains.ChainList[localChainIndexB].AtomList[atomIndexB],
                                        atomicDistanceAngstroms3D);


                                    taskResult.Add(atomPair);
                                }
                            }

                            if (taskResult.Count == 0)
                            {
                                return(null);
                            }

                            return(taskResult);
                        }, cancellationToken);

                        workDivision.TaskList.Add(task);
                    }

                    tasks.AddRange(workDivision.TaskList);
                }
            }


            try
            {
                Task[] tasksToWait = tasks.Where(task => task != null && !task.IsCompleted).ToArray <Task>();
                if (tasksToWait.Length > 0)
                {
                    Task.WaitAll(tasksToWait);
                }
            }
            catch (AggregateException)
            {
            }

            // merge all results

            var atomPairList = new List <AtomPair>();

            foreach (var task in tasks.Where(t => t != null && t.IsCompleted && !t.IsCanceled && !t.IsFaulted && t.Result != null && t.Result.Count > 0))
            {
                atomPairList.AddRange(task.Result);
            }

            if (sort && atomPairList != null && atomPairList.Count > 1)
            {
                atomPairList = atomPairList
                               .OrderBy(i => ProteinDataBankFileOperations.NullableTryParseInt32(i.Atom1.resSeq.FieldValue))
                               .ThenBy(i => ProteinDataBankFileOperations.NullableTryParseInt32(i.Atom1.serial.FieldValue))
                               .ThenBy(j => ProteinDataBankFileOperations.NullableTryParseInt32(j.Atom2.resSeq.FieldValue))
                               .ThenBy(j => ProteinDataBankFileOperations.NullableTryParseInt32(j.Atom2.serial.FieldValue))
                               .ToList();
            }

            if (useCache)
            {
                InteractionsCache.SavePdbInteractionCache(proteinId, atomPairList, requiredChains);
            }

            return(atomPairList);
        }