source: src/molecule_graph.cpp@ b8b75d

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 Candidate_v1.7.0 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 b8b75d was b8b75d, checked in by Frederik Heber <heber@…>, 16 years ago

Refactored CreateAdjacencyList().

  • Property mode set to 100644
File size: 53.3 KB
Line 
1/*
2 * molecule_graph.cpp
3 *
4 * Created on: Oct 5, 2009
5 * Author: heber
6 */
7
8#include "atom.hpp"
9#include "bond.hpp"
10#include "config.hpp"
11#include "element.hpp"
12#include "helpers.hpp"
13#include "linkedcell.hpp"
14#include "lists.hpp"
15#include "memoryallocator.hpp"
16#include "molecule.hpp"
17
18/************************************* Functions for class molecule *********************************/
19
20
21/** Creates an adjacency list of the molecule.
22 * We obtain an outside file with the indices of atoms which are bondmembers.
23 */
24void molecule::CreateAdjacencyListFromDbondFile(ofstream *out, ifstream *input)
25{
26
27 // 1 We will parse bonds out of the dbond file created by tremolo.
28 int atom1, atom2;
29 atom *Walker, *OtherWalker;
30
31 if (!input)
32 {
33 cout << Verbose(1) << "Opening silica failed \n";
34 };
35
36 *input >> ws >> atom1;
37 *input >> ws >> atom2;
38 cout << Verbose(1) << "Scanning file\n";
39 while (!input->eof()) // Check whether we read everything already
40 {
41 *input >> ws >> atom1;
42 *input >> ws >> atom2;
43
44 if(atom2<atom1) //Sort indices of atoms in order
45 flip(atom1, atom2);
46 Walker=FindAtom(atom1);
47 OtherWalker=FindAtom(atom2);
48 AddBond(Walker, OtherWalker); //Add the bond between the two atoms with respective indices.
49 }
50
51 CreateListOfBondsPerAtom(out);
52};
53
54
55/** Creates an adjacency list of the molecule.
56 * Generally, we use the CSD approach to bond recognition, that is the the distance
57 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
58 * a threshold t = 0.4 Angstroem.
59 * To make it O(N log N) the function uses the linked-cell technique as follows:
60 * The procedure is step-wise:
61 * -# Remove every bond in list
62 * -# Count the atoms in the molecule with CountAtoms()
63 * -# partition cell into smaller linked cells of size \a bonddistance
64 * -# put each atom into its corresponding cell
65 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true
66 * -# create the list of bonds via CreateListOfBondsPerAtom()
67 * -# correct the bond degree iteratively (single->double->triple bond)
68 * -# finally print the bond list to \a *out if desired
69 * \param *out out stream for printing the matrix, NULL if no output
70 * \param bonddistance length of linked cells (i.e. maximum minimal length checked)
71 * \param IsAngstroem whether coordinate system is gauged to Angstroem or Bohr radii
72 */
73void molecule::CreateAdjacencyList(ofstream *out, double bonddistance, bool IsAngstroem)
74{
75
76 atom *Walker = NULL;
77 atom *OtherWalker = NULL;
78 atom **AtomMap = NULL;
79 int n[NDIM];
80 double distance, MinDistance, MaxDistance;
81 LinkedCell *LC = NULL;
82 LinkedNodes *List = NULL;
83 LinkedNodes *OtherList = NULL;
84
85 BondDistance = bonddistance; // * ((IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem);
86 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl;
87 // remove every bond from the list
88 if ((first->next != last) && (last->previous != first)) { // there are bonds present
89 cleanup(first,last);
90 }
91
92 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering)
93 CountAtoms(out);
94 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl;
95
96 if (AtomCount != 0) {
97 LC = new LinkedCell(this, bonddistance);
98
99 // create a list to map Tesselpoint::nr to atom *
100 AtomMap = Malloc<atom *>(AtomCount, "molecule::CreateAdjacencyList - **AtomCount");
101 Walker = start;
102 while (Walker->next != end) {
103 Walker = Walker->next;
104 AtomMap[Walker->nr] = Walker;
105 }
106
107 // 3a. go through every cell
108 for (LC->n[0] = 0; LC->n[0] < LC->N[0]; LC->n[0]++)
109 for (LC->n[1] = 0; LC->n[1] < LC->N[1]; LC->n[1]++)
110 for (LC->n[2] = 0; LC->n[2] < LC->N[2]; LC->n[2]++) {
111 List = LC->GetCurrentCell();
112 //*out << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << " containing " << List->size() << " points." << endl;
113 if (List != NULL) {
114 for (LinkedNodes::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
115 Walker = AtomMap[(*Runner)->nr];
116 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl;
117 // 3c. check for possible bond between each atom in this and every one in the 27 cells
118 for (n[0]=-1;n[0]<=1;n[0]++)
119 for (n[1]=-1;n[1]<=1;n[1]++)
120 for (n[2]=-1;n[2]<=1;n[2]++) {
121 OtherList = LC->GetRelativeToCurrentCell(n);
122 //*out << Verbose(2) << "Current relative cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << " containing " << List->size() << " points." << endl;
123 if (OtherList != NULL) {
124 for (LinkedNodes::iterator OtherRunner = OtherList->begin(); OtherRunner != OtherList->end(); OtherRunner++) {
125 if ((*OtherRunner)->nr > Walker->nr) {
126 OtherWalker = AtomMap[(*OtherRunner)->nr];
127 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl;
128 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius;
129 MinDistance *= (IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem;
130 MaxDistance = MinDistance + BONDTHRESHOLD;
131 MinDistance -= BONDTHRESHOLD;
132 distance = OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size);
133 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance*MaxDistance) && (distance >= MinDistance*MinDistance)) { // create bond if distance is smaller
134 //*out << Verbose(1) << "Adding Bond between " << *Walker << " and " << *OtherWalker << " in distance " << sqrt(distance) << "." << endl;
135 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount
136 } else {
137 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl;
138 }
139 }
140 }
141 }
142 }
143 }
144 }
145 }
146 Free(&AtomMap);
147 delete(LC);
148 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << BondDistance << "." << endl;
149
150 // create the adjacency list per atom
151 CreateListOfBondsPerAtom(out);
152
153 // correct bond degree by comparing valence and bond degree
154 CorrectBondDegree(out);
155
156 // output bonds for debugging (if bond chain list was correctly installed)
157 OutputBondsList(out);
158 } else
159 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl;
160 *out << Verbose(0) << "End of CreateAdjacencyList." << endl;
161};
162
163/** Prints a list of all bonds to \a *out.
164 * \param output stream
165 */
166void molecule::OutputBondsList(ofstream *out)
167{
168 *out << Verbose(1) << endl << "From contents of bond chain list:";
169 bond *Binder = first;
170 while(Binder->next != last) {
171 Binder = Binder->next;
172 *out << *Binder << "\t" << endl;
173 }
174 *out << endl;
175};
176
177/** Sums up the number of bonds times bond::BondDegree the atom with index \a nr has.
178 * \param nr indexof atom
179 * \return number of bonds each weighted with its bond::BondDegree
180 */
181int molecule::CountAtomsBonds(int nr)
182{
183 int NoBonds = 0;
184 for(int j=0;j<NumberOfBondsPerAtom[nr];j++)
185 NoBonds += ListOfBondsPerAtom[nr][j]->BondDegree;
186 return NoBonds;
187};
188
189/** correct bond degree by comparing valence and bond degree.
190 * correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees,
191 * iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene
192 * preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of
193 * double bonds as was expected.
194 * \param *out output stream for debugging
195 * \return number of bonds that could not be corrected
196 */
197int molecule::CorrectBondDegree(ofstream *out)
198{
199 int No = 0;
200 int NoBonds = 0;
201 int CandidateBondNo = 0;
202 int FalseBondDegree = 0;
203 atom *Walker = NULL;
204 atom *Candidate = NULL;
205 atom *OtherWalker = NULL;
206
207 if (BondCount != 0) {
208 NoCyclicBonds = 0;
209 *out << Verbose(1) << "Correcting Bond degree of each bond ... ";
210 do {
211 No = 0; // No acts as breakup flag (if 1 we still continue)
212 Walker = start;
213 while (Walker->next != end) { // go through every atom
214 Walker = Walker->next;
215
216 NoBonds = CountAtomsBonds(Walker->nr);
217 *out << Verbose(3) << "Walker " << *Walker << ": " << (int)Walker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
218 if ((int)(Walker->type->NoValenceOrbitals) > NoBonds) { // we have a mismatch, check all bonding partners for mismatch
219 Candidate = NULL;
220 CandidateBondNo = -1;
221 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through each of its bond partners
222 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
223 NoBonds = CountAtomsBonds(OtherWalker->nr);
224 *out << Verbose(3) << "OtherWalker " << *OtherWalker << ": " << (int)OtherWalker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
225 if ((int)(OtherWalker->type->NoValenceOrbitals) > NoBonds) { // check if possible candidate
226 if ((Candidate == NULL) || (NumberOfBondsPerAtom[Candidate->nr] > NumberOfBondsPerAtom[OtherWalker->nr])) { // pick the one with fewer number of bonds first
227 Candidate = OtherWalker;
228 CandidateBondNo = i;
229 *out << Verbose(3) << "New candidate is " << *Candidate << "." << endl;
230 }
231 }
232 }
233 if ((Candidate != NULL) && (CandidateBondNo != -1)) {
234 ListOfBondsPerAtom[Walker->nr][CandidateBondNo]->BondDegree++;
235 *out << Verbose(2) << "Increased bond degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl;
236 } else {
237 *out << Verbose(2) << "Could not find correct degree for atom " << *Walker << "." << endl;
238 FalseBondDegree++;
239 }
240 }
241 }
242 } while (No);
243 *out << " done." << endl;
244 } else {
245 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl;
246 }
247 *out << FalseBondDegree << " bonds could not be corrected." << endl;
248
249 return (FalseBondDegree);
250};
251
252/** Counts all cyclic bonds and returns their number.
253 * \note Hydrogen bonds can never by cyclic, thus no check for that
254 * \param *out output stream for debugging
255 * \return number opf cyclic bonds
256 */
257int molecule::CountCyclicBonds(ofstream *out)
258{
259 int No = 0;
260 int *MinimumRingSize = NULL;
261 MoleculeLeafClass *Subgraphs = NULL;
262 class StackClass<bond *> *BackEdgeStack = NULL;
263 bond *Binder = first;
264 if ((Binder->next != last) && (Binder->next->Type == Undetermined)) {
265 *out << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl;
266 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack);
267 while (Subgraphs->next != NULL) {
268 Subgraphs = Subgraphs->next;
269 delete(Subgraphs->previous);
270 }
271 delete(Subgraphs);
272 delete[](MinimumRingSize);
273 }
274 while(Binder->next != last) {
275 Binder = Binder->next;
276 if (Binder->Cyclic)
277 No++;
278 }
279 delete(BackEdgeStack);
280 return No;
281};
282
283
284/** Returns Shading as a char string.
285 * \param color the Shading
286 * \return string of the flag
287 */
288string molecule::GetColor(enum Shading color)
289{
290 switch(color) {
291 case white:
292 return "white";
293 break;
294 case lightgray:
295 return "lightgray";
296 break;
297 case darkgray:
298 return "darkgray";
299 break;
300 case black:
301 return "black";
302 break;
303 default:
304 return "uncolored";
305 break;
306 };
307};
308
309/** Performs a Depth-First search on this molecule.
310 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
311 * articulations points, ...
312 * We use the algorithm from [Even, Graph Algorithms, p.62].
313 * \param *out output stream for debugging
314 * \param *&BackEdgeStack NULL pointer to StackClass with all the found back edges, allocated and filled on return
315 * \return list of each disconnected subgraph as an individual molecule class structure
316 */
317MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, class StackClass<bond *> *&BackEdgeStack)
318{
319 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
320 BackEdgeStack = new StackClass<bond *> (BondCount);
321 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
322 MoleculeLeafClass *LeafWalker = SubGraphs;
323 int CurrentGraphNr = 0, OldGraphNr;
324 int ComponentNumber = 0;
325 atom *Walker = NULL, *OtherAtom = NULL, *Root = start->next;
326 bond *Binder = NULL;
327 bool BackStepping = false;
328
329 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl;
330
331 ResetAllBondsToUnused();
332 ResetAllAtomNumbers();
333 InitComponentNumbers();
334 BackEdgeStack->ClearStack();
335 while (Root != end) { // if there any atoms at all
336 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all
337 AtomStack->ClearStack();
338
339 // put into new subgraph molecule and add this to list of subgraphs
340 LeafWalker = new MoleculeLeafClass(LeafWalker);
341 LeafWalker->Leaf = new molecule(elemente);
342 LeafWalker->Leaf->AddCopyAtom(Root);
343
344 OldGraphNr = CurrentGraphNr;
345 Walker = Root;
346 do { // (10)
347 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
348 if (!BackStepping) { // if we don't just return from (8)
349 Walker->GraphNr = CurrentGraphNr;
350 Walker->LowpointNr = CurrentGraphNr;
351 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl;
352 AtomStack->Push(Walker);
353 CurrentGraphNr++;
354 }
355 do { // (3) if Walker has no unused egdes, go to (5)
356 BackStepping = false; // reset backstepping flag for (8)
357 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
358 Binder = FindNextUnused(Walker);
359 if (Binder == NULL)
360 break;
361 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl;
362 // (4) Mark Binder used, ...
363 Binder->MarkUsed(black);
364 OtherAtom = Binder->GetOtherAtom(Walker);
365 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl;
366 if (OtherAtom->GraphNr != -1) {
367 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
368 Binder->Type = BackEdge;
369 BackEdgeStack->Push(Binder);
370 Walker->LowpointNr = ( Walker->LowpointNr < OtherAtom->GraphNr ) ? Walker->LowpointNr : OtherAtom->GraphNr;
371 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl;
372 } else {
373 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
374 Binder->Type = TreeEdge;
375 OtherAtom->Ancestor = Walker;
376 Walker = OtherAtom;
377 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl;
378 break;
379 }
380 Binder = NULL;
381 } while (1); // (3)
382 if (Binder == NULL) {
383 *out << Verbose(2) << "No more Unused Bonds." << endl;
384 break;
385 } else
386 Binder = NULL;
387 } while (1); // (2)
388
389 // 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!
390 if ((Walker == Root) && (Binder == NULL))
391 break;
392
393 // (5) if Ancestor of Walker is ...
394 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl;
395 if (Walker->Ancestor->GraphNr != Root->GraphNr) {
396 // (6) (Ancestor of Walker is not Root)
397 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
398 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
399 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
400 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl;
401 } else {
402 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
403 Walker->Ancestor->SeparationVertex = true;
404 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl;
405 SetNextComponentNumber(Walker->Ancestor, ComponentNumber);
406 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << ComponentNumber << "." << endl;
407 SetNextComponentNumber(Walker, ComponentNumber);
408 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << ComponentNumber << "." << endl;
409 do {
410 OtherAtom = AtomStack->PopLast();
411 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
412 SetNextComponentNumber(OtherAtom, ComponentNumber);
413 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
414 } while (OtherAtom != Walker);
415 ComponentNumber++;
416 }
417 // (8) Walker becomes its Ancestor, go to (3)
418 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl;
419 Walker = Walker->Ancestor;
420 BackStepping = true;
421 }
422 if (!BackStepping) { // coming from (8) want to go to (3)
423 // (9) remove all from stack till Walker (including), these and Root form a component
424 AtomStack->Output(out);
425 SetNextComponentNumber(Root, ComponentNumber);
426 *out << Verbose(3) << "(9) Root[" << Root->Name << "]'s Component is " << ComponentNumber << "." << endl;
427 SetNextComponentNumber(Walker, ComponentNumber);
428 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << ComponentNumber << "." << endl;
429 do {
430 OtherAtom = AtomStack->PopLast();
431 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
432 SetNextComponentNumber(OtherAtom, ComponentNumber);
433 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
434 } while (OtherAtom != Walker);
435 ComponentNumber++;
436
437 // (11) Root is separation vertex, set Walker to Root and go to (4)
438 Walker = Root;
439 Binder = FindNextUnused(Walker);
440 *out << Verbose(1) << "(10) Walker is Root[" << Root->Name << "], next Unused Bond is " << Binder << "." << endl;
441 if (Binder != NULL) { // Root is separation vertex
442 *out << Verbose(1) << "(11) Root is a separation vertex." << endl;
443 Walker->SeparationVertex = true;
444 }
445 }
446 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
447
448 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
449 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << CurrentGraphNr << "." << endl;
450 LeafWalker->Leaf->Output(out);
451 *out << endl;
452
453 // step on to next root
454 while ((Root != end) && (Root->GraphNr != -1)) {
455 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl;
456 if (Root->GraphNr != -1) // if already discovered, step on
457 Root = Root->next;
458 }
459 }
460 // set cyclic bond criterium on "same LP" basis
461 Binder = first;
462 while(Binder->next != last) {
463 Binder = Binder->next;
464 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ??
465 Binder->Cyclic = true;
466 NoCyclicBonds++;
467 }
468 }
469
470
471 *out << Verbose(1) << "Final graph info for each atom is:" << endl;
472 Walker = start;
473 while (Walker->next != end) {
474 Walker = Walker->next;
475 *out << Verbose(2) << "Atom " << Walker->Name << " is " << ((Walker->SeparationVertex) ? "a" : "not a") << " separation vertex, components are ";
476 OutputComponentNumber(out, Walker);
477 *out << " with Lowpoint " << Walker->LowpointNr << " and Graph Nr. " << Walker->GraphNr << "." << endl;
478 }
479
480 *out << Verbose(1) << "Final graph info for each bond is:" << endl;
481 Binder = first;
482 while(Binder->next != last) {
483 Binder = Binder->next;
484 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
485 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
486 OutputComponentNumber(out, Binder->leftatom);
487 *out << " === ";
488 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
489 OutputComponentNumber(out, Binder->rightatom);
490 *out << ">." << endl;
491 if (Binder->Cyclic) // cyclic ??
492 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl;
493 }
494
495 // free all and exit
496 delete(AtomStack);
497 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl;
498 return SubGraphs;
499};
500
501/** Analyses the cycles found and returns minimum of all cycle lengths.
502 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
503 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
504 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
505 * as cyclic and print out the cycles.
506 * \param *out output stream for debugging
507 * \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!
508 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
509 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
510 */
511void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize)
512{
513 atom **PredecessorList = Malloc<atom*>(AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList");
514 int *ShortestPathList = Malloc<int>(AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList");
515 enum Shading *ColorList = Malloc<enum Shading>(AtomCount, "molecule::CyclicStructureAnalysis: *ColorList");
516 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring
517 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop)
518 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL;
519 bond *Binder = NULL, *BackEdge = NULL;
520 int RingSize, NumCycles, MinRingSize = -1;
521
522 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
523 for (int i=AtomCount;i--;) {
524 PredecessorList[i] = NULL;
525 ShortestPathList[i] = -1;
526 ColorList[i] = white;
527 }
528
529 *out << Verbose(1) << "Back edge list - ";
530 BackEdgeStack->Output(out);
531
532 *out << Verbose(1) << "Analysing cycles ... " << endl;
533 NumCycles = 0;
534 while (!BackEdgeStack->IsEmpty()) {
535 BackEdge = BackEdgeStack->PopFirst();
536 // this is the target
537 Root = BackEdge->leftatom;
538 // this is the source point
539 Walker = BackEdge->rightatom;
540 ShortestPathList[Walker->nr] = 0;
541 BFSStack->ClearStack(); // start with empty BFS stack
542 BFSStack->Push(Walker);
543 TouchedStack->Push(Walker);
544 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
545 OtherAtom = NULL;
546 do { // look for Root
547 Walker = BFSStack->PopFirst();
548 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
549 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
550 Binder = ListOfBondsPerAtom[Walker->nr][i];
551 if (Binder != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
552 OtherAtom = Binder->GetOtherAtom(Walker);
553#ifdef ADDHYDROGEN
554 if (OtherAtom->type->Z != 1) {
555#endif
556 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
557 if (ColorList[OtherAtom->nr] == white) {
558 TouchedStack->Push(OtherAtom);
559 ColorList[OtherAtom->nr] = lightgray;
560 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
561 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
562 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
563 //if (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
564 *out << Verbose(3) << "Putting OtherAtom into queue." << endl;
565 BFSStack->Push(OtherAtom);
566 //}
567 } else {
568 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
569 }
570 if (OtherAtom == Root)
571 break;
572#ifdef ADDHYDROGEN
573 } else {
574 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl;
575 ColorList[OtherAtom->nr] = black;
576 }
577#endif
578 } else {
579 *out << Verbose(2) << "Bond " << *Binder << " not Visiting, is the back edge." << endl;
580 }
581 }
582 ColorList[Walker->nr] = black;
583 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
584 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
585 // step through predecessor list
586 while (OtherAtom != BackEdge->rightatom) {
587 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
588 break;
589 else
590 OtherAtom = PredecessorList[OtherAtom->nr];
591 }
592 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
593 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;\
594 do {
595 OtherAtom = TouchedStack->PopLast();
596 if (PredecessorList[OtherAtom->nr] == Walker) {
597 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl;
598 PredecessorList[OtherAtom->nr] = NULL;
599 ShortestPathList[OtherAtom->nr] = -1;
600 ColorList[OtherAtom->nr] = white;
601 BFSStack->RemoveItem(OtherAtom);
602 }
603 } while ((!TouchedStack->IsEmpty()) && (PredecessorList[OtherAtom->nr] == NULL));
604 TouchedStack->Push(OtherAtom); // last was wrongly popped
605 OtherAtom = BackEdge->rightatom; // set to not Root
606 } else
607 OtherAtom = Root;
608 }
609 } while ((!BFSStack->IsEmpty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr])));
610
611 if (OtherAtom == Root) {
612 // now climb back the predecessor list and thus find the cycle members
613 NumCycles++;
614 RingSize = 1;
615 Root->GetTrueFather()->IsCyclic = true;
616 *out << Verbose(1) << "Found ring contains: ";
617 Walker = Root;
618 while (Walker != BackEdge->rightatom) {
619 *out << Walker->Name << " <-> ";
620 Walker = PredecessorList[Walker->nr];
621 Walker->GetTrueFather()->IsCyclic = true;
622 RingSize++;
623 }
624 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl;
625 // walk through all and set MinimumRingSize
626 Walker = Root;
627 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
628 while (Walker != BackEdge->rightatom) {
629 Walker = PredecessorList[Walker->nr];
630 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr])
631 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
632 }
633 if ((RingSize < MinRingSize) || (MinRingSize == -1))
634 MinRingSize = RingSize;
635 } else {
636 *out << Verbose(1) << "No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl;
637 }
638
639 // now clean the lists
640 while (!TouchedStack->IsEmpty()){
641 Walker = TouchedStack->PopFirst();
642 PredecessorList[Walker->nr] = NULL;
643 ShortestPathList[Walker->nr] = -1;
644 ColorList[Walker->nr] = white;
645 }
646 }
647 if (MinRingSize != -1) {
648 // go over all atoms
649 Root = start;
650 while(Root->next != end) {
651 Root = Root->next;
652
653 if (MinimumRingSize[Root->GetTrueFather()->nr] == AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is
654 Walker = Root;
655 ShortestPathList[Walker->nr] = 0;
656 BFSStack->ClearStack(); // start with empty BFS stack
657 BFSStack->Push(Walker);
658 TouchedStack->Push(Walker);
659 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
660 OtherAtom = Walker;
661 while (OtherAtom != NULL) { // look for Root
662 Walker = BFSStack->PopFirst();
663 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
664 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
665 Binder = ListOfBondsPerAtom[Walker->nr][i];
666 if ((Binder != BackEdge) || (NumberOfBondsPerAtom[Walker->nr] == 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
667 OtherAtom = Binder->GetOtherAtom(Walker);
668 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
669 if (ColorList[OtherAtom->nr] == white) {
670 TouchedStack->Push(OtherAtom);
671 ColorList[OtherAtom->nr] = lightgray;
672 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
673 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
674 //*out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
675 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
676 MinimumRingSize[Root->GetTrueFather()->nr] = ShortestPathList[OtherAtom->nr]+MinimumRingSize[OtherAtom->GetTrueFather()->nr];
677 OtherAtom = NULL; //break;
678 break;
679 } else
680 BFSStack->Push(OtherAtom);
681 } else {
682 //*out << Verbose(3) << "Not Adding, has already been visited." << endl;
683 }
684 } else {
685 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl;
686 }
687 }
688 ColorList[Walker->nr] = black;
689 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
690 }
691
692 // now clean the lists
693 while (!TouchedStack->IsEmpty()){
694 Walker = TouchedStack->PopFirst();
695 PredecessorList[Walker->nr] = NULL;
696 ShortestPathList[Walker->nr] = -1;
697 ColorList[Walker->nr] = white;
698 }
699 }
700 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl;
701 }
702 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl;
703 } else
704 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
705
706 Free(&PredecessorList);
707 Free(&ShortestPathList);
708 Free(&ColorList);
709 delete(BFSStack);
710};
711
712/** Sets the next component number.
713 * This is O(N) as the number of bonds per atom is bound.
714 * \param *vertex atom whose next atom::*ComponentNr is to be set
715 * \param nr number to use
716 */
717void molecule::SetNextComponentNumber(atom *vertex, int nr)
718{
719 int i=0;
720 if (vertex != NULL) {
721 for(;i<NumberOfBondsPerAtom[vertex->nr];i++) {
722 if (vertex->ComponentNr[i] == -1) { // check if not yet used
723 vertex->ComponentNr[i] = nr;
724 break;
725 }
726 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
727 break; // breaking here will not cause error!
728 }
729 if (i == NumberOfBondsPerAtom[vertex->nr])
730 cerr << "Error: All Component entries are already occupied!" << endl;
731 } else
732 cerr << "Error: Given vertex is NULL!" << endl;
733};
734
735/** Output a list of flags, stating whether the bond was visited or not.
736 * \param *out output stream for debugging
737 */
738void molecule::OutputComponentNumber(ofstream *out, atom *vertex)
739{
740 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
741 *out << vertex->ComponentNr[i] << " ";
742};
743
744/** Allocates memory for all atom::*ComponentNr in this molecule and sets each entry to -1.
745 */
746void molecule::InitComponentNumbers()
747{
748 atom *Walker = start;
749 while(Walker->next != end) {
750 Walker = Walker->next;
751 if (Walker->ComponentNr != NULL)
752 Free(&Walker->ComponentNr);
753 Walker->ComponentNr = Malloc<int>(NumberOfBondsPerAtom[Walker->nr], "molecule::InitComponentNumbers: *Walker->ComponentNr");
754 for (int i=NumberOfBondsPerAtom[Walker->nr];i--;)
755 Walker->ComponentNr[i] = -1;
756 }
757};
758
759/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
760 * \param *vertex atom to regard
761 * \return bond class or NULL
762 */
763bond * molecule::FindNextUnused(atom *vertex)
764{
765 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
766 if (ListOfBondsPerAtom[vertex->nr][i]->IsUsed() == white)
767 return(ListOfBondsPerAtom[vertex->nr][i]);
768 return NULL;
769};
770
771/** Resets bond::Used flag of all bonds in this molecule.
772 * \return true - success, false - -failure
773 */
774void molecule::ResetAllBondsToUnused()
775{
776 bond *Binder = first;
777 while (Binder->next != last) {
778 Binder = Binder->next;
779 Binder->ResetUsed();
780 }
781};
782
783/** Resets atom::nr to -1 of all atoms in this molecule.
784 */
785void molecule::ResetAllAtomNumbers()
786{
787 atom *Walker = start;
788 while (Walker->next != end) {
789 Walker = Walker->next;
790 Walker->GraphNr = -1;
791 }
792};
793
794/** Output a list of flags, stating whether the bond was visited or not.
795 * \param *out output stream for debugging
796 * \param *list
797 */
798void OutputAlreadyVisited(ofstream *out, int *list)
799{
800 *out << Verbose(4) << "Already Visited Bonds:\t";
801 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " ";
802 *out << endl;
803};
804
805
806/** Storing the bond structure of a molecule to file.
807 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
808 * \param *out output stream for debugging
809 * \param *path path to file
810 * \return true - file written successfully, false - writing failed
811 */
812bool molecule::StoreAdjacencyToFile(ofstream *out, char *path)
813{
814 ofstream AdjacencyFile;
815 atom *Walker = NULL;
816 stringstream line;
817 bool status = true;
818
819 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
820 AdjacencyFile.open(line.str().c_str(), ios::out);
821 *out << Verbose(1) << "Saving adjacency list ... ";
822 if (AdjacencyFile != NULL) {
823 Walker = start;
824 while(Walker->next != end) {
825 Walker = Walker->next;
826 AdjacencyFile << Walker->nr << "\t";
827 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
828 AdjacencyFile << ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker)->nr << "\t";
829 AdjacencyFile << endl;
830 }
831 AdjacencyFile.close();
832 *out << Verbose(1) << "done." << endl;
833 } else {
834 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
835 status = false;
836 }
837
838 return status;
839};
840
841/** Checks contents of adjacency file against bond structure in structure molecule.
842 * \param *out output stream for debugging
843 * \param *path path to file
844 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
845 * \return true - structure is equal, false - not equivalence
846 */
847bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms)
848{
849 ifstream File;
850 stringstream filename;
851 bool status = true;
852 char *buffer = Malloc<char>(MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
853
854 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
855 File.open(filename.str().c_str(), ios::out);
856 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... ";
857 if (File != NULL) {
858 // allocate storage structure
859 int NonMatchNumber = 0; // will number of atoms with differing bond structure
860 int *CurrentBonds = Malloc<int>(8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
861 int CurrentBondsOfAtom;
862
863 // Parse the file line by line and count the bonds
864 while (!File.eof()) {
865 File.getline(buffer, MAXSTRINGSIZE);
866 stringstream line;
867 line.str(buffer);
868 int AtomNr = -1;
869 line >> AtomNr;
870 CurrentBondsOfAtom = -1; // we count one too far due to line end
871 // parse into structure
872 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
873 while (!line.eof())
874 line >> CurrentBonds[ ++CurrentBondsOfAtom ];
875 // compare against present bonds
876 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
877 if (CurrentBondsOfAtom == NumberOfBondsPerAtom[AtomNr]) {
878 for(int i=0;i<NumberOfBondsPerAtom[AtomNr];i++) {
879 int id = ListOfBondsPerAtom[AtomNr][i]->GetOtherAtom(ListOfAtoms[AtomNr])->nr;
880 int j = 0;
881 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds
882 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms
883 ListOfAtoms[AtomNr] = NULL;
884 NonMatchNumber++;
885 status = false;
886 //out << "[" << id << "]\t";
887 } else {
888 //out << id << "\t";
889 }
890 }
891 //out << endl;
892 } else {
893 *out << "Number of bonds for Atom " << *ListOfAtoms[AtomNr] << " does not match, parsed " << CurrentBondsOfAtom << " against " << NumberOfBondsPerAtom[AtomNr] << "." << endl;
894 status = false;
895 }
896 }
897 }
898 File.close();
899 File.clear();
900 if (status) { // if equal we parse the KeySetFile
901 *out << Verbose(1) << "done: Equal." << endl;
902 status = true;
903 } else
904 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
905 Free(&CurrentBonds);
906 } else {
907 *out << Verbose(1) << "Adjacency file not found." << endl;
908 status = false;
909 }
910 *out << endl;
911 Free(&buffer);
912
913 return status;
914};
915
916
917/** Picks from a global stack with all back edges the ones in the fragment.
918 * \param *out output stream for debugging
919 * \param **ListOfLocalAtoms array of father atom::nr to local atom::nr (reverse of atom::father)
920 * \param *ReferenceStack stack with all the back egdes
921 * \param *LocalStack stack to be filled
922 * \return true - everything ok, false - ReferenceStack was empty
923 */
924bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack)
925{
926 bool status = true;
927 if (ReferenceStack->IsEmpty()) {
928 cerr << "ReferenceStack is empty!" << endl;
929 return false;
930 }
931 bond *Binder = ReferenceStack->PopFirst();
932 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
933 atom *Walker = NULL, *OtherAtom = NULL;
934 ReferenceStack->Push(Binder);
935
936 do { // go through all bonds and push local ones
937 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule
938 if (Walker != NULL) // if this Walker exists in the subgraph ...
939 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through the local list of bonds
940 OtherAtom = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
941 if (OtherAtom == ListOfLocalAtoms[Binder->rightatom->nr]) { // found the bond
942 LocalStack->Push(ListOfBondsPerAtom[Walker->nr][i]);
943 *out << Verbose(3) << "Found local edge " << *(ListOfBondsPerAtom[Walker->nr][i]) << "." << endl;
944 break;
945 }
946 }
947 Binder = ReferenceStack->PopFirst(); // loop the stack for next item
948 *out << Verbose(3) << "Current candidate edge " << Binder << "." << endl;
949 ReferenceStack->Push(Binder);
950 } while (FirstBond != Binder);
951
952 return status;
953};
954
955
956/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
957 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
958 * white and putting into queue.
959 * \param *out output stream for debugging
960 * \param *Mol Molecule class to add atoms to
961 * \param **AddedAtomList list with added atom pointers, index is atom father's number
962 * \param **AddedBondList list with added bond pointers, index is bond father's number
963 * \param *Root root vertex for BFS
964 * \param *Bond bond not to look beyond
965 * \param BondOrder maximum distance for vertices to add
966 * \param IsAngstroem lengths are in angstroem or bohrradii
967 */
968void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
969{
970 atom **PredecessorList = Malloc<atom*>(AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList");
971 int *ShortestPathList = Malloc<int>(AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList");
972 enum Shading *ColorList = Malloc<enum Shading>(AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList");
973 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
974 atom *Walker = NULL, *OtherAtom = NULL;
975 bond *Binder = NULL;
976
977 // add Root if not done yet
978 AtomStack->ClearStack();
979 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
980 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
981 AtomStack->Push(Root);
982
983 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
984 for (int i=AtomCount;i--;) {
985 PredecessorList[i] = NULL;
986 ShortestPathList[i] = -1;
987 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited
988 ColorList[i] = lightgray;
989 else
990 ColorList[i] = white;
991 }
992 ShortestPathList[Root->nr] = 0;
993
994 // and go on ... Queue always contains all lightgray vertices
995 while (!AtomStack->IsEmpty()) {
996 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
997 // e.g. if current atom is 2, push to end of stack are of length 3, but first all of length 2 would be popped. They again
998 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
999 // followed by n+1 till top of stack.
1000 Walker = AtomStack->PopFirst(); // pop oldest added
1001 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl;
1002 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
1003 Binder = ListOfBondsPerAtom[Walker->nr][i];
1004 if (Binder != NULL) { // don't look at bond equal NULL
1005 OtherAtom = Binder->GetOtherAtom(Walker);
1006 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
1007 if (ColorList[OtherAtom->nr] == white) {
1008 if (Binder != Bond) // let other atom white if it's via Root bond. In case it's cyclic it has to be reached again (yet Root is from OtherAtom already black, thus no problem)
1009 ColorList[OtherAtom->nr] = lightgray;
1010 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
1011 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
1012 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " " << ((ColorList[OtherAtom->nr] == white) ? "white" : "lightgray") << ", its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
1013 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance
1014 *out << Verbose(3);
1015 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
1016 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
1017 *out << "Added OtherAtom " << OtherAtom->Name;
1018 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
1019 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
1020 AddedBondList[Binder->nr]->Type = Binder->Type;
1021 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
1022 } else { // this code should actually never come into play (all white atoms are not yet present in BondMolecule, that's why they are white in the first place)
1023 *out << "Not adding OtherAtom " << OtherAtom->Name;
1024 if (AddedBondList[Binder->nr] == NULL) {
1025 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
1026 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
1027 AddedBondList[Binder->nr]->Type = Binder->Type;
1028 *out << ", added Bond " << *(AddedBondList[Binder->nr]);
1029 } else
1030 *out << ", not added Bond ";
1031 }
1032 *out << ", putting OtherAtom into queue." << endl;
1033 AtomStack->Push(OtherAtom);
1034 } else { // out of bond order, then replace
1035 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
1036 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
1037 if (Binder == Bond)
1038 *out << Verbose(3) << "Not Queueing, is the Root bond";
1039 else if (ShortestPathList[OtherAtom->nr] >= BondOrder)
1040 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder;
1041 if (!Binder->Cyclic)
1042 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
1043 if (AddedBondList[Binder->nr] == NULL) {
1044 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
1045 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
1046 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
1047 AddedBondList[Binder->nr]->Type = Binder->Type;
1048 } else {
1049#ifdef ADDHYDROGEN
1050 if (!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem))
1051 exit(1);
1052#endif
1053 }
1054 }
1055 }
1056 } else {
1057 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
1058 // This has to be a cyclic bond, check whether it's present ...
1059 if (AddedBondList[Binder->nr] == NULL) {
1060 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) {
1061 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
1062 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
1063 AddedBondList[Binder->nr]->Type = Binder->Type;
1064 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
1065#ifdef ADDHYDROGEN
1066 if(!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem))
1067 exit(1);
1068#endif
1069 }
1070 }
1071 }
1072 }
1073 }
1074 ColorList[Walker->nr] = black;
1075 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
1076 }
1077 Free(&PredecessorList);
1078 Free(&ShortestPathList);
1079 Free(&ColorList);
1080 delete(AtomStack);
1081};
1082
1083/** Adds bond structure to this molecule from \a Father molecule.
1084 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
1085 * with end points present in this molecule, bond is created in this molecule.
1086 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
1087 * \param *out output stream for debugging
1088 * \param *Father father molecule
1089 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
1090 * \todo not checked, not fully working probably
1091 */
1092bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
1093{
1094 atom *Walker = NULL, *OtherAtom = NULL;
1095 bool status = true;
1096 atom **ParentList = Malloc<atom*>(Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList");
1097
1098 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
1099
1100 // reset parent list
1101 *out << Verbose(3) << "Resetting ParentList." << endl;
1102 for (int i=Father->AtomCount;i--;)
1103 ParentList[i] = NULL;
1104
1105 // fill parent list with sons
1106 *out << Verbose(3) << "Filling Parent List." << endl;
1107 Walker = start;
1108 while (Walker->next != end) {
1109 Walker = Walker->next;
1110 ParentList[Walker->father->nr] = Walker;
1111 // Outputting List for debugging
1112 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
1113 }
1114
1115 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
1116 *out << Verbose(3) << "Creating bonds." << endl;
1117 Walker = Father->start;
1118 while (Walker->next != Father->end) {
1119 Walker = Walker->next;
1120 if (ParentList[Walker->nr] != NULL) {
1121 if (ParentList[Walker->nr]->father != Walker) {
1122 status = false;
1123 } else {
1124 for (int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) {
1125 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
1126 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
1127 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i] << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
1128 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree);
1129 }
1130 }
1131 }
1132 }
1133 }
1134
1135 Free(&ParentList);
1136 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
1137 return status;
1138};
1139
1140
1141/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
1142 * \param *out output stream for debugging
1143 * \param *Fragment Keyset of fragment's vertices
1144 * \return true - connected, false - disconnected
1145 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
1146 */
1147bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment)
1148{
1149 atom *Walker = NULL, *Walker2 = NULL;
1150 bool BondStatus = false;
1151 int size;
1152
1153 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
1154 *out << Verbose(2) << "Disconnected atom: ";
1155
1156 // count number of atoms in graph
1157 size = 0;
1158 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
1159 size++;
1160 if (size > 1)
1161 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
1162 Walker = FindAtom(*runner);
1163 BondStatus = false;
1164 for(KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
1165 Walker2 = FindAtom(*runners);
1166 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
1167 if (ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker) == Walker2) {
1168 BondStatus = true;
1169 break;
1170 }
1171 if (BondStatus)
1172 break;
1173 }
1174 }
1175 if (!BondStatus) {
1176 *out << (*Walker) << endl;
1177 return false;
1178 }
1179 }
1180 else {
1181 *out << "none." << endl;
1182 return true;
1183 }
1184 *out << "none." << endl;
1185
1186 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
1187
1188 return true;
1189}
Note: See TracBrowser for help on using the repository browser.