Changeset 8d9c38 for src


Ignore:
Timestamp:
May 7, 2008, 2:46:33 PM (17 years ago)
Author:
Frederik Heber <heber@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
Children:
fe5589
Parents:
6d35e4
Message:

rewritten CyclicStructureAnalysis(): uses DFS spanning tree and limited BFS from all back edges

The DFS tree is given via a StackClass and from each BackEdge a BFS is started to find the leftatom from rightatom but not by taking BackEdge itself. Hence, it finds the smallest circle and returns it.
Also, it limits itself by constantly redefining MinimumRingSize as the minimum of this and the current RingSize.
Tested to good results on buckyball. And may easily be enhanced to scanning and returning all rings (but so far we only need the minimum ring size).

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/molecules.cpp

    r6d35e4 r8d9c38  
    15721572
    15731573  // analysis of the cycles (print rings, get minimum cycle length)
    1574   CyclicStructureAnalysis(out, MinimumRingSize);
     1574  CyclicStructureAnalysis(out, BackEdgeStack, MinimumRingSize);
    15751575
    15761576  *out << Verbose(1) << "Final graph info for each atom is:" << endl;
     
    16061606/** Analyses the cycles found and returns minimum of all cycle lengths.
    16071607 * \param *out output stream for debugging
    1608  * \param MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found
     1608 * \param *BackEdgeStack stack with all back edges found during DFS scan
     1609 * \param MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
    16091610 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
    16101611 */
    1611 void molecule::CyclicStructureAnalysis(ofstream *out, int &MinimumRingSize)
    1612 {
    1613   class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
    1614   int LP;
    1615   atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Runner = NULL;
    1616   bond *Binder = NULL;
     1612void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> *  BackEdgeStack, int &MinimumRingSize)
     1613{
     1614  atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList");
     1615  int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList");
     1616  enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CyclicStructureAnalysis: *ColorList");
     1617  class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount);   // will hold the current ring
     1618  class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount);   // contains all "touched" atoms
     1619  atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL;
     1620  bond *Binder = NULL, *BackEdge = NULL;
    16171621  int RingSize, NumCycles;
    16181622
    1619   // count number of cyclic bonds per atom and push all with 3 cyclic bonds onto stack
    1620   AtomStack->ClearStack();
    1621   int *NoCyclicBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CyclicStructureAnalysis: *NoCyclicBondsPerAtom");
    1622   Walker = start;
    1623   while (Walker->next != end) {
    1624     Walker = Walker->next;
    1625     NoCyclicBondsPerAtom[Walker->nr] = 0;
    1626     // check whether it's connected to cyclic bonds and count per atom
    1627     // 0 means not part of a cycle, 2 means in a cycle, 3 or more means interconnection site of cycles
    1628     for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
    1629       Binder = ListOfBondsPerAtom[Walker->nr][i];
    1630       NoCyclicBondsPerAtom[Walker->nr] += (int) Binder->Cyclic;
    1631       if (NoCyclicBondsPerAtom[Walker->nr] == 3)  //push all intersections
    1632         AtomStack->Push(Walker);
    1633     }
    1634   }
    1635   *out << Verbose(1) << "NoCyclicBondsPerAtom: ";
    1636   for(int i=0;i<AtomCount;i++) {
    1637     *out << NoCyclicBondsPerAtom[i] << " ";
    1638   }
    1639   *out << endl;
     1623  // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
     1624  for (int i=0;i<AtomCount;i++) {
     1625    PredecessorList[i] = NULL;
     1626    ShortestPathList[i] = -1;
     1627    ColorList[i] = white;
     1628  }
     1629 
     1630  *out << Verbose(1) << "Back edge list - ";
     1631  BackEdgeStack->Output(out);
     1632 
    16401633  *out << Verbose(1) << "Analysing cycles ... " << endl;
    1641   MinimumRingSize = -1;
     1634  if ((MinimumRingSize <= 2) || (MinimumRingSize > AtomCount))
     1635    MinimumRingSize = AtomCount;
    16421636  NumCycles = 0;
    1643   while (!AtomStack->IsEmpty()) {
    1644     Walker = AtomStack->PopFirst();
    1645     if (NoCyclicBondsPerAtom[Walker->nr] > 1) {
    1646       NoCyclicBondsPerAtom[Walker->nr]--; // remove one for being intersection
    1647       RingSize = 0;
    1648       *out << Verbose(2) << "Current intersection is " << *Walker << ", expect to find " << NoCyclicBondsPerAtom[Walker->nr] << " cycles." << endl;
     1637  while (!BackEdgeStack->IsEmpty()) {
     1638    BackEdge = BackEdgeStack->PopFirst();
     1639    // this is the target
     1640    Root = BackEdge->leftatom; 
     1641    // this is the source point
     1642    Walker = BackEdge->rightatom;
     1643    ShortestPathList[Walker->nr] = 0;
     1644    BFSStack->ClearStack();  // start with empty BFS stack
     1645    BFSStack->Push(Walker);
     1646    TouchedStack->Push(Walker);
     1647    //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
     1648    OtherAtom = NULL;
     1649    while ((Walker != Root) && ((OtherAtom == NULL) || (ShortestPathList[OtherAtom->nr] < MinimumRingSize))) {  // look for Root
     1650      Walker = BFSStack->PopFirst();
     1651      //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
    16491652      for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
    16501653        Binder = ListOfBondsPerAtom[Walker->nr][i];
    1651         OtherAtom = Binder->GetOtherAtom(Walker);
    1652         // note down the LowPoint number of this cycle
    1653         if (NoCyclicBondsPerAtom[OtherAtom->nr] > 1) {
    1654           LP = OtherAtom->LowpointNr;
    1655           NoCyclicBondsPerAtom[Walker->nr]--; // walker is start of cycle
    1656           if (LP != Walker->LowpointNr)
    1657             *out << Verbose(2) << "Tributary cycle: ... <-> " << Walker->Name;
    1658           else
    1659             *out << Verbose(2) << "Main cycle: ... <-> " << Walker->Name;
    1660           Root = Walker;  // root acts as predecessor marker so that we don't step back accidentally
    1661           RingSize = 1;
    1662           do {
    1663             for(int j=0;j<NumberOfBondsPerAtom[OtherAtom->nr];j++) {  // search among its bonds for next in cycle (same lowpoint nr)
    1664               Runner = ListOfBondsPerAtom[OtherAtom->nr][j]->GetOtherAtom(OtherAtom);
    1665               if (((Runner->LowpointNr == LP) || (Runner->LowpointNr == Walker->LowpointNr)) && (Runner != Root)) {
    1666                 // first check is to stay in the cycle
    1667                 // middle check is allow for getting back into main cycle briefly from tributary cycle (just one step, then while further down stops)
    1668                 // last check is not step back
    1669                 *out << " <-> " << OtherAtom->Name;
    1670                 NoCyclicBondsPerAtom[OtherAtom->nr]--;
    1671                 Root = OtherAtom;
    1672                 OtherAtom = Runner;
    1673                 NoCyclicBondsPerAtom[Root->nr]--;
    1674                 RingSize++;
    1675                 break;
    1676               }
     1654        if (Binder != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
     1655          OtherAtom = Binder->GetOtherAtom(Walker);
     1656          //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
     1657          if (ColorList[OtherAtom->nr] == white) {
     1658            TouchedStack->Push(OtherAtom);
     1659            ColorList[OtherAtom->nr] = lightgray;
     1660            PredecessorList[OtherAtom->nr] = Walker;  // Walker is the predecessor
     1661            ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
     1662            //*out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
     1663            if (ShortestPathList[OtherAtom->nr] < MinimumRingSize) { // Check for maximum distance
     1664              //*out << Verbose(3) << "Putting OtherAtom into queue." << endl;
     1665              BFSStack->Push(OtherAtom);
    16771666            }
    1678           } while ((OtherAtom->LowpointNr == LP) && (Walker != OtherAtom) && (Root->LowpointNr == OtherAtom->LowpointNr));
    1679           // now check if the LP is different from Walker's, as then there is one more bond to follow
    1680           if (LP != Walker->LowpointNr) {
    1681             // find last bond to home base
    1682             for(int j=0;j<NumberOfBondsPerAtom[OtherAtom->nr];j++)
    1683               if (ListOfBondsPerAtom[OtherAtom->nr][j]->GetOtherAtom(OtherAtom) == Root) {
    1684                 *out << " <-> " << OtherAtom->Name;
    1685                 RingSize++;
    1686                 NoCyclicBondsPerAtom[OtherAtom->nr]--;
    1687               }
    16881667          } else {
    1689             // we have made the complete cycle
     1668            //*out << Verbose(3) << "Not Adding, has already been visited." << endl;
    16901669          }
    1691           *out << " <-> ... with cycle length of " << RingSize << "." << endl;
    1692           NumCycles++;
    1693           if ((RingSize < MinimumRingSize) || (MinimumRingSize == -1))
    1694             MinimumRingSize = RingSize;
     1670        } else {
     1671          //*out << Verbose(3) << "Not Visiting, is a back edge." << endl;
    16951672        }
    16961673      }
    1697     }
    1698   }
    1699 
    1700   // print NoCyclicBondsPerAtom to visually check of all are zero
    1701   *out << Verbose(1) << "NoCyclicBondsPerAtom: ";
    1702   for(int i=0;i<AtomCount;i++) {
    1703     if (NoCyclicBondsPerAtom[i] > 0)
    1704       cerr << "There was an error in  molecule::CyclicStructureAnalysis!" << endl;
    1705     *out << NoCyclicBondsPerAtom[i] << " ";
    1706   }
    1707   *out << endl;
     1674      ColorList[Walker->nr] = black;
     1675      //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
     1676    }
     1677   
     1678    if (Walker == Root) {
     1679      // now climb back the predecessor list and thus find the cycle members
     1680      NumCycles++;
     1681      RingSize = 1;
     1682      Walker = Root;
     1683      *out << Verbose(1) << "Found ring contains: ";
     1684      while (Walker != BackEdge->rightatom) {
     1685        *out << Walker->Name << " <-> ";
     1686        Walker = PredecessorList[Walker->nr];
     1687        RingSize++;
     1688      }
     1689      *out << Walker->Name << "  with a length of " << RingSize << "." << endl << endl;
     1690      if (RingSize < MinimumRingSize)
     1691        MinimumRingSize = RingSize;
     1692    } else {
     1693      *out << Verbose(1) << "No ring with length equal to or smaller than " << MinimumRingSize << " found." << endl;
     1694    }
     1695   
     1696    // now clean the lists
     1697    while (!TouchedStack->IsEmpty()){
     1698      Walker = TouchedStack->PopFirst();
     1699      PredecessorList[Walker->nr] = NULL;
     1700      ShortestPathList[Walker->nr] = -1;
     1701      ColorList[Walker->nr] = white;
     1702    }
     1703  }
     1704       
    17081705
    17091706  if (MinimumRingSize != -1)
     
    17121709    *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
    17131710
    1714   Free((void **)&NoCyclicBondsPerAtom, "molecule::CyclicStructureAnalysis: *NoCyclicBondsPerAtom");
    1715   delete(AtomStack);
     1711  Free((void **)&PredecessorList, "molecule::CyclicStructureAnalysis: **PredecessorList");
     1712  Free((void **)&ShortestPathList, "molecule::CyclicStructureAnalysis: **ShortestPathList");
     1713  Free((void **)&ColorList, "molecule::CyclicStructureAnalysis: **ColorList");
     1714  delete(BFSStack);
    17161715};
    17171716
  • src/molecules.hpp

    r6d35e4 r8d9c38  
    326326  // Graph analysis
    327327  MoleculeLeafClass * DepthFirstSearchAnalysis(ofstream *out, bool ReturnStack, int &MinimumRingSize);
    328   void CyclicStructureAnalysis(ofstream *out, int &MinimumRingSize);
     328  void CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> *BackEdgeStack, int &MinimumRingSize);
    329329  bond * FindNextUnused(atom *vertex);
    330330  void SetNextComponentNumber(atom *vertex, int nr);
Note: See TracChangeset for help on using the changeset viewer.