source: src/molecule_graph.cpp@ e73ad9a

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 e73ad9a was e73ad9a, checked in by Frederik Heber <heber@…>, 14 years ago

Moved CyclicStructureAnalysis from molecule_graph.cpp into own functor in Graph/.

  • Property mode set to 100644
File size: 37.3 KB
Line 
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
8/*
9 * molecule_graph.cpp
10 *
11 * Created on: Oct 5, 2009
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include <stack>
23
24#include "atom.hpp"
25#include "Bond/bond.hpp"
26#include "Box.hpp"
27#include "CodePatterns/Assert.hpp"
28#include "CodePatterns/Info.hpp"
29#include "CodePatterns/Log.hpp"
30#include "CodePatterns/Verbose.hpp"
31#include "config.hpp"
32#include "element.hpp"
33#include "Graph/BondGraph.hpp"
34#include "Helpers/defs.hpp"
35#include "Helpers/fast_functions.hpp"
36#include "Helpers/helpers.hpp"
37#include "LinearAlgebra/RealSpaceMatrix.hpp"
38#include "linkedcell.hpp"
39#include "molecule.hpp"
40#include "PointCloudAdaptor.hpp"
41#include "World.hpp"
42#include "WorldTime.hpp"
43
44#define MAXBONDS 8
45
46
47/** Accounting data for Depth First Search.
48 */
49struct DFSAccounting
50{
51 std::deque<atom *> *AtomStack;
52 std::deque<bond *> *BackEdgeStack;
53 int CurrentGraphNr;
54 int ComponentNumber;
55 atom *Root;
56 bool BackStepping;
57};
58
59/************************************* Functions for class molecule *********************************/
60
61/** Fills the bond structure of this chain list subgraphs that are derived from a complete \a *reference molecule.
62 * Calls this routine in each MoleculeLeafClass::next subgraph if it's not NULL.
63 * \param *reference reference molecule with the bond structure to be copied
64 * \param **&ListOfLocalAtoms Lookup table for this subgraph and index of each atom in \a *reference, may be NULL on start, then it is filled
65 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
66 * \return true - success, false - failure
67 */
68bool molecule::FillBondStructureFromReference(const molecule * const reference, atom **&ListOfLocalAtoms, bool FreeList)
69{
70 atom *OtherWalker = NULL;
71 atom *Father = NULL;
72 bool status = true;
73 int AtomNo;
74
75 DoLog(1) && (Log() << Verbose(1) << "Begin of FillBondStructureFromReference." << endl);
76 // fill ListOfLocalAtoms if NULL was given
77 if (!FillListOfLocalAtoms(ListOfLocalAtoms, reference->getAtomCount())) {
78 DoLog(1) && (Log() << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl);
79 return false;
80 }
81
82 if (status) {
83 DoLog(1) && (Log() << Verbose(1) << "Creating adjacency list for molecule " << getName() << "." << endl);
84 // remove every bond from the list
85 for_each(begin(), end(),
86 boost::bind(&BondedParticle::ClearBondsAtStep,_1,WorldTime::getTime()));
87
88
89 for(molecule::const_iterator iter = begin(); iter != end(); ++iter) {
90 Father = (*iter)->GetTrueFather();
91 AtomNo = Father->getNr(); // global id of the current walker
92 const BondList& ListOfBonds = Father->getListOfBonds();
93 for (BondList::const_iterator Runner = ListOfBonds.begin();
94 Runner != ListOfBonds.end();
95 ++Runner) {
96 OtherWalker = ListOfLocalAtoms[(*Runner)->GetOtherAtom((*iter)->GetTrueFather())->getNr()]; // local copy of current bond partner of walker
97 if (OtherWalker != NULL) {
98 if (OtherWalker->getNr() > (*iter)->getNr())
99 AddBond((*iter), OtherWalker, (*Runner)->BondDegree);
100 } else {
101 DoLog(1) && (Log() << Verbose(1) << "OtherWalker = ListOfLocalAtoms[" << (*Runner)->GetOtherAtom((*iter)->GetTrueFather())->getNr() << "] is NULL!" << endl);
102 status = false;
103 }
104 }
105 }
106 }
107
108 if ((FreeList) && (ListOfLocalAtoms != NULL)) {
109 // free the index lookup list
110 delete[](ListOfLocalAtoms);
111 }
112 DoLog(1) && (Log() << Verbose(1) << "End of FillBondStructureFromReference." << endl);
113 return status;
114};
115
116/** Checks for presence of bonds within atom list.
117 * TODO: more sophisticated check for bond structure (e.g. connected subgraph, ...)
118 * \return true - bonds present, false - no bonds
119 */
120bool molecule::hasBondStructure() const
121{
122 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
123 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
124 if (!ListOfBonds.empty())
125 return true;
126 }
127 return false;
128}
129
130/** Prints a list of all bonds to \a *out.
131 */
132void molecule::OutputBondsList() const
133{
134 DoLog(1) && (Log() << Verbose(1) << endl << "From contents of bond chain list:");
135 for(molecule::const_iterator AtomRunner = molecule::begin(); AtomRunner != molecule::end(); ++AtomRunner) {
136 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
137 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
138 BondRunner != ListOfBonds.end();
139 ++BondRunner)
140 if ((*BondRunner)->leftatom == *AtomRunner) {
141 DoLog(0) && (Log() << Verbose(0) << *(*BondRunner) << "\t" << endl);
142 }
143 }
144 DoLog(0) && (Log() << Verbose(0) << endl);
145}
146;
147
148
149/** Counts all cyclic bonds and returns their number.
150 * \note Hydrogen bonds can never by cyclic, thus no check for that
151 * \return number of cyclic bonds
152 */
153int molecule::CountCyclicBonds()
154{
155 NoCyclicBonds = 0;
156 int *MinimumRingSize = NULL;
157 MoleculeLeafClass *Subgraphs = NULL;
158 std::deque<bond *> *BackEdgeStack = NULL;
159 for(molecule::iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
160 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
161 if ((!ListOfBonds.empty()) && ((*ListOfBonds.begin())->Type == GraphEdge::Undetermined)) {
162 DoLog(0) && (Log() << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl);
163 Subgraphs = DepthFirstSearchAnalysis(BackEdgeStack);
164 while (Subgraphs->next != NULL) {
165 Subgraphs = Subgraphs->next;
166 delete (Subgraphs->previous);
167 }
168 delete (Subgraphs);
169 delete[] (MinimumRingSize);
170 break;
171 }
172 }
173 for(molecule::iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
174 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
175 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
176 BondRunner != ListOfBonds.end();
177 ++BondRunner)
178 if ((*BondRunner)->leftatom == *AtomRunner)
179 if ((*BondRunner)->Cyclic)
180 NoCyclicBonds++;
181 }
182 delete (BackEdgeStack);
183 return NoCyclicBonds;
184}
185;
186
187
188/** Sets atom::GraphNr and atom::LowpointNr to DFSAccounting::CurrentGraphNr.
189 * \param *Walker current node
190 * \param &BFS structure with accounting data for BFS
191 */
192void DepthFirstSearchAnalysis_SetWalkersGraphNr(atom *&Walker, struct DFSAccounting &DFS)
193{
194 if (!DFS.BackStepping) { // if we don't just return from (8)
195 Walker->GraphNr = DFS.CurrentGraphNr;
196 Walker->LowpointNr = DFS.CurrentGraphNr;
197 DoLog(1) && (Log() << Verbose(1) << "Setting Walker[" << Walker->getName() << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl);
198 DFS.AtomStack->push_front(Walker);
199 DFS.CurrentGraphNr++;
200 }
201}
202;
203
204/** During DFS goes along unvisited bond and touches other atom.
205 * Sets bond::type, if
206 * -# BackEdge: set atom::LowpointNr and push on \a BackEdgeStack
207 * -# TreeEgde: set atom::Ancestor and continue with Walker along this edge
208 * Continue until molecule::FindNextUnused() finds no more unused bonds.
209 * \param *mol molecule with atoms and finding unused bonds
210 * \param *&Binder current edge
211 * \param &DFS DFS accounting data
212 */
213void DepthFirstSearchAnalysis_ProbeAlongUnusedBond(const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS)
214{
215 atom *OtherAtom = NULL;
216
217 do { // (3) if Walker has no unused egdes, go to (5)
218 DFS.BackStepping = false; // reset backstepping flag for (8)
219 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
220 Binder = mol->FindNextUnused(Walker);
221 if (Binder == NULL)
222 break;
223 DoLog(2) && (Log() << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl);
224 // (4) Mark Binder used, ...
225 Binder->MarkUsed(GraphEdge::black);
226 OtherAtom = Binder->GetOtherAtom(Walker);
227 DoLog(2) && (Log() << Verbose(2) << "(4) OtherAtom is " << OtherAtom->getName() << "." << endl);
228 if (OtherAtom->GraphNr != -1) {
229 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
230 Binder->Type = GraphEdge::BackEdge;
231 DFS.BackEdgeStack->push_front(Binder);
232 Walker->LowpointNr = (Walker->LowpointNr < OtherAtom->GraphNr) ? Walker->LowpointNr : OtherAtom->GraphNr;
233 DoLog(3) && (Log() << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->getName() << "] to " << Walker->LowpointNr << "." << endl);
234 } else {
235 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
236 Binder->Type = GraphEdge::TreeEdge;
237 OtherAtom->Ancestor = Walker;
238 Walker = OtherAtom;
239 DoLog(3) && (Log() << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->getName() << "]'s Ancestor is now " << OtherAtom->Ancestor->getName() << ", Walker is OtherAtom " << OtherAtom->getName() << "." << endl);
240 break;
241 }
242 Binder = NULL;
243 } while (1); // (3)
244}
245;
246
247/** Checks whether we have a new component.
248 * if atom::LowpointNr of \a *&Walker is greater than atom::GraphNr of its atom::Ancestor, we have a new component.
249 * Meaning that if we touch upon a node who suddenly has a smaller atom::LowpointNr than its ancestor, then we
250 * have a found a new branch in the graph tree.
251 * \param *mol molecule with atoms and finding unused bonds
252 * \param *&Walker current node
253 * \param &DFS DFS accounting data
254 */
255void DepthFirstSearchAnalysis_CheckForaNewComponent(const molecule * const mol, atom *&Walker, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
256{
257 atom *OtherAtom = NULL;
258
259 // (5) if Ancestor of Walker is ...
260 DoLog(1) && (Log() << Verbose(1) << "(5) Number of Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "] is " << Walker->Ancestor->GraphNr << "." << endl);
261
262 if (Walker->Ancestor->GraphNr != DFS.Root->GraphNr) {
263 // (6) (Ancestor of Walker is not Root)
264 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
265 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
266 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
267 DoLog(2) && (Log() << Verbose(2) << "(6) Setting Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl);
268 } else {
269 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
270 Walker->Ancestor->SeparationVertex = true;
271 DoLog(2) && (Log() << Verbose(2) << "(7) Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s is a separating vertex, creating component." << endl);
272 mol->SetNextComponentNumber(Walker->Ancestor, DFS.ComponentNumber);
273 DoLog(3) && (Log() << Verbose(3) << "(7) Walker[" << Walker->getName() << "]'s Ancestor's Compont is " << DFS.ComponentNumber << "." << endl);
274 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
275 DoLog(3) && (Log() << Verbose(3) << "(7) Walker[" << Walker->getName() << "]'s Compont is " << DFS.ComponentNumber << "." << endl);
276 do {
277 ASSERT(!DFS.AtomStack->empty(), "DepthFirstSearchAnalysis_CheckForaNewComponent() - DFS.AtomStack is empty!");
278 OtherAtom = DFS.AtomStack->front();
279 DFS.AtomStack->pop_front();
280 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
281 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
282 DoLog(3) && (Log() << Verbose(3) << "(7) Other[" << OtherAtom->getName() << "]'s Compont is " << DFS.ComponentNumber << "." << endl);
283 } while (OtherAtom != Walker);
284 DFS.ComponentNumber++;
285 }
286 // (8) Walker becomes its Ancestor, go to (3)
287 DoLog(2) && (Log() << Verbose(2) << "(8) Walker[" << Walker->getName() << "] is now its Ancestor " << Walker->Ancestor->getName() << ", backstepping. " << endl);
288 Walker = Walker->Ancestor;
289 DFS.BackStepping = true;
290 }
291}
292;
293
294/** Cleans the root stack when we have found a component.
295 * If we are not DFSAccounting::BackStepping, then we clear the root stack by putting everything into a
296 * component down till we meet DFSAccounting::Root.
297 * \param *mol molecule with atoms and finding unused bonds
298 * \param *&Walker current node
299 * \param *&Binder current edge
300 * \param &DFS DFS accounting data
301 */
302void DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
303{
304 atom *OtherAtom = NULL;
305
306 if (!DFS.BackStepping) { // coming from (8) want to go to (3)
307 // (9) remove all from stack till Walker (including), these and Root form a component
308 //DFS.AtomStack->Output(out);
309 mol->SetNextComponentNumber(DFS.Root, DFS.ComponentNumber);
310 DoLog(3) && (Log() << Verbose(3) << "(9) Root[" << DFS.Root->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
311 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
312 DoLog(3) && (Log() << Verbose(3) << "(9) Walker[" << Walker->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
313 do {
314 ASSERT(!DFS.AtomStack->empty(), "DepthFirstSearchAnalysis_CleanRootStackDownTillWalker() - DFS.AtomStack is empty!");
315 OtherAtom = DFS.AtomStack->front();
316 DFS.AtomStack->pop_front();
317 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
318 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
319 DoLog(3) && (Log() << Verbose(3) << "(7) Other[" << OtherAtom->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
320 } while (OtherAtom != Walker);
321 DFS.ComponentNumber++;
322
323 // (11) Root is separation vertex, set Walker to Root and go to (4)
324 Walker = DFS.Root;
325 Binder = mol->FindNextUnused(Walker);
326 DoLog(1) && (Log() << Verbose(1) << "(10) Walker is Root[" << DFS.Root->getName() << "], next Unused Bond is " << Binder << "." << endl);
327 if (Binder != NULL) { // Root is separation vertex
328 DoLog(1) && (Log() << Verbose(1) << "(11) Root is a separation vertex." << endl);
329 Walker->SeparationVertex = true;
330 }
331 }
332}
333;
334
335/** Initializes DFSAccounting structure.
336 * \param &DFS accounting structure to allocate
337 * \param *mol molecule with AtomCount, BondCount and all atoms
338 */
339void DepthFirstSearchAnalysis_Init(struct DFSAccounting &DFS, const molecule * const mol)
340{
341 DFS.AtomStack = new std::deque<atom *> (mol->getAtomCount());
342 DFS.CurrentGraphNr = 0;
343 DFS.ComponentNumber = 0;
344 DFS.BackStepping = false;
345 mol->ResetAllBondsToUnused();
346 DFS.BackEdgeStack->clear();
347}
348;
349
350/** Free's DFSAccounting structure.
351 * \param &DFS accounting structure to free
352 */
353void DepthFirstSearchAnalysis_Finalize(struct DFSAccounting &DFS)
354{
355 delete (DFS.AtomStack);
356 // delete (DFS.BackEdgeStack); // DON'T free, see DepthFirstSearchAnalysis(), is returned as allocated
357}
358;
359
360void molecule::init_DFS(struct DFSAccounting &DFS) const{
361 DepthFirstSearchAnalysis_Init(DFS, this);
362 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::resetGraphNr));
363 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::InitComponentNr));
364}
365
366/** Performs a Depth-First search on this molecule.
367 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
368 * articulations points, ...
369 * We use the algorithm from [Even, Graph Algorithms, p.62].
370 * \param *&BackEdgeStack NULL pointer to std::deque<bond *> with all the found back edges, allocated and filled on return
371 * \return list of each disconnected subgraph as an individual molecule class structure
372 */
373MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(std::deque<bond *> *&BackEdgeStack) const
374{
375 struct DFSAccounting DFS;
376 BackEdgeStack = new std::deque<bond *> (getBondCount());
377 DFS.BackEdgeStack = BackEdgeStack;
378 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
379 MoleculeLeafClass *LeafWalker = SubGraphs;
380 int OldGraphNr = 0;
381 atom *Walker = NULL;
382 bond *Binder = NULL;
383
384 if (getAtomCount() == 0)
385 return SubGraphs;
386 DoLog(0) && (Log() << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl);
387 init_DFS(DFS);
388
389 for (molecule::const_iterator iter = begin(); iter != end();) {
390 DFS.Root = *iter;
391 // (1) mark all edges unused, empty stack, set atom->GraphNr = -1 for all
392 DFS.AtomStack->clear();
393
394 // put into new subgraph molecule and add this to list of subgraphs
395 LeafWalker = new MoleculeLeafClass(LeafWalker);
396 LeafWalker->Leaf = World::getInstance().createMolecule();
397 LeafWalker->Leaf->AddCopyAtom(DFS.Root);
398
399 OldGraphNr = DFS.CurrentGraphNr;
400 Walker = DFS.Root;
401 do { // (10)
402 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
403 DepthFirstSearchAnalysis_SetWalkersGraphNr(Walker, DFS);
404
405 DepthFirstSearchAnalysis_ProbeAlongUnusedBond(this, Walker, Binder, DFS);
406
407 if (Binder == NULL) {
408 DoLog(2) && (Log() << Verbose(2) << "No more Unused Bonds." << endl);
409 break;
410 } else
411 Binder = NULL;
412 } while (1); // (2)
413
414 // 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!
415 if ((Walker == DFS.Root) && (Binder == NULL))
416 break;
417
418 DepthFirstSearchAnalysis_CheckForaNewComponent(this, Walker, DFS, LeafWalker);
419
420 DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(this, Walker, Binder, DFS, LeafWalker);
421
422 } while ((DFS.BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
423
424 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
425 DoLog(0) && (Log() << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << DFS.CurrentGraphNr << "." << endl);
426 LeafWalker->Leaf->Output((ofstream *)&(Log() << Verbose(0)));
427 DoLog(0) && (Log() << Verbose(0) << endl);
428
429 // step on to next root
430 while ((iter != end()) && ((*iter)->GraphNr != -1)) {
431 //Log() << Verbose(1) << "Current next subgraph root candidate is " << (*iter)->Name << "." << endl;
432 if ((*iter)->GraphNr != -1) // if already discovered, step on
433 iter++;
434 }
435 }
436 // set cyclic bond criterium on "same LP" basis
437 CyclicBondAnalysis();
438
439 OutputGraphInfoPerAtom();
440
441 OutputGraphInfoPerBond();
442
443 // free all and exit
444 DepthFirstSearchAnalysis_Finalize(DFS);
445 DoLog(0) && (Log() << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl);
446 return SubGraphs;
447}
448;
449
450/** Scans through all bonds and set bond::Cyclic to true where atom::LowpointNr of both ends is equal: LP criterion.
451 */
452void molecule::CyclicBondAnalysis() const
453{
454 NoCyclicBonds = 0;
455 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
456 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
457 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
458 BondRunner != ListOfBonds.end();
459 ++BondRunner)
460 if ((*BondRunner)->leftatom == *AtomRunner)
461 if ((*BondRunner)->rightatom->LowpointNr == (*BondRunner)->leftatom->LowpointNr) { // cyclic ??
462 (*BondRunner)->Cyclic = true;
463 NoCyclicBonds++;
464 }
465 }
466}
467;
468
469/** Output graph information per atom.
470 */
471void molecule::OutputGraphInfoPerAtom() const
472{
473 DoLog(1) && (Log() << Verbose(1) << "Final graph info for each atom is:" << endl);
474 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::OutputGraphInfo));
475}
476;
477
478/** Output graph information per bond.
479 */
480void molecule::OutputGraphInfoPerBond() const
481{
482 DoLog(1) && (Log() << Verbose(1) << "Final graph info for each bond is:" << endl);
483 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
484 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
485 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
486 BondRunner != ListOfBonds.end();
487 ++BondRunner)
488 if ((*BondRunner)->leftatom == *AtomRunner) {
489 const bond *Binder = *BondRunner;
490 if (DoLog(2)) {
491 ostream &out = (Log() << Verbose(2));
492 out << ((Binder->Type == GraphEdge::TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
493 out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
494 Binder->leftatom->OutputComponentNumber(&out);
495 out << " === ";
496 out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
497 Binder->rightatom->OutputComponentNumber(&out);
498 out << ">." << endl;
499 }
500 if (Binder->Cyclic) // cyclic ??
501 DoLog(3) && (Log() << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl);
502 }
503 }
504}
505;
506
507/** Sets the next component number.
508 * This is O(N) as the number of bonds per atom is bound.
509 * \param *vertex atom whose next atom::*ComponentNr is to be set
510 * \param Nr number to use
511 */
512void molecule::SetNextComponentNumber(atom *vertex, int nr) const
513{
514 size_t i = 0;
515 if (vertex != NULL) {
516 const BondList& ListOfBonds = vertex->getListOfBonds();
517 for (; i < ListOfBonds.size(); i++) {
518 if (vertex->ComponentNr[i] == -1) { // check if not yet used
519 vertex->ComponentNr[i] = nr;
520 break;
521 } else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
522 break; // breaking here will not cause error!
523 }
524 if (i == ListOfBonds.size()) {
525 DoeLog(0) && (eLog()<< Verbose(0) << "Error: All Component entries are already occupied!" << endl);
526 performCriticalExit();
527 }
528 } else {
529 DoeLog(0) && (eLog()<< Verbose(0) << "Error: Given vertex is NULL!" << endl);
530 performCriticalExit();
531 }
532}
533;
534
535/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
536 * \param *vertex atom to regard
537 * \return bond class or NULL
538 */
539bond * molecule::FindNextUnused(atom *vertex) const
540{
541 const BondList& ListOfBonds = vertex->getListOfBonds();
542 for (BondList::const_iterator Runner = ListOfBonds.begin();
543 Runner != ListOfBonds.end();
544 ++Runner)
545 if ((*Runner)->IsUsed() == GraphEdge::white)
546 return ((*Runner));
547 return NULL;
548}
549;
550
551/** Resets bond::Used flag of all bonds in this molecule.
552 * \return true - success, false - -failure
553 */
554void molecule::ResetAllBondsToUnused() const
555{
556 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
557 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
558 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
559 BondRunner != ListOfBonds.end();
560 ++BondRunner)
561 if ((*BondRunner)->leftatom == *AtomRunner)
562 (*BondRunner)->ResetUsed();
563 }
564}
565;
566
567/** Output a list of flags, stating whether the bond was visited or not.
568 * \param *list list to print
569 */
570void OutputAlreadyVisited(int *list)
571{
572 DoLog(4) && (Log() << Verbose(4) << "Already Visited Bonds:\t");
573 for (int i = 1; i <= list[0]; i++)
574 DoLog(0) && (Log() << Verbose(0) << list[i] << " ");
575 DoLog(0) && (Log() << Verbose(0) << endl);
576}
577;
578
579/** Storing the bond structure of a molecule to file.
580 * Simply stores Atom::Nr and then the Atom::Nr of all bond partners per line.
581 * \param &filename name of file
582 * \param path path to file, defaults to empty
583 * \return true - file written successfully, false - writing failed
584 */
585bool molecule::StoreAdjacencyToFile(std::string filename, std::string path)
586{
587 ofstream AdjacencyFile;
588 string line;
589 bool status = true;
590
591 if (path != "")
592 line = path + "/" + filename;
593 else
594 line = filename;
595 AdjacencyFile.open(line.c_str(), ios::out);
596 DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl);
597 if (AdjacencyFile.good()) {
598 AdjacencyFile << "m\tn" << endl;
599 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputAdjacency),&AdjacencyFile));
600 AdjacencyFile.close();
601 DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl);
602 } else {
603 DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl);
604 status = false;
605 }
606
607 return status;
608}
609;
610
611/** Storing the bond structure of a molecule to file.
612 * Simply stores Atom::Nr and then the Atom::Nr of all bond partners, one per line.
613 * \param &filename name of file
614 * \param path path to file, defaults to empty
615 * \return true - file written successfully, false - writing failed
616 */
617bool molecule::StoreBondsToFile(std::string filename, std::string path)
618{
619 ofstream BondFile;
620 string line;
621 bool status = true;
622
623 if (path != "")
624 line = path + "/" + filename;
625 else
626 line = filename;
627 BondFile.open(line.c_str(), ios::out);
628 DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl);
629 if (BondFile.good()) {
630 BondFile << "m\tn" << endl;
631 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputBonds),&BondFile));
632 BondFile.close();
633 DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl);
634 } else {
635 DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl);
636 status = false;
637 }
638
639 return status;
640}
641;
642
643bool CheckAdjacencyFileAgainstMolecule_Init(std::string &path, ifstream &File, int *&CurrentBonds)
644{
645 string filename;
646 filename = path + ADJACENCYFILE;
647 File.open(filename.c_str(), ios::out);
648 DoLog(1) && (Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl);
649 if (File.fail())
650 return false;
651
652 // allocate storage structure
653 CurrentBonds = new int[MAXBONDS]; // contains parsed bonds of current atom
654 for(int i=0;i<MAXBONDS;i++)
655 CurrentBonds[i] = 0;
656 return true;
657}
658;
659
660void CheckAdjacencyFileAgainstMolecule_Finalize(ifstream &File, int *&CurrentBonds)
661{
662 File.close();
663 File.clear();
664 delete[](CurrentBonds);
665}
666;
667
668void CheckAdjacencyFileAgainstMolecule_CompareBonds(bool &status, int &NonMatchNumber, atom *&Walker, size_t &CurrentBondsOfAtom, int AtomNr, int *&CurrentBonds, atom **ListOfAtoms)
669{
670 size_t j = 0;
671 int id = -1;
672
673 //Log() << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
674 const BondList& ListOfBonds = Walker->getListOfBonds();
675 if (CurrentBondsOfAtom == ListOfBonds.size()) {
676 for (BondList::const_iterator Runner = ListOfBonds.begin();
677 Runner != ListOfBonds.end();
678 ++Runner) {
679 id = (*Runner)->GetOtherAtom(Walker)->getNr();
680 j = 0;
681 for (; (j < CurrentBondsOfAtom) && (CurrentBonds[j++] != id);)
682 ; // check against all parsed bonds
683 if (CurrentBonds[j - 1] != id) { // no match ? Then mark in ListOfAtoms
684 ListOfAtoms[AtomNr] = NULL;
685 NonMatchNumber++;
686 status = false;
687 DoeLog(2) && (eLog() << Verbose(2) << id << " can not be found in list." << endl);
688 } else {
689 //Log() << Verbose(0) << "[" << id << "]\t";
690 }
691 }
692 //Log() << Verbose(0) << endl;
693 } else {
694 DoLog(0) && (Log() << Verbose(0) << "Number of bonds for Atom " << *Walker << " does not match, parsed " << CurrentBondsOfAtom << " against " << ListOfBonds.size() << "." << endl);
695 status = false;
696 }
697}
698;
699
700/** Checks contents of adjacency file against bond structure in structure molecule.
701 * \param *path path to file
702 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::Nr) to *Atom
703 * \return true - structure is equal, false - not equivalence
704 */
705bool molecule::CheckAdjacencyFileAgainstMolecule(std::string &path, atom **ListOfAtoms)
706{
707 ifstream File;
708 bool status = true;
709 atom *Walker = NULL;
710 int *CurrentBonds = NULL;
711 int NonMatchNumber = 0; // will number of atoms with differing bond structure
712 size_t CurrentBondsOfAtom = -1;
713 const int AtomCount = getAtomCount();
714
715 if (!CheckAdjacencyFileAgainstMolecule_Init(path, File, CurrentBonds)) {
716 DoLog(1) && (Log() << Verbose(1) << "Adjacency file not found." << endl);
717 return true;
718 }
719
720 char buffer[MAXSTRINGSIZE];
721 int tmp;
722 // Parse the file line by line and count the bonds
723 while (!File.eof()) {
724 File.getline(buffer, MAXSTRINGSIZE);
725 stringstream line;
726 line.str(buffer);
727 int AtomNr = -1;
728 line >> AtomNr;
729 CurrentBondsOfAtom = -1; // we count one too far due to line end
730 // parse into structure
731 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
732 Walker = ListOfAtoms[AtomNr];
733 while (line >> ws >> tmp) {
734 std::cout << "Recognized bond partner " << tmp << std::endl;
735 CurrentBonds[++CurrentBondsOfAtom] = tmp;
736 ASSERT(CurrentBondsOfAtom < MAXBONDS,
737 "molecule::CheckAdjacencyFileAgainstMolecule() - encountered more bonds than allowed: "
738 +toString(CurrentBondsOfAtom)+" >= "+toString(MAXBONDS)+"!");
739 }
740 // compare against present bonds
741 CheckAdjacencyFileAgainstMolecule_CompareBonds(status, NonMatchNumber, Walker, CurrentBondsOfAtom, AtomNr, CurrentBonds, ListOfAtoms);
742 } else {
743 if (AtomNr != -1)
744 DoeLog(2) && (eLog() << Verbose(2) << AtomNr << " is not valid in the range of ids [" << 0 << "," << AtomCount << ")." << endl);
745 }
746 }
747 CheckAdjacencyFileAgainstMolecule_Finalize(File, CurrentBonds);
748
749 if (status) { // if equal we parse the KeySetFile
750 DoLog(1) && (Log() << Verbose(1) << "done: Equal." << endl);
751 } else
752 DoLog(1) && (Log() << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl);
753 return status;
754}
755;
756
757/** Picks from a global stack with all back edges the ones in the fragment.
758 * \param **ListOfLocalAtoms array of father atom::Nr to local atom::Nr (reverse of atom::father)
759 * \param *ReferenceStack stack with all the back egdes
760 * \param *LocalStack stack to be filled
761 * \return true - everything ok, false - ReferenceStack was empty
762 */
763bool molecule::PickLocalBackEdges(atom **ListOfLocalAtoms, std::deque<bond *> *&ReferenceStack, std::deque<bond *> *&LocalStack) const
764{
765 bool status = true;
766 if (ReferenceStack->empty()) {
767 DoLog(1) && (Log() << Verbose(1) << "ReferenceStack is empty!" << endl);
768 return false;
769 }
770 bond *Binder = ReferenceStack->front();
771 ReferenceStack->pop_front();
772 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
773 atom *Walker = NULL, *OtherAtom = NULL;
774 ReferenceStack->push_front(Binder);
775
776 do { // go through all bonds and push local ones
777 Walker = ListOfLocalAtoms[Binder->leftatom->getNr()]; // get one atom in the reference molecule
778 if (Walker != NULL) { // if this Walker exists in the subgraph ...
779 const BondList& ListOfBonds = Walker->getListOfBonds();
780 for (BondList::const_iterator Runner = ListOfBonds.begin();
781 Runner != ListOfBonds.end();
782 ++Runner) {
783 OtherAtom = (*Runner)->GetOtherAtom(Walker);
784 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->getNr()]) { // found the bond
785 LocalStack->push_front((*Runner));
786 DoLog(3) && (Log() << Verbose(3) << "Found local edge " << *(*Runner) << "." << endl);
787 break;
788 }
789 }
790 }
791 ASSERT(!ReferenceStack->empty(), "molecule::PickLocalBackEdges() - ReferenceStack is empty!");
792 Binder = ReferenceStack->front(); // loop the stack for next item
793 ReferenceStack->pop_front();
794 DoLog(3) && (Log() << Verbose(3) << "Current candidate edge " << Binder << "." << endl);
795 ReferenceStack->push_front(Binder);
796 } while (FirstBond != Binder);
797
798 return status;
799}
800;
801
802/** Adds a bond as a copy to a given one
803 * \param *left leftatom of new bond
804 * \param *right rightatom of new bond
805 * \param *CopyBond rest of fields in bond are copied from this
806 * \return pointer to new bond
807 */
808bond * molecule::CopyBond(atom *left, atom *right, bond *CopyBond)
809{
810 bond *Binder = AddBond(left, right, CopyBond->BondDegree);
811 Binder->Cyclic = CopyBond->Cyclic;
812 Binder->Type = CopyBond->Type;
813 return Binder;
814}
815;
816
817void BuildInducedSubgraph_Init(atom **&ParentList, int AtomCount)
818{
819 // reset parent list
820 ParentList = new atom*[AtomCount];
821 for (int i=0;i<AtomCount;i++)
822 ParentList[i] = NULL;
823 DoLog(3) && (Log() << Verbose(3) << "Resetting ParentList." << endl);
824}
825;
826
827void BuildInducedSubgraph_FillParentList(const molecule *mol, const molecule *Father, atom **&ParentList)
828{
829 // fill parent list with sons
830 DoLog(3) && (Log() << Verbose(3) << "Filling Parent List." << endl);
831 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
832 ParentList[(*iter)->father->getNr()] = (*iter);
833 // Outputting List for debugging
834 DoLog(4) && (Log() << Verbose(4) << "Son[" << (*iter)->father->getNr() << "] of " << (*iter)->father << " is " << ParentList[(*iter)->father->getNr()] << "." << endl);
835 }
836};
837
838void BuildInducedSubgraph_Finalize(atom **&ParentList)
839{
840 delete[](ParentList);
841}
842;
843
844bool BuildInducedSubgraph_CreateBondsFromParent(molecule *mol, const molecule *Father, atom **&ParentList)
845{
846 bool status = true;
847 atom *OtherAtom = NULL;
848 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
849 DoLog(3) && (Log() << Verbose(3) << "Creating bonds." << endl);
850 for (molecule::const_iterator iter = Father->begin(); iter != Father->end(); ++iter) {
851 if (ParentList[(*iter)->getNr()] != NULL) {
852 if (ParentList[(*iter)->getNr()]->father != (*iter)) {
853 status = false;
854 } else {
855 const BondList& ListOfBonds = (*iter)->getListOfBonds();
856 for (BondList::const_iterator Runner = ListOfBonds.begin();
857 Runner != ListOfBonds.end();
858 ++Runner) {
859 OtherAtom = (*Runner)->GetOtherAtom((*iter));
860 if (ParentList[OtherAtom->getNr()] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
861 DoLog(4) && (Log() << Verbose(4) << "Endpoints of Bond " << (*Runner) << " are both present: " << ParentList[(*iter)->getNr()]->getName() << " and " << ParentList[OtherAtom->getNr()]->getName() << "." << endl);
862 mol->AddBond(ParentList[(*iter)->getNr()], ParentList[OtherAtom->getNr()], (*Runner)->BondDegree);
863 }
864 }
865 }
866 }
867 }
868 return status;
869}
870;
871
872/** Adds bond structure to this molecule from \a Father molecule.
873 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
874 * with end points present in this molecule, bond is created in this molecule.
875 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
876 * \param *Father father molecule
877 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
878 * \todo not checked, not fully working probably
879 */
880bool molecule::BuildInducedSubgraph(const molecule *Father){
881 bool status = true;
882 atom **ParentList = NULL;
883 DoLog(2) && (Log() << Verbose(2) << "Begin of BuildInducedSubgraph." << endl);
884 BuildInducedSubgraph_Init(ParentList, Father->getAtomCount());
885 BuildInducedSubgraph_FillParentList(this, Father, ParentList);
886 status = BuildInducedSubgraph_CreateBondsFromParent(this, Father, ParentList);
887 BuildInducedSubgraph_Finalize(ParentList);
888 DoLog(2) && (Log() << Verbose(2) << "End of BuildInducedSubgraph." << endl);
889 return status;
890}
891;
892
893/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
894 * \param *Fragment Keyset of fragment's vertices
895 * \return true - connected, false - disconnected
896 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
897 */
898bool molecule::CheckForConnectedSubgraph(KeySet *Fragment)
899{
900 atom *Walker = NULL, *Walker2 = NULL;
901 bool BondStatus = false;
902 int size;
903
904 DoLog(1) && (Log() << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl);
905 DoLog(2) && (Log() << Verbose(2) << "Disconnected atom: ");
906
907 // count number of atoms in graph
908 size = 0;
909 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
910 size++;
911 if (size > 1)
912 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
913 Walker = FindAtom(*runner);
914 BondStatus = false;
915 for (KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
916 Walker2 = FindAtom(*runners);
917 const BondList& ListOfBonds = Walker->getListOfBonds();
918 for (BondList::const_iterator Runner = ListOfBonds.begin();
919 Runner != ListOfBonds.end();
920 ++Runner) {
921 if ((*Runner)->GetOtherAtom(Walker) == Walker2) {
922 BondStatus = true;
923 break;
924 }
925 if (BondStatus)
926 break;
927 }
928 }
929 if (!BondStatus) {
930 DoLog(0) && (Log() << Verbose(0) << (*Walker) << endl);
931 return false;
932 }
933 }
934 else {
935 DoLog(0) && (Log() << Verbose(0) << "none." << endl);
936 return true;
937 }
938 DoLog(0) && (Log() << Verbose(0) << "none." << endl);
939
940 DoLog(1) && (Log() << Verbose(1) << "End of CheckForConnectedSubgraph" << endl);
941
942 return true;
943}
944
945/** Fills a lookup list of father's Atom::Nr -> atom for each subgraph.
946 * \param *out output stream from debugging
947 * \param **&ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
948 * \param GlobalAtomCount number of atoms in the complete molecule
949 * \return true - success, false - failure (ListOfLocalAtoms != NULL)
950 */
951bool molecule::FillListOfLocalAtoms(atom **&ListOfLocalAtoms, const int GlobalAtomCount)
952{
953 bool status = true;
954
955 if (ListOfLocalAtoms == NULL) { // allocate and fill list of this fragment/subgraph
956 status = status && CreateFatherLookupTable(ListOfLocalAtoms, GlobalAtomCount);
957 } else
958 return false;
959
960 return status;
961}
962
Note: See TracBrowser for help on using the repository browser.