source: src/molecule_graph.cpp@ 111387

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
Last change on this file since 111387 was 129204, checked in by Frederik Heber <heber@…>, 14 years ago

Moved bond.* to Bond/, new class GraphEdge which contains graph parts of bond.

  • enums Shading and EdgeType are now part of GraphEdge, hence bigger change in the code where these are used.
  • Property mode set to 100644
File size: 53.0 KB
RevLine 
[bcf653]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
[cee0b57]8/*
9 * molecule_graph.cpp
10 *
11 * Created on: Oct 5, 2009
12 * Author: heber
13 */
14
[bf3817]15// include config.h
[aafd77]16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
[ad011c]20#include "CodePatterns/MemDebug.hpp"
[112b09]21
[a564be]22#include <stack>
23
[f66195]24#include "atom.hpp"
[129204]25#include "Bond/bond.hpp"
[34c43a]26#include "Box.hpp"
27#include "CodePatterns/Assert.hpp"
28#include "CodePatterns/Info.hpp"
29#include "CodePatterns/Log.hpp"
30#include "CodePatterns/Verbose.hpp"
[cee0b57]31#include "config.hpp"
[f66195]32#include "element.hpp"
[129204]33#include "Graph/BondGraph.hpp"
[1d5afa5]34#include "Helpers/defs.hpp"
35#include "Helpers/fast_functions.hpp"
[952f38]36#include "Helpers/helpers.hpp"
[1d5afa5]37#include "LinearAlgebra/RealSpaceMatrix.hpp"
[b8b75d]38#include "linkedcell.hpp"
[cee0b57]39#include "molecule.hpp"
[34c43a]40#include "PointCloudAdaptor.hpp"
[b34306]41#include "World.hpp"
[9d83b6]42#include "WorldTime.hpp"
[1d5afa5]43
44#define MAXBONDS 8
45
[9eefda]46struct BFSAccounting
47{
48 atom **PredecessorList;
49 int *ShortestPathList;
[129204]50 enum GraphEdge::Shading *ColorList;
[a564be]51 std::deque<atom *> *BFSStack;
52 std::deque<atom *> *TouchedStack;
[9eefda]53 int AtomCount;
54 int BondOrder;
55 atom *Root;
56 bool BackStepping;
57 int CurrentGraphNr;
58 int ComponentNr;
59};
[cee0b57]60
[9eefda]61/** Accounting data for Depth First Search.
62 */
63struct DFSAccounting
64{
[a564be]65 std::deque<atom *> *AtomStack;
66 std::deque<bond *> *BackEdgeStack;
[9eefda]67 int CurrentGraphNr;
68 int ComponentNumber;
69 atom *Root;
70 bool BackStepping;
71};
72
73/************************************* Functions for class molecule *********************************/
[cee0b57]74
[99752a]75/** Fills the bond structure of this chain list subgraphs that are derived from a complete \a *reference molecule.
76 * Calls this routine in each MoleculeLeafClass::next subgraph if it's not NULL.
77 * \param *reference reference molecule with the bond structure to be copied
78 * \param **&ListOfLocalAtoms Lookup table for this subgraph and index of each atom in \a *reference, may be NULL on start, then it is filled
79 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
80 * \return true - success, false - failure
81 */
82bool molecule::FillBondStructureFromReference(const molecule * const reference, atom **&ListOfLocalAtoms, bool FreeList)
83{
84 atom *OtherWalker = NULL;
85 atom *Father = NULL;
86 bool status = true;
87 int AtomNo;
88
89 DoLog(1) && (Log() << Verbose(1) << "Begin of FillBondStructureFromReference." << endl);
90 // fill ListOfLocalAtoms if NULL was given
91 if (!FillListOfLocalAtoms(ListOfLocalAtoms, reference->getAtomCount())) {
92 DoLog(1) && (Log() << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl);
93 return false;
94 }
95
96 if (status) {
97 DoLog(1) && (Log() << Verbose(1) << "Creating adjacency list for molecule " << getName() << "." << endl);
98 // remove every bond from the list
99 for_each(begin(), end(),
100 boost::bind(&BondedParticle::ClearBondsAtStep,_1,WorldTime::getTime()));
101
102
103 for(molecule::const_iterator iter = begin(); iter != end(); ++iter) {
104 Father = (*iter)->GetTrueFather();
105 AtomNo = Father->getNr(); // global id of the current walker
106 const BondList& ListOfBonds = Father->getListOfBonds();
107 for (BondList::const_iterator Runner = ListOfBonds.begin();
108 Runner != ListOfBonds.end();
109 ++Runner) {
110 OtherWalker = ListOfLocalAtoms[(*Runner)->GetOtherAtom((*iter)->GetTrueFather())->getNr()]; // local copy of current bond partner of walker
111 if (OtherWalker != NULL) {
112 if (OtherWalker->getNr() > (*iter)->getNr())
113 AddBond((*iter), OtherWalker, (*Runner)->BondDegree);
114 } else {
115 DoLog(1) && (Log() << Verbose(1) << "OtherWalker = ListOfLocalAtoms[" << (*Runner)->GetOtherAtom((*iter)->GetTrueFather())->getNr() << "] is NULL!" << endl);
116 status = false;
117 }
118 }
119 }
120 }
121
122 if ((FreeList) && (ListOfLocalAtoms != NULL)) {
123 // free the index lookup list
124 delete[](ListOfLocalAtoms);
125 }
126 DoLog(1) && (Log() << Verbose(1) << "End of FillBondStructureFromReference." << endl);
127 return status;
128};
129
[e08c46]130/** Checks for presence of bonds within atom list.
131 * TODO: more sophisticated check for bond structure (e.g. connected subgraph, ...)
132 * \return true - bonds present, false - no bonds
133 */
[e4afb4]134bool molecule::hasBondStructure() const
[e08c46]135{
[9d83b6]136 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
137 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
138 if (!ListOfBonds.empty())
[e08c46]139 return true;
[9d83b6]140 }
[e08c46]141 return false;
142}
143
[b8b75d]144/** Prints a list of all bonds to \a *out.
145 */
[e138de]146void molecule::OutputBondsList() const
[b8b75d]147{
[a67d19]148 DoLog(1) && (Log() << Verbose(1) << endl << "From contents of bond chain list:");
[9d83b6]149 for(molecule::const_iterator AtomRunner = molecule::begin(); AtomRunner != molecule::end(); ++AtomRunner) {
150 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
151 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
152 BondRunner != ListOfBonds.end();
153 ++BondRunner)
[e08c46]154 if ((*BondRunner)->leftatom == *AtomRunner) {
155 DoLog(0) && (Log() << Verbose(0) << *(*BondRunner) << "\t" << endl);
156 }
[9d83b6]157 }
[a67d19]158 DoLog(0) && (Log() << Verbose(0) << endl);
[9eefda]159}
160;
[cee0b57]161
162
163/** Counts all cyclic bonds and returns their number.
164 * \note Hydrogen bonds can never by cyclic, thus no check for that
[9d37ac]165 * \return number of cyclic bonds
[cee0b57]166 */
[e138de]167int molecule::CountCyclicBonds()
[cee0b57]168{
[266237]169 NoCyclicBonds = 0;
[cee0b57]170 int *MinimumRingSize = NULL;
171 MoleculeLeafClass *Subgraphs = NULL;
[a564be]172 std::deque<bond *> *BackEdgeStack = NULL;
[9d83b6]173 for(molecule::iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
174 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
[129204]175 if ((!ListOfBonds.empty()) && ((*ListOfBonds.begin())->Type == GraphEdge::Undetermined)) {
[e08c46]176 DoLog(0) && (Log() << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl);
177 Subgraphs = DepthFirstSearchAnalysis(BackEdgeStack);
178 while (Subgraphs->next != NULL) {
179 Subgraphs = Subgraphs->next;
180 delete (Subgraphs->previous);
181 }
182 delete (Subgraphs);
183 delete[] (MinimumRingSize);
184 break;
[cee0b57]185 }
[9d83b6]186 }
187 for(molecule::iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
188 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
189 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
190 BondRunner != ListOfBonds.end();
191 ++BondRunner)
[e08c46]192 if ((*BondRunner)->leftatom == *AtomRunner)
193 if ((*BondRunner)->Cyclic)
194 NoCyclicBonds++;
[9d83b6]195 }
[9eefda]196 delete (BackEdgeStack);
[266237]197 return NoCyclicBonds;
[9eefda]198}
199;
[b8b75d]200
[cee0b57]201
[9eefda]202/** Sets atom::GraphNr and atom::LowpointNr to BFSAccounting::CurrentGraphNr.
203 * \param *Walker current node
204 * \param &BFS structure with accounting data for BFS
205 */
[e138de]206void DepthFirstSearchAnalysis_SetWalkersGraphNr(atom *&Walker, struct DFSAccounting &DFS)
[174e0e]207{
[9eefda]208 if (!DFS.BackStepping) { // if we don't just return from (8)
209 Walker->GraphNr = DFS.CurrentGraphNr;
210 Walker->LowpointNr = DFS.CurrentGraphNr;
[68f03d]211 DoLog(1) && (Log() << Verbose(1) << "Setting Walker[" << Walker->getName() << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl);
[a564be]212 DFS.AtomStack->push_front(Walker);
[9eefda]213 DFS.CurrentGraphNr++;
[174e0e]214 }
[9eefda]215}
216;
[174e0e]217
[9eefda]218/** During DFS goes along unvisited bond and touches other atom.
219 * Sets bond::type, if
220 * -# BackEdge: set atom::LowpointNr and push on \a BackEdgeStack
221 * -# TreeEgde: set atom::Ancestor and continue with Walker along this edge
222 * Continue until molecule::FindNextUnused() finds no more unused bonds.
223 * \param *mol molecule with atoms and finding unused bonds
224 * \param *&Binder current edge
225 * \param &DFS DFS accounting data
226 */
[e138de]227void DepthFirstSearchAnalysis_ProbeAlongUnusedBond(const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS)
[174e0e]228{
229 atom *OtherAtom = NULL;
230
231 do { // (3) if Walker has no unused egdes, go to (5)
[9eefda]232 DFS.BackStepping = false; // reset backstepping flag for (8)
[174e0e]233 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
234 Binder = mol->FindNextUnused(Walker);
235 if (Binder == NULL)
236 break;
[a67d19]237 DoLog(2) && (Log() << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl);
[174e0e]238 // (4) Mark Binder used, ...
[129204]239 Binder->MarkUsed(GraphEdge::black);
[174e0e]240 OtherAtom = Binder->GetOtherAtom(Walker);
[68f03d]241 DoLog(2) && (Log() << Verbose(2) << "(4) OtherAtom is " << OtherAtom->getName() << "." << endl);
[174e0e]242 if (OtherAtom->GraphNr != -1) {
243 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
[129204]244 Binder->Type = GraphEdge::BackEdge;
[a564be]245 DFS.BackEdgeStack->push_front(Binder);
[9eefda]246 Walker->LowpointNr = (Walker->LowpointNr < OtherAtom->GraphNr) ? Walker->LowpointNr : OtherAtom->GraphNr;
[68f03d]247 DoLog(3) && (Log() << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->getName() << "] to " << Walker->LowpointNr << "." << endl);
[174e0e]248 } else {
249 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
[129204]250 Binder->Type = GraphEdge::TreeEdge;
[174e0e]251 OtherAtom->Ancestor = Walker;
252 Walker = OtherAtom;
[68f03d]253 DoLog(3) && (Log() << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->getName() << "]'s Ancestor is now " << OtherAtom->Ancestor->getName() << ", Walker is OtherAtom " << OtherAtom->getName() << "." << endl);
[174e0e]254 break;
255 }
256 Binder = NULL;
[9eefda]257 } while (1); // (3)
258}
259;
[174e0e]260
[9eefda]261/** Checks whether we have a new component.
262 * if atom::LowpointNr of \a *&Walker is greater than atom::GraphNr of its atom::Ancestor, we have a new component.
263 * Meaning that if we touch upon a node who suddenly has a smaller atom::LowpointNr than its ancestor, then we
264 * have a found a new branch in the graph tree.
265 * \param *mol molecule with atoms and finding unused bonds
266 * \param *&Walker current node
267 * \param &DFS DFS accounting data
268 */
[e138de]269void DepthFirstSearchAnalysis_CheckForaNewComponent(const molecule * const mol, atom *&Walker, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
[174e0e]270{
271 atom *OtherAtom = NULL;
272
273 // (5) if Ancestor of Walker is ...
[68f03d]274 DoLog(1) && (Log() << Verbose(1) << "(5) Number of Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "] is " << Walker->Ancestor->GraphNr << "." << endl);
[174e0e]275
[9eefda]276 if (Walker->Ancestor->GraphNr != DFS.Root->GraphNr) {
[174e0e]277 // (6) (Ancestor of Walker is not Root)
278 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
279 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
280 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
[68f03d]281 DoLog(2) && (Log() << Verbose(2) << "(6) Setting Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl);
[174e0e]282 } else {
283 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
284 Walker->Ancestor->SeparationVertex = true;
[68f03d]285 DoLog(2) && (Log() << Verbose(2) << "(7) Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s is a separating vertex, creating component." << endl);
[9eefda]286 mol->SetNextComponentNumber(Walker->Ancestor, DFS.ComponentNumber);
[68f03d]287 DoLog(3) && (Log() << Verbose(3) << "(7) Walker[" << Walker->getName() << "]'s Ancestor's Compont is " << DFS.ComponentNumber << "." << endl);
[9eefda]288 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
[68f03d]289 DoLog(3) && (Log() << Verbose(3) << "(7) Walker[" << Walker->getName() << "]'s Compont is " << DFS.ComponentNumber << "." << endl);
[174e0e]290 do {
[a564be]291 ASSERT(!DFS.AtomStack->empty(), "DepthFirstSearchAnalysis_CheckForaNewComponent() - DFS.AtomStack is empty!");
292 OtherAtom = DFS.AtomStack->front();
293 DFS.AtomStack->pop_front();
[174e0e]294 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
[9eefda]295 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
[68f03d]296 DoLog(3) && (Log() << Verbose(3) << "(7) Other[" << OtherAtom->getName() << "]'s Compont is " << DFS.ComponentNumber << "." << endl);
[174e0e]297 } while (OtherAtom != Walker);
[9eefda]298 DFS.ComponentNumber++;
[174e0e]299 }
300 // (8) Walker becomes its Ancestor, go to (3)
[68f03d]301 DoLog(2) && (Log() << Verbose(2) << "(8) Walker[" << Walker->getName() << "] is now its Ancestor " << Walker->Ancestor->getName() << ", backstepping. " << endl);
[174e0e]302 Walker = Walker->Ancestor;
[9eefda]303 DFS.BackStepping = true;
[174e0e]304 }
[9eefda]305}
306;
[174e0e]307
[9eefda]308/** Cleans the root stack when we have found a component.
309 * If we are not DFSAccounting::BackStepping, then we clear the root stack by putting everything into a
310 * component down till we meet DFSAccounting::Root.
311 * \param *mol molecule with atoms and finding unused bonds
312 * \param *&Walker current node
313 * \param *&Binder current edge
314 * \param &DFS DFS accounting data
315 */
[e138de]316void DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
[174e0e]317{
318 atom *OtherAtom = NULL;
319
[9eefda]320 if (!DFS.BackStepping) { // coming from (8) want to go to (3)
[174e0e]321 // (9) remove all from stack till Walker (including), these and Root form a component
[99593f]322 //DFS.AtomStack->Output(out);
[9eefda]323 mol->SetNextComponentNumber(DFS.Root, DFS.ComponentNumber);
[68f03d]324 DoLog(3) && (Log() << Verbose(3) << "(9) Root[" << DFS.Root->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
[9eefda]325 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
[68f03d]326 DoLog(3) && (Log() << Verbose(3) << "(9) Walker[" << Walker->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
[174e0e]327 do {
[a564be]328 ASSERT(!DFS.AtomStack->empty(), "DepthFirstSearchAnalysis_CleanRootStackDownTillWalker() - DFS.AtomStack is empty!");
329 OtherAtom = DFS.AtomStack->front();
330 DFS.AtomStack->pop_front();
[174e0e]331 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
[9eefda]332 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
[a564be]333 DoLog(3) && (Log() << Verbose(3) << "(7) Other[" << OtherAtom->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
[174e0e]334 } while (OtherAtom != Walker);
[9eefda]335 DFS.ComponentNumber++;
[174e0e]336
337 // (11) Root is separation vertex, set Walker to Root and go to (4)
[9eefda]338 Walker = DFS.Root;
[174e0e]339 Binder = mol->FindNextUnused(Walker);
[68f03d]340 DoLog(1) && (Log() << Verbose(1) << "(10) Walker is Root[" << DFS.Root->getName() << "], next Unused Bond is " << Binder << "." << endl);
[174e0e]341 if (Binder != NULL) { // Root is separation vertex
[a67d19]342 DoLog(1) && (Log() << Verbose(1) << "(11) Root is a separation vertex." << endl);
[174e0e]343 Walker->SeparationVertex = true;
344 }
345 }
[9eefda]346}
347;
348
349/** Initializes DFSAccounting structure.
350 * \param &DFS accounting structure to allocate
[7218f8]351 * \param *mol molecule with AtomCount, BondCount and all atoms
[9eefda]352 */
[e138de]353void DepthFirstSearchAnalysis_Init(struct DFSAccounting &DFS, const molecule * const mol)
[9eefda]354{
[a564be]355 DFS.AtomStack = new std::deque<atom *> (mol->getAtomCount());
[9eefda]356 DFS.CurrentGraphNr = 0;
357 DFS.ComponentNumber = 0;
358 DFS.BackStepping = false;
[7218f8]359 mol->ResetAllBondsToUnused();
[a564be]360 DFS.BackEdgeStack->clear();
[9eefda]361}
362;
[174e0e]363
[9eefda]364/** Free's DFSAccounting structure.
365 * \param &DFS accounting structure to free
366 */
[e138de]367void DepthFirstSearchAnalysis_Finalize(struct DFSAccounting &DFS)
[9eefda]368{
369 delete (DFS.AtomStack);
[7218f8]370 // delete (DFS.BackEdgeStack); // DON'T free, see DepthFirstSearchAnalysis(), is returned as allocated
[9eefda]371}
372;
[174e0e]373
[00ef5c]374void molecule::init_DFS(struct DFSAccounting &DFS) const{
375 DepthFirstSearchAnalysis_Init(DFS, this);
376 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::resetGraphNr));
377 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::InitComponentNr));
378}
379
[cee0b57]380/** Performs a Depth-First search on this molecule.
381 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
382 * articulations points, ...
383 * We use the algorithm from [Even, Graph Algorithms, p.62].
[a564be]384 * \param *&BackEdgeStack NULL pointer to std::deque<bond *> with all the found back edges, allocated and filled on return
[cee0b57]385 * \return list of each disconnected subgraph as an individual molecule class structure
386 */
[a564be]387MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(std::deque<bond *> *&BackEdgeStack) const
[cee0b57]388{
[9eefda]389 struct DFSAccounting DFS;
[458c31]390 BackEdgeStack = new std::deque<bond *> (getBondCount());
[9eefda]391 DFS.BackEdgeStack = BackEdgeStack;
[cee0b57]392 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
393 MoleculeLeafClass *LeafWalker = SubGraphs;
[9eefda]394 int OldGraphNr = 0;
[174e0e]395 atom *Walker = NULL;
[cee0b57]396 bond *Binder = NULL;
397
[a7b761b]398 if (getAtomCount() == 0)
[046783]399 return SubGraphs;
[a67d19]400 DoLog(0) && (Log() << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl);
[00ef5c]401 init_DFS(DFS);
[cee0b57]402
[9879f6]403 for (molecule::const_iterator iter = begin(); iter != end();) {
404 DFS.Root = *iter;
[7218f8]405 // (1) mark all edges unused, empty stack, set atom->GraphNr = -1 for all
[a564be]406 DFS.AtomStack->clear();
[cee0b57]407
408 // put into new subgraph molecule and add this to list of subgraphs
409 LeafWalker = new MoleculeLeafClass(LeafWalker);
[5f612ee]410 LeafWalker->Leaf = World::getInstance().createMolecule();
[9eefda]411 LeafWalker->Leaf->AddCopyAtom(DFS.Root);
[cee0b57]412
[9eefda]413 OldGraphNr = DFS.CurrentGraphNr;
414 Walker = DFS.Root;
[cee0b57]415 do { // (10)
416 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
[e138de]417 DepthFirstSearchAnalysis_SetWalkersGraphNr(Walker, DFS);
[174e0e]418
[e138de]419 DepthFirstSearchAnalysis_ProbeAlongUnusedBond(this, Walker, Binder, DFS);
[174e0e]420
[cee0b57]421 if (Binder == NULL) {
[a67d19]422 DoLog(2) && (Log() << Verbose(2) << "No more Unused Bonds." << endl);
[cee0b57]423 break;
424 } else
425 Binder = NULL;
[9eefda]426 } while (1); // (2)
[cee0b57]427
428 // if we came from backstepping, yet there were no more unused bonds, we end up here with no Ancestor, because Walker is Root! Then we are finished!
[9eefda]429 if ((Walker == DFS.Root) && (Binder == NULL))
[cee0b57]430 break;
431
[e138de]432 DepthFirstSearchAnalysis_CheckForaNewComponent(this, Walker, DFS, LeafWalker);
[174e0e]433
[e138de]434 DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(this, Walker, Binder, DFS, LeafWalker);
[174e0e]435
[9eefda]436 } while ((DFS.BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
[cee0b57]437
438 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
[a67d19]439 DoLog(0) && (Log() << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << DFS.CurrentGraphNr << "." << endl);
[986ed3]440 LeafWalker->Leaf->Output((ofstream *)&(Log() << Verbose(0)));
[a67d19]441 DoLog(0) && (Log() << Verbose(0) << endl);
[cee0b57]442
443 // step on to next root
[9879f6]444 while ((iter != end()) && ((*iter)->GraphNr != -1)) {
445 //Log() << Verbose(1) << "Current next subgraph root candidate is " << (*iter)->Name << "." << endl;
446 if ((*iter)->GraphNr != -1) // if already discovered, step on
447 iter++;
[cee0b57]448 }
449 }
450 // set cyclic bond criterium on "same LP" basis
[266237]451 CyclicBondAnalysis();
452
[e138de]453 OutputGraphInfoPerAtom();
[266237]454
[e138de]455 OutputGraphInfoPerBond();
[266237]456
457 // free all and exit
[e138de]458 DepthFirstSearchAnalysis_Finalize(DFS);
[a67d19]459 DoLog(0) && (Log() << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl);
[266237]460 return SubGraphs;
[9eefda]461}
462;
[266237]463
464/** Scans through all bonds and set bond::Cyclic to true where atom::LowpointNr of both ends is equal: LP criterion.
465 */
[fa649a]466void molecule::CyclicBondAnalysis() const
[266237]467{
468 NoCyclicBonds = 0;
[9d83b6]469 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
470 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
471 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
472 BondRunner != ListOfBonds.end();
473 ++BondRunner)
[e08c46]474 if ((*BondRunner)->leftatom == *AtomRunner)
475 if ((*BondRunner)->rightatom->LowpointNr == (*BondRunner)->leftatom->LowpointNr) { // cyclic ??
476 (*BondRunner)->Cyclic = true;
477 NoCyclicBonds++;
478 }
[9d83b6]479 }
[9eefda]480}
481;
[cee0b57]482
[266237]483/** Output graph information per atom.
484 */
[e138de]485void molecule::OutputGraphInfoPerAtom() const
[266237]486{
[a67d19]487 DoLog(1) && (Log() << Verbose(1) << "Final graph info for each atom is:" << endl);
[c743f8]488 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::OutputGraphInfo));
[9eefda]489}
490;
[cee0b57]491
[266237]492/** Output graph information per bond.
493 */
[e138de]494void molecule::OutputGraphInfoPerBond() const
[266237]495{
[a67d19]496 DoLog(1) && (Log() << Verbose(1) << "Final graph info for each bond is:" << endl);
[9d83b6]497 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
498 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
499 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
500 BondRunner != ListOfBonds.end();
501 ++BondRunner)
[e08c46]502 if ((*BondRunner)->leftatom == *AtomRunner) {
[9d83b6]503 const bond *Binder = *BondRunner;
[f9183b]504 if (DoLog(2)) {
505 ostream &out = (Log() << Verbose(2));
[129204]506 out << ((Binder->Type == GraphEdge::TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
[f9183b]507 out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
508 Binder->leftatom->OutputComponentNumber(&out);
509 out << " === ";
510 out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
511 Binder->rightatom->OutputComponentNumber(&out);
512 out << ">." << endl;
513 }
[e08c46]514 if (Binder->Cyclic) // cyclic ??
515 DoLog(3) && (Log() << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl);
516 }
[9d83b6]517 }
[9eefda]518}
519;
520
521/** Initialise each vertex as white with no predecessor, empty queue, color Root lightgray.
522 * \param &BFS accounting structure
523 * \param AtomCount number of entries in the array to allocate
524 */
[e138de]525void InitializeBFSAccounting(struct BFSAccounting &BFS, int AtomCount)
[9eefda]526{
527 BFS.AtomCount = AtomCount;
[920c70]528 BFS.PredecessorList = new atom*[AtomCount];
529 BFS.ShortestPathList = new int[AtomCount];
[129204]530 BFS.ColorList = new enum GraphEdge::Shading[AtomCount];
[a564be]531 BFS.BFSStack = new std::deque<atom *> (AtomCount);
532 BFS.TouchedStack = new std::deque<atom *> (AtomCount);
[9eefda]533
[920c70]534 for (int i = AtomCount; i--;) {
[9eefda]535 BFS.ShortestPathList[i] = -1;
[920c70]536 BFS.PredecessorList[i] = 0;
[129204]537 BFS.ColorList[i] = GraphEdge::white;
[920c70]538 }
[cee0b57]539};
540
[9eefda]541/** Free's accounting structure.
542 * \param &BFS accounting structure
543 */
[e138de]544void FinalizeBFSAccounting(struct BFSAccounting &BFS)
[9eefda]545{
[920c70]546 delete[](BFS.PredecessorList);
547 delete[](BFS.ShortestPathList);
548 delete[](BFS.ColorList);
[9eefda]549 delete (BFS.BFSStack);
[c27778]550 delete (BFS.TouchedStack);
[9eefda]551 BFS.AtomCount = 0;
552};
553
554/** Clean the accounting structure.
555 * \param &BFS accounting structure
[ef9aae]556 */
[e138de]557void CleanBFSAccounting(struct BFSAccounting &BFS)
[ef9aae]558{
[9eefda]559 atom *Walker = NULL;
[a564be]560 while (!BFS.TouchedStack->empty()) {
561 Walker = BFS.TouchedStack->front();
562 BFS.TouchedStack->pop_front();
[735b1c]563 BFS.PredecessorList[Walker->getNr()] = NULL;
564 BFS.ShortestPathList[Walker->getNr()] = -1;
[129204]565 BFS.ColorList[Walker->getNr()] = GraphEdge::white;
[ef9aae]566 }
567};
568
[9eefda]569/** Resets shortest path list and BFSStack.
570 * \param *&Walker current node, pushed onto BFSAccounting::BFSStack and BFSAccounting::TouchedStack
571 * \param &BFS accounting structure
572 */
[e138de]573void ResetBFSAccounting(atom *&Walker, struct BFSAccounting &BFS)
[ef9aae]574{
[735b1c]575 BFS.ShortestPathList[Walker->getNr()] = 0;
[a564be]576 BFS.BFSStack->clear(); // start with empty BFS stack
577 BFS.BFSStack->push_front(Walker);
578 BFS.TouchedStack->push_front(Walker);
[ef9aae]579};
580
[9eefda]581/** Performs a BFS from \a *Root, trying to find the same node and hence a cycle.
582 * \param *&BackEdge the edge from root that we don't want to move along
583 * \param &BFS accounting structure
584 */
[e138de]585void CyclicStructureAnalysis_CyclicBFSFromRootToRoot(bond *&BackEdge, struct BFSAccounting &BFS)
[ef9aae]586{
587 atom *Walker = NULL;
588 atom *OtherAtom = NULL;
[9eefda]589 do { // look for Root
[a564be]590 ASSERT(!BFS.BFSStack->empty(), "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - BFS.BFSStack is empty!");
591 Walker = BFS.BFSStack->front();
592 BFS.BFSStack->pop_front();
[a67d19]593 DoLog(2) && (Log() << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *BFS.Root << "." << endl);
[9d83b6]594 const BondList& ListOfBonds = Walker->getListOfBonds();
595 for (BondList::const_iterator Runner = ListOfBonds.begin();
596 Runner != ListOfBonds.end();
597 ++Runner) {
[ef9aae]598 if ((*Runner) != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
599 OtherAtom = (*Runner)->GetOtherAtom(Walker);
[9eefda]600#ifdef ADDHYDROGEN
[83f176]601 if (OtherAtom->getType()->getAtomicNumber() != 1) {
[9eefda]602#endif
[68f03d]603 DoLog(2) && (Log() << Verbose(2) << "Current OtherAtom is: " << OtherAtom->getName() << " for bond " << *(*Runner) << "." << endl);
[129204]604 if (BFS.ColorList[OtherAtom->getNr()] == GraphEdge::white) {
[a564be]605 BFS.TouchedStack->push_front(OtherAtom);
[129204]606 BFS.ColorList[OtherAtom->getNr()] = GraphEdge::lightgray;
[735b1c]607 BFS.PredecessorList[OtherAtom->getNr()] = Walker; // Walker is the predecessor
608 BFS.ShortestPathList[OtherAtom->getNr()] = BFS.ShortestPathList[Walker->getNr()] + 1;
609 DoLog(2) && (Log() << Verbose(2) << "Coloring OtherAtom " << OtherAtom->getName() << " lightgray, its predecessor is " << Walker->getName() << " and its Shortest Path is " << BFS.ShortestPathList[OtherAtom->getNr()] << " egde(s) long." << endl);
610 //if (BFS.ShortestPathList[OtherAtom->getNr()] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
[a67d19]611 DoLog(3) && (Log() << Verbose(3) << "Putting OtherAtom into queue." << endl);
[a564be]612 BFS.BFSStack->push_front(OtherAtom);
[9eefda]613 //}
[ef9aae]614 } else {
[a67d19]615 DoLog(3) && (Log() << Verbose(3) << "Not Adding, has already been visited." << endl);
[ef9aae]616 }
[9eefda]617 if (OtherAtom == BFS.Root)
618 break;
619#ifdef ADDHYDROGEN
620 } else {
[a67d19]621 DoLog(2) && (Log() << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl);
[129204]622 BFS.ColorList[OtherAtom->getNr()] = GraphEdge::black;
[9eefda]623 }
624#endif
[ef9aae]625 } else {
[a67d19]626 DoLog(2) && (Log() << Verbose(2) << "Bond " << *(*Runner) << " not Visiting, is the back edge." << endl);
[ef9aae]627 }
628 }
[129204]629 BFS.ColorList[Walker->getNr()] = GraphEdge::black;
[68f03d]630 DoLog(1) && (Log() << Verbose(1) << "Coloring Walker " << Walker->getName() << " black." << endl);
[9eefda]631 if (OtherAtom == BFS.Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
[ef9aae]632 // step through predecessor list
633 while (OtherAtom != BackEdge->rightatom) {
[9eefda]634 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
[ef9aae]635 break;
636 else
[735b1c]637 OtherAtom = BFS.PredecessorList[OtherAtom->getNr()];
[ef9aae]638 }
639 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
[a67d19]640 DoLog(3) && (Log() << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl);
[ef9aae]641 do {
[a564be]642 ASSERT(!BFS.TouchedStack->empty(), "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - BFS.TouchedStack is empty!");
643 OtherAtom = BFS.TouchedStack->front();
644 BFS.TouchedStack->pop_front();
[735b1c]645 if (BFS.PredecessorList[OtherAtom->getNr()] == Walker) {
[a67d19]646 DoLog(4) && (Log() << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl);
[735b1c]647 BFS.PredecessorList[OtherAtom->getNr()] = NULL;
648 BFS.ShortestPathList[OtherAtom->getNr()] = -1;
[129204]649 BFS.ColorList[OtherAtom->getNr()] = GraphEdge::white;
[a564be]650 // rats ... deque has no find()
651 std::deque<atom *>::iterator iter = find(
652 BFS.BFSStack->begin(),
653 BFS.BFSStack->end(),
654 OtherAtom);
655 ASSERT(iter != BFS.BFSStack->end(),
656 "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - can't find "+toString(*OtherAtom)+" on stack!");
657 BFS.BFSStack->erase(iter);
[ef9aae]658 }
[735b1c]659 } while ((!BFS.TouchedStack->empty()) && (BFS.PredecessorList[OtherAtom->getNr()] == NULL));
[a564be]660 BFS.TouchedStack->push_front(OtherAtom); // last was wrongly popped
[ef9aae]661 OtherAtom = BackEdge->rightatom; // set to not Root
662 } else
[9eefda]663 OtherAtom = BFS.Root;
[ef9aae]664 }
[735b1c]665 } while ((!BFS.BFSStack->empty()) && (OtherAtom != BFS.Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->getNr()] < MinimumRingSize[Walker->GetTrueFather()->getNr()])));
[ef9aae]666};
667
[9eefda]668/** Climb back the BFSAccounting::PredecessorList and find cycle members.
669 * \param *&OtherAtom
670 * \param *&BackEdge denotes the edge we did not want to travel along when doing CyclicBFSFromRootToRoot()
671 * \param &BFS accounting structure
672 * \param *&MinimumRingSize minimum distance from this node possible without encountering oneself, set on return for each atom
673 * \param &MinRingSize global minimum distance from one node without encountering oneself, set on return
674 */
[e138de]675void CyclicStructureAnalysis_RetrieveCycleMembers(atom *&OtherAtom, bond *&BackEdge, struct BFSAccounting &BFS, int *&MinimumRingSize, int &MinRingSize)
[ef9aae]676{
677 atom *Walker = NULL;
678 int NumCycles = 0;
679 int RingSize = -1;
680
[9eefda]681 if (OtherAtom == BFS.Root) {
[ef9aae]682 // now climb back the predecessor list and thus find the cycle members
683 NumCycles++;
684 RingSize = 1;
[9eefda]685 BFS.Root->GetTrueFather()->IsCyclic = true;
[a67d19]686 DoLog(1) && (Log() << Verbose(1) << "Found ring contains: ");
[9eefda]687 Walker = BFS.Root;
[ef9aae]688 while (Walker != BackEdge->rightatom) {
[68f03d]689 DoLog(0) && (Log() << Verbose(0) << Walker->getName() << " <-> ");
[735b1c]690 Walker = BFS.PredecessorList[Walker->getNr()];
[ef9aae]691 Walker->GetTrueFather()->IsCyclic = true;
692 RingSize++;
693 }
[68f03d]694 DoLog(0) && (Log() << Verbose(0) << Walker->getName() << " with a length of " << RingSize << "." << endl << endl);
[ef9aae]695 // walk through all and set MinimumRingSize
[9eefda]696 Walker = BFS.Root;
[735b1c]697 MinimumRingSize[Walker->GetTrueFather()->getNr()] = RingSize;
[ef9aae]698 while (Walker != BackEdge->rightatom) {
[735b1c]699 Walker = BFS.PredecessorList[Walker->getNr()];
700 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->getNr()])
701 MinimumRingSize[Walker->GetTrueFather()->getNr()] = RingSize;
[ef9aae]702 }
703 if ((RingSize < MinRingSize) || (MinRingSize == -1))
704 MinRingSize = RingSize;
705 } else {
[735b1c]706 DoLog(1) && (Log() << Verbose(1) << "No ring containing " << *BFS.Root << " with length equal to or smaller than " << MinimumRingSize[BFS.Root->GetTrueFather()->getNr()] << " found." << endl);
[ef9aae]707 }
708};
709
[9eefda]710/** From a given node performs a BFS to touch the next cycle, for whose nodes \a *&MinimumRingSize is set and set it accordingly.
711 * \param *&Root node to look for closest cycle from, i.e. \a *&MinimumRingSize is set for this node
712 * \param *&MinimumRingSize minimum distance from this node possible without encountering oneself, set on return for each atom
713 * \param AtomCount number of nodes in graph
714 */
[e138de]715void CyclicStructureAnalysis_BFSToNextCycle(atom *&Root, atom *&Walker, int *&MinimumRingSize, int AtomCount)
[ef9aae]716{
[9eefda]717 struct BFSAccounting BFS;
[ef9aae]718 atom *OtherAtom = Walker;
719
[e138de]720 InitializeBFSAccounting(BFS, AtomCount);
[ef9aae]721
[e138de]722 ResetBFSAccounting(Walker, BFS);
[9eefda]723 while (OtherAtom != NULL) { // look for Root
[a564be]724 ASSERT(!BFS.BFSStack->empty(), "CyclicStructureAnalysis_BFSToNextCycle() - BFS.BFSStack is empty!");
725 Walker = BFS.BFSStack->front();
726 BFS.BFSStack->pop_front();
[e138de]727 //Log() << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
[9d83b6]728 const BondList& ListOfBonds = Walker->getListOfBonds();
729 for (BondList::const_iterator Runner = ListOfBonds.begin();
730 Runner != ListOfBonds.end();
731 ++Runner) {
[9eefda]732 // "removed (*Runner) != BackEdge) || " from next if, is u
[9d83b6]733 if ((ListOfBonds.size() == 1)) { // only walk along DFS spanning tree (otherwise we always find SP of 1 being backedge Binder), but terminal hydrogens may be connected via backedge, hence extra check
[ef9aae]734 OtherAtom = (*Runner)->GetOtherAtom(Walker);
[e138de]735 //Log() << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
[129204]736 if (BFS.ColorList[OtherAtom->getNr()] == GraphEdge::white) {
[a564be]737 BFS.TouchedStack->push_front(OtherAtom);
[129204]738 BFS.ColorList[OtherAtom->getNr()] = GraphEdge::lightgray;
[735b1c]739 BFS.PredecessorList[OtherAtom->getNr()] = Walker; // Walker is the predecessor
740 BFS.ShortestPathList[OtherAtom->getNr()] = BFS.ShortestPathList[Walker->getNr()] + 1;
741 //Log() << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->getNr()] << " egde(s) long." << endl;
[ef9aae]742 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
[735b1c]743 MinimumRingSize[Root->GetTrueFather()->getNr()] = BFS.ShortestPathList[OtherAtom->getNr()] + MinimumRingSize[OtherAtom->GetTrueFather()->getNr()];
[ef9aae]744 OtherAtom = NULL; //break;
745 break;
746 } else
[a564be]747 BFS.BFSStack->push_front(OtherAtom);
[ef9aae]748 } else {
[e138de]749 //Log() << Verbose(3) << "Not Adding, has already been visited." << endl;
[ef9aae]750 }
751 } else {
[e138de]752 //Log() << Verbose(3) << "Not Visiting, is a back edge." << endl;
[ef9aae]753 }
754 }
[129204]755 BFS.ColorList[Walker->getNr()] = GraphEdge::black;
[e138de]756 //Log() << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
[ef9aae]757 }
758 //CleanAccountingLists(TouchedStack, PredecessorList, ShortestPathList, ColorList);
759
[e138de]760 FinalizeBFSAccounting(BFS);
[9eefda]761}
762;
[ef9aae]763
[9eefda]764/** All nodes that are not in cycles get assigned a \a *&MinimumRingSizeby BFS to next cycle.
765 * \param *&MinimumRingSize array with minimum distance without encountering onself for each atom
766 * \param &MinRingSize global minium distance
767 * \param &NumCyles number of cycles in graph
768 * \param *mol molecule with atoms
769 */
[e138de]770void CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(int *&MinimumRingSize, int &MinRingSize, int &NumCycles, const molecule * const mol)
[ef9aae]771{
[9eefda]772 atom *Root = NULL;
[ef9aae]773 atom *Walker = NULL;
774 if (MinRingSize != -1) { // if rings are present
775 // go over all atoms
[9879f6]776 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
777 Root = *iter;
[ef9aae]778
[735b1c]779 if (MinimumRingSize[Root->GetTrueFather()->getNr()] == mol->getAtomCount()) { // check whether MinimumRingSize is set, if not BFS to next where it is
[ef9aae]780 Walker = Root;
781
[e138de]782 //Log() << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
[ea7176]783 CyclicStructureAnalysis_BFSToNextCycle(Root, Walker, MinimumRingSize, mol->getAtomCount());
[ef9aae]784
785 }
[735b1c]786 DoLog(1) && (Log() << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->getNr()] << "." << endl);
[ef9aae]787 }
[a67d19]788 DoLog(1) && (Log() << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl);
[ef9aae]789 } else
[a67d19]790 DoLog(1) && (Log() << Verbose(1) << "No rings were detected in the molecular structure." << endl);
[9eefda]791}
792;
[ef9aae]793
[cee0b57]794/** Analyses the cycles found and returns minimum of all cycle lengths.
795 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
796 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
797 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
798 * as cyclic and print out the cycles.
799 * \param *BackEdgeStack stack with all back edges found during DFS scan. Beware: This stack contains the bonds from the total molecule, not from the subgraph!
800 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
801 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
802 */
[9d37ac]803void molecule::CyclicStructureAnalysis(
804 std::deque<bond *> * BackEdgeStack,
805 int *&MinimumRingSize
806 ) const
[cee0b57]807{
[9eefda]808 struct BFSAccounting BFS;
[ef9aae]809 atom *Walker = NULL;
810 atom *OtherAtom = NULL;
811 bond *BackEdge = NULL;
812 int NumCycles = 0;
813 int MinRingSize = -1;
[cee0b57]814
[ea7176]815 InitializeBFSAccounting(BFS, getAtomCount());
[cee0b57]816
[e138de]817 //Log() << Verbose(1) << "Back edge list - ";
[99593f]818 //BackEdgeStack->Output(out);
[cee0b57]819
[a67d19]820 DoLog(1) && (Log() << Verbose(1) << "Analysing cycles ... " << endl);
[cee0b57]821 NumCycles = 0;
[a564be]822 while (!BackEdgeStack->empty()) {
823 BackEdge = BackEdgeStack->front();
824 BackEdgeStack->pop_front();
[cee0b57]825 // this is the target
[9eefda]826 BFS.Root = BackEdge->leftatom;
[cee0b57]827 // this is the source point
828 Walker = BackEdge->rightatom;
829
[e138de]830 ResetBFSAccounting(Walker, BFS);
[cee0b57]831
[a67d19]832 DoLog(1) && (Log() << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl);
[ef9aae]833 OtherAtom = NULL;
[e138de]834 CyclicStructureAnalysis_CyclicBFSFromRootToRoot(BackEdge, BFS);
[cee0b57]835
[e138de]836 CyclicStructureAnalysis_RetrieveCycleMembers(OtherAtom, BackEdge, BFS, MinimumRingSize, MinRingSize);
[cee0b57]837
[e138de]838 CleanBFSAccounting(BFS);
[ef9aae]839 }
[e138de]840 FinalizeBFSAccounting(BFS);
[ef9aae]841
[e138de]842 CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(MinimumRingSize, MinRingSize, NumCycles, this);
[fa649a]843};
[cee0b57]844
845/** Sets the next component number.
846 * This is O(N) as the number of bonds per atom is bound.
847 * \param *vertex atom whose next atom::*ComponentNr is to be set
[5309ba]848 * \param Nr number to use
[cee0b57]849 */
[fa649a]850void molecule::SetNextComponentNumber(atom *vertex, int nr) const
[cee0b57]851{
[9eefda]852 size_t i = 0;
[cee0b57]853 if (vertex != NULL) {
[9d83b6]854 const BondList& ListOfBonds = vertex->getListOfBonds();
855 for (; i < ListOfBonds.size(); i++) {
[9eefda]856 if (vertex->ComponentNr[i] == -1) { // check if not yet used
[cee0b57]857 vertex->ComponentNr[i] = nr;
858 break;
[9eefda]859 } else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
860 break; // breaking here will not cause error!
[cee0b57]861 }
[9d83b6]862 if (i == ListOfBonds.size()) {
[58ed4a]863 DoeLog(0) && (eLog()<< Verbose(0) << "Error: All Component entries are already occupied!" << endl);
[e359a8]864 performCriticalExit();
865 }
866 } else {
[58ed4a]867 DoeLog(0) && (eLog()<< Verbose(0) << "Error: Given vertex is NULL!" << endl);
[e359a8]868 performCriticalExit();
869 }
[9eefda]870}
871;
[cee0b57]872
873/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
874 * \param *vertex atom to regard
875 * \return bond class or NULL
876 */
[fa649a]877bond * molecule::FindNextUnused(atom *vertex) const
[cee0b57]878{
[9d83b6]879 const BondList& ListOfBonds = vertex->getListOfBonds();
880 for (BondList::const_iterator Runner = ListOfBonds.begin();
881 Runner != ListOfBonds.end();
882 ++Runner)
[129204]883 if ((*Runner)->IsUsed() == GraphEdge::white)
[9eefda]884 return ((*Runner));
[cee0b57]885 return NULL;
[9eefda]886}
887;
[cee0b57]888
889/** Resets bond::Used flag of all bonds in this molecule.
890 * \return true - success, false - -failure
891 */
[fa649a]892void molecule::ResetAllBondsToUnused() const
[cee0b57]893{
[9d83b6]894 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
895 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
896 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
897 BondRunner != ListOfBonds.end();
898 ++BondRunner)
[e08c46]899 if ((*BondRunner)->leftatom == *AtomRunner)
900 (*BondRunner)->ResetUsed();
[9d83b6]901 }
[9eefda]902}
903;
[cee0b57]904
905/** Output a list of flags, stating whether the bond was visited or not.
[9d37ac]906 * \param *list list to print
[cee0b57]907 */
[e138de]908void OutputAlreadyVisited(int *list)
[cee0b57]909{
[a67d19]910 DoLog(4) && (Log() << Verbose(4) << "Already Visited Bonds:\t");
[9eefda]911 for (int i = 1; i <= list[0]; i++)
[a67d19]912 DoLog(0) && (Log() << Verbose(0) << list[i] << " ");
913 DoLog(0) && (Log() << Verbose(0) << endl);
[9eefda]914}
915;
[cee0b57]916
917/** Storing the bond structure of a molecule to file.
[5309ba]918 * Simply stores Atom::Nr and then the Atom::Nr of all bond partners per line.
[35b698]919 * \param &filename name of file
920 * \param path path to file, defaults to empty
[cee0b57]921 * \return true - file written successfully, false - writing failed
922 */
[e4afb4]923bool molecule::StoreAdjacencyToFile(std::string filename, std::string path)
[cee0b57]924{
925 ofstream AdjacencyFile;
[35b698]926 string line;
[cee0b57]927 bool status = true;
928
[35b698]929 if (path != "")
930 line = path + "/" + filename;
[8ab0407]931 else
[35b698]932 line = filename;
933 AdjacencyFile.open(line.c_str(), ios::out);
[acf800]934 DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl);
[35b698]935 if (AdjacencyFile.good()) {
[1f1b23]936 AdjacencyFile << "m\tn" << endl;
[00ef5c]937 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputAdjacency),&AdjacencyFile));
[cee0b57]938 AdjacencyFile.close();
[acf800]939 DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl);
[cee0b57]940 } else {
[35b698]941 DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl);
[cee0b57]942 status = false;
943 }
944
945 return status;
[9eefda]946}
947;
[cee0b57]948
[1f1b23]949/** Storing the bond structure of a molecule to file.
[5309ba]950 * Simply stores Atom::Nr and then the Atom::Nr of all bond partners, one per line.
[35b698]951 * \param &filename name of file
952 * \param path path to file, defaults to empty
[1f1b23]953 * \return true - file written successfully, false - writing failed
954 */
[e4afb4]955bool molecule::StoreBondsToFile(std::string filename, std::string path)
[1f1b23]956{
957 ofstream BondFile;
[35b698]958 string line;
[1f1b23]959 bool status = true;
960
[35b698]961 if (path != "")
962 line = path + "/" + filename;
[8ab0407]963 else
[35b698]964 line = filename;
965 BondFile.open(line.c_str(), ios::out);
[acf800]966 DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl);
[35b698]967 if (BondFile.good()) {
[1f1b23]968 BondFile << "m\tn" << endl;
[00ef5c]969 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputBonds),&BondFile));
[1f1b23]970 BondFile.close();
[acf800]971 DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl);
[1f1b23]972 } else {
[35b698]973 DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl);
[1f1b23]974 status = false;
975 }
976
977 return status;
978}
979;
980
[35b698]981bool CheckAdjacencyFileAgainstMolecule_Init(std::string &path, ifstream &File, int *&CurrentBonds)
[ba4170]982{
[35b698]983 string filename;
984 filename = path + ADJACENCYFILE;
985 File.open(filename.c_str(), ios::out);
[0de7e8]986 DoLog(1) && (Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl);
[35b698]987 if (File.fail())
[ba4170]988 return false;
989
990 // allocate storage structure
[1d5afa5]991 CurrentBonds = new int[MAXBONDS]; // contains parsed bonds of current atom
992 for(int i=0;i<MAXBONDS;i++)
[920c70]993 CurrentBonds[i] = 0;
[ba4170]994 return true;
[9eefda]995}
996;
[ba4170]997
[e138de]998void CheckAdjacencyFileAgainstMolecule_Finalize(ifstream &File, int *&CurrentBonds)
[ba4170]999{
1000 File.close();
1001 File.clear();
[920c70]1002 delete[](CurrentBonds);
[9eefda]1003}
1004;
[ba4170]1005
[e138de]1006void CheckAdjacencyFileAgainstMolecule_CompareBonds(bool &status, int &NonMatchNumber, atom *&Walker, size_t &CurrentBondsOfAtom, int AtomNr, int *&CurrentBonds, atom **ListOfAtoms)
[ba4170]1007{
1008 size_t j = 0;
1009 int id = -1;
1010
[e138de]1011 //Log() << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
[9d83b6]1012 const BondList& ListOfBonds = Walker->getListOfBonds();
1013 if (CurrentBondsOfAtom == ListOfBonds.size()) {
1014 for (BondList::const_iterator Runner = ListOfBonds.begin();
1015 Runner != ListOfBonds.end();
1016 ++Runner) {
[735b1c]1017 id = (*Runner)->GetOtherAtom(Walker)->getNr();
[ba4170]1018 j = 0;
[9eefda]1019 for (; (j < CurrentBondsOfAtom) && (CurrentBonds[j++] != id);)
[ba4170]1020 ; // check against all parsed bonds
[9eefda]1021 if (CurrentBonds[j - 1] != id) { // no match ? Then mark in ListOfAtoms
[ba4170]1022 ListOfAtoms[AtomNr] = NULL;
1023 NonMatchNumber++;
1024 status = false;
[0de7e8]1025 DoeLog(2) && (eLog() << Verbose(2) << id << " can not be found in list." << endl);
[ba4170]1026 } else {
[0de7e8]1027 //Log() << Verbose(0) << "[" << id << "]\t";
[ba4170]1028 }
1029 }
[e138de]1030 //Log() << Verbose(0) << endl;
[ba4170]1031 } else {
[9d83b6]1032 DoLog(0) && (Log() << Verbose(0) << "Number of bonds for Atom " << *Walker << " does not match, parsed " << CurrentBondsOfAtom << " against " << ListOfBonds.size() << "." << endl);
[ba4170]1033 status = false;
1034 }
[9eefda]1035}
1036;
[ba4170]1037
[cee0b57]1038/** Checks contents of adjacency file against bond structure in structure molecule.
1039 * \param *path path to file
[5309ba]1040 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::Nr) to *Atom
[cee0b57]1041 * \return true - structure is equal, false - not equivalence
1042 */
[35b698]1043bool molecule::CheckAdjacencyFileAgainstMolecule(std::string &path, atom **ListOfAtoms)
[cee0b57]1044{
1045 ifstream File;
1046 bool status = true;
[266237]1047 atom *Walker = NULL;
[ba4170]1048 int *CurrentBonds = NULL;
[9eefda]1049 int NonMatchNumber = 0; // will number of atoms with differing bond structure
[ba4170]1050 size_t CurrentBondsOfAtom = -1;
[0de7e8]1051 const int AtomCount = getAtomCount();
[cee0b57]1052
[e138de]1053 if (!CheckAdjacencyFileAgainstMolecule_Init(path, File, CurrentBonds)) {
[a67d19]1054 DoLog(1) && (Log() << Verbose(1) << "Adjacency file not found." << endl);
[ba4170]1055 return true;
1056 }
1057
[920c70]1058 char buffer[MAXSTRINGSIZE];
[1d5afa5]1059 int tmp;
[ba4170]1060 // Parse the file line by line and count the bonds
1061 while (!File.eof()) {
1062 File.getline(buffer, MAXSTRINGSIZE);
1063 stringstream line;
1064 line.str(buffer);
1065 int AtomNr = -1;
1066 line >> AtomNr;
1067 CurrentBondsOfAtom = -1; // we count one too far due to line end
1068 // parse into structure
[0de7e8]1069 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
[ba4170]1070 Walker = ListOfAtoms[AtomNr];
[1d5afa5]1071 while (line >> ws >> tmp) {
1072 std::cout << "Recognized bond partner " << tmp << std::endl;
1073 CurrentBonds[++CurrentBondsOfAtom] = tmp;
1074 ASSERT(CurrentBondsOfAtom < MAXBONDS,
1075 "molecule::CheckAdjacencyFileAgainstMolecule() - encountered more bonds than allowed: "
1076 +toString(CurrentBondsOfAtom)+" >= "+toString(MAXBONDS)+"!");
1077 }
[ba4170]1078 // compare against present bonds
[e138de]1079 CheckAdjacencyFileAgainstMolecule_CompareBonds(status, NonMatchNumber, Walker, CurrentBondsOfAtom, AtomNr, CurrentBonds, ListOfAtoms);
[0de7e8]1080 } else {
1081 if (AtomNr != -1)
1082 DoeLog(2) && (eLog() << Verbose(2) << AtomNr << " is not valid in the range of ids [" << 0 << "," << AtomCount << ")." << endl);
[ba4170]1083 }
[cee0b57]1084 }
[e138de]1085 CheckAdjacencyFileAgainstMolecule_Finalize(File, CurrentBonds);
[cee0b57]1086
[ba4170]1087 if (status) { // if equal we parse the KeySetFile
[a67d19]1088 DoLog(1) && (Log() << Verbose(1) << "done: Equal." << endl);
[ba4170]1089 } else
[a67d19]1090 DoLog(1) && (Log() << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl);
[cee0b57]1091 return status;
[9eefda]1092}
1093;
[cee0b57]1094
1095/** Picks from a global stack with all back edges the ones in the fragment.
[5309ba]1096 * \param **ListOfLocalAtoms array of father atom::Nr to local atom::Nr (reverse of atom::father)
[cee0b57]1097 * \param *ReferenceStack stack with all the back egdes
1098 * \param *LocalStack stack to be filled
1099 * \return true - everything ok, false - ReferenceStack was empty
1100 */
[a564be]1101bool molecule::PickLocalBackEdges(atom **ListOfLocalAtoms, std::deque<bond *> *&ReferenceStack, std::deque<bond *> *&LocalStack) const
[cee0b57]1102{
1103 bool status = true;
[a564be]1104 if (ReferenceStack->empty()) {
[a67d19]1105 DoLog(1) && (Log() << Verbose(1) << "ReferenceStack is empty!" << endl);
[cee0b57]1106 return false;
1107 }
[a564be]1108 bond *Binder = ReferenceStack->front();
1109 ReferenceStack->pop_front();
[9eefda]1110 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
[cee0b57]1111 atom *Walker = NULL, *OtherAtom = NULL;
[a564be]1112 ReferenceStack->push_front(Binder);
[cee0b57]1113
[9eefda]1114 do { // go through all bonds and push local ones
[735b1c]1115 Walker = ListOfLocalAtoms[Binder->leftatom->getNr()]; // get one atom in the reference molecule
[9d83b6]1116 if (Walker != NULL) { // if this Walker exists in the subgraph ...
1117 const BondList& ListOfBonds = Walker->getListOfBonds();
1118 for (BondList::const_iterator Runner = ListOfBonds.begin();
1119 Runner != ListOfBonds.end();
1120 ++Runner) {
[266237]1121 OtherAtom = (*Runner)->GetOtherAtom(Walker);
[735b1c]1122 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->getNr()]) { // found the bond
[a564be]1123 LocalStack->push_front((*Runner));
[a67d19]1124 DoLog(3) && (Log() << Verbose(3) << "Found local edge " << *(*Runner) << "." << endl);
[cee0b57]1125 break;
1126 }
1127 }
[9d83b6]1128 }
[a564be]1129 ASSERT(!ReferenceStack->empty(), "molecule::PickLocalBackEdges() - ReferenceStack is empty!");
1130 Binder = ReferenceStack->front(); // loop the stack for next item
1131 ReferenceStack->pop_front();
[a67d19]1132 DoLog(3) && (Log() << Verbose(3) << "Current candidate edge " << Binder << "." << endl);
[a564be]1133 ReferenceStack->push_front(Binder);
[cee0b57]1134 } while (FirstBond != Binder);
1135
1136 return status;
[9eefda]1137}
1138;
[ce7cc5]1139
[266237]1140/** Adds a bond as a copy to a given one
1141 * \param *left leftatom of new bond
1142 * \param *right rightatom of new bond
1143 * \param *CopyBond rest of fields in bond are copied from this
1144 * \return pointer to new bond
1145 */
1146bond * molecule::CopyBond(atom *left, atom *right, bond *CopyBond)
1147{
1148 bond *Binder = AddBond(left, right, CopyBond->BondDegree);
1149 Binder->Cyclic = CopyBond->Cyclic;
1150 Binder->Type = CopyBond->Type;
1151 return Binder;
[9eefda]1152}
1153;
[266237]1154
[e138de]1155void BuildInducedSubgraph_Init(atom **&ParentList, int AtomCount)
[cee0b57]1156{
1157 // reset parent list
[920c70]1158 ParentList = new atom*[AtomCount];
1159 for (int i=0;i<AtomCount;i++)
1160 ParentList[i] = NULL;
[a67d19]1161 DoLog(3) && (Log() << Verbose(3) << "Resetting ParentList." << endl);
[9eefda]1162}
1163;
[cee0b57]1164
[e138de]1165void BuildInducedSubgraph_FillParentList(const molecule *mol, const molecule *Father, atom **&ParentList)
[43587e]1166{
[cee0b57]1167 // fill parent list with sons
[a67d19]1168 DoLog(3) && (Log() << Verbose(3) << "Filling Parent List." << endl);
[9879f6]1169 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
[735b1c]1170 ParentList[(*iter)->father->getNr()] = (*iter);
[cee0b57]1171 // Outputting List for debugging
[735b1c]1172 DoLog(4) && (Log() << Verbose(4) << "Son[" << (*iter)->father->getNr() << "] of " << (*iter)->father << " is " << ParentList[(*iter)->father->getNr()] << "." << endl);
[cee0b57]1173 }
[a7b761b]1174};
[43587e]1175
[e138de]1176void BuildInducedSubgraph_Finalize(atom **&ParentList)
[43587e]1177{
[920c70]1178 delete[](ParentList);
[9eefda]1179}
1180;
[43587e]1181
[e138de]1182bool BuildInducedSubgraph_CreateBondsFromParent(molecule *mol, const molecule *Father, atom **&ParentList)
[43587e]1183{
1184 bool status = true;
1185 atom *OtherAtom = NULL;
[cee0b57]1186 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
[a67d19]1187 DoLog(3) && (Log() << Verbose(3) << "Creating bonds." << endl);
[9879f6]1188 for (molecule::const_iterator iter = Father->begin(); iter != Father->end(); ++iter) {
[735b1c]1189 if (ParentList[(*iter)->getNr()] != NULL) {
1190 if (ParentList[(*iter)->getNr()]->father != (*iter)) {
[cee0b57]1191 status = false;
1192 } else {
[9d83b6]1193 const BondList& ListOfBonds = (*iter)->getListOfBonds();
1194 for (BondList::const_iterator Runner = ListOfBonds.begin();
1195 Runner != ListOfBonds.end();
1196 ++Runner) {
[9879f6]1197 OtherAtom = (*Runner)->GetOtherAtom((*iter));
[735b1c]1198 if (ParentList[OtherAtom->getNr()] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
1199 DoLog(4) && (Log() << Verbose(4) << "Endpoints of Bond " << (*Runner) << " are both present: " << ParentList[(*iter)->getNr()]->getName() << " and " << ParentList[OtherAtom->getNr()]->getName() << "." << endl);
1200 mol->AddBond(ParentList[(*iter)->getNr()], ParentList[OtherAtom->getNr()], (*Runner)->BondDegree);
[cee0b57]1201 }
1202 }
1203 }
1204 }
1205 }
[43587e]1206 return status;
[9eefda]1207}
1208;
[cee0b57]1209
[43587e]1210/** Adds bond structure to this molecule from \a Father molecule.
1211 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
1212 * with end points present in this molecule, bond is created in this molecule.
1213 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
1214 * \param *Father father molecule
1215 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
1216 * \todo not checked, not fully working probably
1217 */
[9d37ac]1218bool molecule::BuildInducedSubgraph(const molecule *Father){
[43587e]1219 bool status = true;
1220 atom **ParentList = NULL;
[a67d19]1221 DoLog(2) && (Log() << Verbose(2) << "Begin of BuildInducedSubgraph." << endl);
[ea7176]1222 BuildInducedSubgraph_Init(ParentList, Father->getAtomCount());
[e138de]1223 BuildInducedSubgraph_FillParentList(this, Father, ParentList);
1224 status = BuildInducedSubgraph_CreateBondsFromParent(this, Father, ParentList);
1225 BuildInducedSubgraph_Finalize(ParentList);
[a67d19]1226 DoLog(2) && (Log() << Verbose(2) << "End of BuildInducedSubgraph." << endl);
[cee0b57]1227 return status;
[9eefda]1228}
1229;
[cee0b57]1230
1231/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
1232 * \param *Fragment Keyset of fragment's vertices
1233 * \return true - connected, false - disconnected
1234 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
1235 */
[e138de]1236bool molecule::CheckForConnectedSubgraph(KeySet *Fragment)
[cee0b57]1237{
1238 atom *Walker = NULL, *Walker2 = NULL;
1239 bool BondStatus = false;
1240 int size;
1241
[a67d19]1242 DoLog(1) && (Log() << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl);
1243 DoLog(2) && (Log() << Verbose(2) << "Disconnected atom: ");
[cee0b57]1244
1245 // count number of atoms in graph
1246 size = 0;
[9eefda]1247 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
[cee0b57]1248 size++;
1249 if (size > 1)
[9eefda]1250 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
[cee0b57]1251 Walker = FindAtom(*runner);
1252 BondStatus = false;
[9eefda]1253 for (KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
[cee0b57]1254 Walker2 = FindAtom(*runners);
[9d83b6]1255 const BondList& ListOfBonds = Walker->getListOfBonds();
1256 for (BondList::const_iterator Runner = ListOfBonds.begin();
1257 Runner != ListOfBonds.end();
1258 ++Runner) {
[266237]1259 if ((*Runner)->GetOtherAtom(Walker) == Walker2) {
[cee0b57]1260 BondStatus = true;
1261 break;
1262 }
1263 if (BondStatus)
1264 break;
1265 }
1266 }
1267 if (!BondStatus) {
[a67d19]1268 DoLog(0) && (Log() << Verbose(0) << (*Walker) << endl);
[cee0b57]1269 return false;
1270 }
1271 }
1272 else {
[a67d19]1273 DoLog(0) && (Log() << Verbose(0) << "none." << endl);
[cee0b57]1274 return true;
1275 }
[a67d19]1276 DoLog(0) && (Log() << Verbose(0) << "none." << endl);
[cee0b57]1277
[a67d19]1278 DoLog(1) && (Log() << Verbose(1) << "End of CheckForConnectedSubgraph" << endl);
[cee0b57]1279
1280 return true;
1281}
[c6123b]1282
1283/** Fills a lookup list of father's Atom::Nr -> atom for each subgraph.
1284 * \param *out output stream from debugging
1285 * \param **&ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
1286 * \param GlobalAtomCount number of atoms in the complete molecule
1287 * \return true - success, false - failure (ListOfLocalAtoms != NULL)
1288 */
1289bool molecule::FillListOfLocalAtoms(atom **&ListOfLocalAtoms, const int GlobalAtomCount)
1290{
1291 bool status = true;
1292
1293 if (ListOfLocalAtoms == NULL) { // allocate and fill list of this fragment/subgraph
1294 status = status && CreateFatherLookupTable(ListOfLocalAtoms, GlobalAtomCount);
1295 } else
1296 return false;
1297
1298 return status;
1299}
1300
Note: See TracBrowser for help on using the repository browser.