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
RevLine 
[bcf653]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
[cee0b57]8/*
9 * molecule_graph.cpp
10 *
11 * Created on: Oct 5, 2009
12 * Author: heber
13 */
14
[bf3817]15// include config.h
[aafd77]16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
[ad011c]20#include "CodePatterns/MemDebug.hpp"
[112b09]21
[a564be]22#include <stack>
23
[f66195]24#include "atom.hpp"
[129204]25#include "Bond/bond.hpp"
[34c43a]26#include "Box.hpp"
27#include "CodePatterns/Assert.hpp"
28#include "CodePatterns/Info.hpp"
29#include "CodePatterns/Log.hpp"
30#include "CodePatterns/Verbose.hpp"
[cee0b57]31#include "config.hpp"
[f66195]32#include "element.hpp"
[129204]33#include "Graph/BondGraph.hpp"
[1d5afa5]34#include "Helpers/defs.hpp"
35#include "Helpers/fast_functions.hpp"
[952f38]36#include "Helpers/helpers.hpp"
[1d5afa5]37#include "LinearAlgebra/RealSpaceMatrix.hpp"
[b8b75d]38#include "linkedcell.hpp"
[cee0b57]39#include "molecule.hpp"
[34c43a]40#include "PointCloudAdaptor.hpp"
[b34306]41#include "World.hpp"
[9d83b6]42#include "WorldTime.hpp"
[1d5afa5]43
44#define MAXBONDS 8
45
[cee0b57]46
[9eefda]47/** Accounting data for Depth First Search.
48 */
49struct DFSAccounting
50{
[a564be]51 std::deque<atom *> *AtomStack;
52 std::deque<bond *> *BackEdgeStack;
[9eefda]53 int CurrentGraphNr;
54 int ComponentNumber;
55 atom *Root;
56 bool BackStepping;
57};
58
59/************************************* Functions for class molecule *********************************/
[cee0b57]60
[99752a]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
[e08c46]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 */
[e4afb4]120bool molecule::hasBondStructure() const
[e08c46]121{
[9d83b6]122 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
123 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
124 if (!ListOfBonds.empty())
[e08c46]125 return true;
[9d83b6]126 }
[e08c46]127 return false;
128}
129
[b8b75d]130/** Prints a list of all bonds to \a *out.
131 */
[e138de]132void molecule::OutputBondsList() const
[b8b75d]133{
[a67d19]134 DoLog(1) && (Log() << Verbose(1) << endl << "From contents of bond chain list:");
[9d83b6]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)
[e08c46]140 if ((*BondRunner)->leftatom == *AtomRunner) {
141 DoLog(0) && (Log() << Verbose(0) << *(*BondRunner) << "\t" << endl);
142 }
[9d83b6]143 }
[a67d19]144 DoLog(0) && (Log() << Verbose(0) << endl);
[9eefda]145}
146;
[cee0b57]147
148
149/** Counts all cyclic bonds and returns their number.
150 * \note Hydrogen bonds can never by cyclic, thus no check for that
[9d37ac]151 * \return number of cyclic bonds
[cee0b57]152 */
[e138de]153int molecule::CountCyclicBonds()
[cee0b57]154{
[266237]155 NoCyclicBonds = 0;
[cee0b57]156 int *MinimumRingSize = NULL;
157 MoleculeLeafClass *Subgraphs = NULL;
[a564be]158 std::deque<bond *> *BackEdgeStack = NULL;
[9d83b6]159 for(molecule::iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
160 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
[129204]161 if ((!ListOfBonds.empty()) && ((*ListOfBonds.begin())->Type == GraphEdge::Undetermined)) {
[e08c46]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;
[cee0b57]171 }
[9d83b6]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)
[e08c46]178 if ((*BondRunner)->leftatom == *AtomRunner)
179 if ((*BondRunner)->Cyclic)
180 NoCyclicBonds++;
[9d83b6]181 }
[9eefda]182 delete (BackEdgeStack);
[266237]183 return NoCyclicBonds;
[9eefda]184}
185;
[b8b75d]186
[cee0b57]187
[e73ad9a]188/** Sets atom::GraphNr and atom::LowpointNr to DFSAccounting::CurrentGraphNr.
[9eefda]189 * \param *Walker current node
190 * \param &BFS structure with accounting data for BFS
191 */
[e138de]192void DepthFirstSearchAnalysis_SetWalkersGraphNr(atom *&Walker, struct DFSAccounting &DFS)
[174e0e]193{
[9eefda]194 if (!DFS.BackStepping) { // if we don't just return from (8)
195 Walker->GraphNr = DFS.CurrentGraphNr;
196 Walker->LowpointNr = DFS.CurrentGraphNr;
[68f03d]197 DoLog(1) && (Log() << Verbose(1) << "Setting Walker[" << Walker->getName() << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl);
[a564be]198 DFS.AtomStack->push_front(Walker);
[9eefda]199 DFS.CurrentGraphNr++;
[174e0e]200 }
[9eefda]201}
202;
[174e0e]203
[9eefda]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 */
[e138de]213void DepthFirstSearchAnalysis_ProbeAlongUnusedBond(const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS)
[174e0e]214{
215 atom *OtherAtom = NULL;
216
217 do { // (3) if Walker has no unused egdes, go to (5)
[9eefda]218 DFS.BackStepping = false; // reset backstepping flag for (8)
[174e0e]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;
[a67d19]223 DoLog(2) && (Log() << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl);
[174e0e]224 // (4) Mark Binder used, ...
[129204]225 Binder->MarkUsed(GraphEdge::black);
[174e0e]226 OtherAtom = Binder->GetOtherAtom(Walker);
[68f03d]227 DoLog(2) && (Log() << Verbose(2) << "(4) OtherAtom is " << OtherAtom->getName() << "." << endl);
[174e0e]228 if (OtherAtom->GraphNr != -1) {
229 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
[129204]230 Binder->Type = GraphEdge::BackEdge;
[a564be]231 DFS.BackEdgeStack->push_front(Binder);
[9eefda]232 Walker->LowpointNr = (Walker->LowpointNr < OtherAtom->GraphNr) ? Walker->LowpointNr : OtherAtom->GraphNr;
[68f03d]233 DoLog(3) && (Log() << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->getName() << "] to " << Walker->LowpointNr << "." << endl);
[174e0e]234 } else {
235 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
[129204]236 Binder->Type = GraphEdge::TreeEdge;
[174e0e]237 OtherAtom->Ancestor = Walker;
238 Walker = OtherAtom;
[68f03d]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);
[174e0e]240 break;
241 }
242 Binder = NULL;
[9eefda]243 } while (1); // (3)
244}
245;
[174e0e]246
[9eefda]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 */
[e138de]255void DepthFirstSearchAnalysis_CheckForaNewComponent(const molecule * const mol, atom *&Walker, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
[174e0e]256{
257 atom *OtherAtom = NULL;
258
259 // (5) if Ancestor of Walker is ...
[68f03d]260 DoLog(1) && (Log() << Verbose(1) << "(5) Number of Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "] is " << Walker->Ancestor->GraphNr << "." << endl);
[174e0e]261
[9eefda]262 if (Walker->Ancestor->GraphNr != DFS.Root->GraphNr) {
[174e0e]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;
[68f03d]267 DoLog(2) && (Log() << Verbose(2) << "(6) Setting Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl);
[174e0e]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;
[68f03d]271 DoLog(2) && (Log() << Verbose(2) << "(7) Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s is a separating vertex, creating component." << endl);
[9eefda]272 mol->SetNextComponentNumber(Walker->Ancestor, DFS.ComponentNumber);
[68f03d]273 DoLog(3) && (Log() << Verbose(3) << "(7) Walker[" << Walker->getName() << "]'s Ancestor's Compont is " << DFS.ComponentNumber << "." << endl);
[9eefda]274 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
[68f03d]275 DoLog(3) && (Log() << Verbose(3) << "(7) Walker[" << Walker->getName() << "]'s Compont is " << DFS.ComponentNumber << "." << endl);
[174e0e]276 do {
[a564be]277 ASSERT(!DFS.AtomStack->empty(), "DepthFirstSearchAnalysis_CheckForaNewComponent() - DFS.AtomStack is empty!");
278 OtherAtom = DFS.AtomStack->front();
279 DFS.AtomStack->pop_front();
[174e0e]280 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
[9eefda]281 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
[68f03d]282 DoLog(3) && (Log() << Verbose(3) << "(7) Other[" << OtherAtom->getName() << "]'s Compont is " << DFS.ComponentNumber << "." << endl);
[174e0e]283 } while (OtherAtom != Walker);
[9eefda]284 DFS.ComponentNumber++;
[174e0e]285 }
286 // (8) Walker becomes its Ancestor, go to (3)
[68f03d]287 DoLog(2) && (Log() << Verbose(2) << "(8) Walker[" << Walker->getName() << "] is now its Ancestor " << Walker->Ancestor->getName() << ", backstepping. " << endl);
[174e0e]288 Walker = Walker->Ancestor;
[9eefda]289 DFS.BackStepping = true;
[174e0e]290 }
[9eefda]291}
292;
[174e0e]293
[9eefda]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 */
[e138de]302void DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
[174e0e]303{
304 atom *OtherAtom = NULL;
305
[9eefda]306 if (!DFS.BackStepping) { // coming from (8) want to go to (3)
[174e0e]307 // (9) remove all from stack till Walker (including), these and Root form a component
[99593f]308 //DFS.AtomStack->Output(out);
[9eefda]309 mol->SetNextComponentNumber(DFS.Root, DFS.ComponentNumber);
[68f03d]310 DoLog(3) && (Log() << Verbose(3) << "(9) Root[" << DFS.Root->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
[9eefda]311 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
[68f03d]312 DoLog(3) && (Log() << Verbose(3) << "(9) Walker[" << Walker->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
[174e0e]313 do {
[a564be]314 ASSERT(!DFS.AtomStack->empty(), "DepthFirstSearchAnalysis_CleanRootStackDownTillWalker() - DFS.AtomStack is empty!");
315 OtherAtom = DFS.AtomStack->front();
316 DFS.AtomStack->pop_front();
[174e0e]317 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
[9eefda]318 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
[a564be]319 DoLog(3) && (Log() << Verbose(3) << "(7) Other[" << OtherAtom->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
[174e0e]320 } while (OtherAtom != Walker);
[9eefda]321 DFS.ComponentNumber++;
[174e0e]322
323 // (11) Root is separation vertex, set Walker to Root and go to (4)
[9eefda]324 Walker = DFS.Root;
[174e0e]325 Binder = mol->FindNextUnused(Walker);
[68f03d]326 DoLog(1) && (Log() << Verbose(1) << "(10) Walker is Root[" << DFS.Root->getName() << "], next Unused Bond is " << Binder << "." << endl);
[174e0e]327 if (Binder != NULL) { // Root is separation vertex
[a67d19]328 DoLog(1) && (Log() << Verbose(1) << "(11) Root is a separation vertex." << endl);
[174e0e]329 Walker->SeparationVertex = true;
330 }
331 }
[9eefda]332}
333;
334
335/** Initializes DFSAccounting structure.
336 * \param &DFS accounting structure to allocate
[7218f8]337 * \param *mol molecule with AtomCount, BondCount and all atoms
[9eefda]338 */
[e138de]339void DepthFirstSearchAnalysis_Init(struct DFSAccounting &DFS, const molecule * const mol)
[9eefda]340{
[a564be]341 DFS.AtomStack = new std::deque<atom *> (mol->getAtomCount());
[9eefda]342 DFS.CurrentGraphNr = 0;
343 DFS.ComponentNumber = 0;
344 DFS.BackStepping = false;
[7218f8]345 mol->ResetAllBondsToUnused();
[a564be]346 DFS.BackEdgeStack->clear();
[9eefda]347}
348;
[174e0e]349
[9eefda]350/** Free's DFSAccounting structure.
351 * \param &DFS accounting structure to free
352 */
[e138de]353void DepthFirstSearchAnalysis_Finalize(struct DFSAccounting &DFS)
[9eefda]354{
355 delete (DFS.AtomStack);
[7218f8]356 // delete (DFS.BackEdgeStack); // DON'T free, see DepthFirstSearchAnalysis(), is returned as allocated
[9eefda]357}
358;
[174e0e]359
[00ef5c]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
[cee0b57]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].
[a564be]370 * \param *&BackEdgeStack NULL pointer to std::deque<bond *> with all the found back edges, allocated and filled on return
[cee0b57]371 * \return list of each disconnected subgraph as an individual molecule class structure
372 */
[a564be]373MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(std::deque<bond *> *&BackEdgeStack) const
[cee0b57]374{
[9eefda]375 struct DFSAccounting DFS;
[458c31]376 BackEdgeStack = new std::deque<bond *> (getBondCount());
[9eefda]377 DFS.BackEdgeStack = BackEdgeStack;
[cee0b57]378 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
379 MoleculeLeafClass *LeafWalker = SubGraphs;
[9eefda]380 int OldGraphNr = 0;
[174e0e]381 atom *Walker = NULL;
[cee0b57]382 bond *Binder = NULL;
383
[a7b761b]384 if (getAtomCount() == 0)
[046783]385 return SubGraphs;
[a67d19]386 DoLog(0) && (Log() << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl);
[00ef5c]387 init_DFS(DFS);
[cee0b57]388
[9879f6]389 for (molecule::const_iterator iter = begin(); iter != end();) {
390 DFS.Root = *iter;
[7218f8]391 // (1) mark all edges unused, empty stack, set atom->GraphNr = -1 for all
[a564be]392 DFS.AtomStack->clear();
[cee0b57]393
394 // put into new subgraph molecule and add this to list of subgraphs
395 LeafWalker = new MoleculeLeafClass(LeafWalker);
[5f612ee]396 LeafWalker->Leaf = World::getInstance().createMolecule();
[9eefda]397 LeafWalker->Leaf->AddCopyAtom(DFS.Root);
[cee0b57]398
[9eefda]399 OldGraphNr = DFS.CurrentGraphNr;
400 Walker = DFS.Root;
[cee0b57]401 do { // (10)
402 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
[e138de]403 DepthFirstSearchAnalysis_SetWalkersGraphNr(Walker, DFS);
[174e0e]404
[e138de]405 DepthFirstSearchAnalysis_ProbeAlongUnusedBond(this, Walker, Binder, DFS);
[174e0e]406
[cee0b57]407 if (Binder == NULL) {
[a67d19]408 DoLog(2) && (Log() << Verbose(2) << "No more Unused Bonds." << endl);
[cee0b57]409 break;
410 } else
411 Binder = NULL;
[9eefda]412 } while (1); // (2)
[cee0b57]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!
[9eefda]415 if ((Walker == DFS.Root) && (Binder == NULL))
[cee0b57]416 break;
417
[e138de]418 DepthFirstSearchAnalysis_CheckForaNewComponent(this, Walker, DFS, LeafWalker);
[174e0e]419
[e138de]420 DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(this, Walker, Binder, DFS, LeafWalker);
[174e0e]421
[9eefda]422 } while ((DFS.BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
[cee0b57]423
424 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
[a67d19]425 DoLog(0) && (Log() << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << DFS.CurrentGraphNr << "." << endl);
[986ed3]426 LeafWalker->Leaf->Output((ofstream *)&(Log() << Verbose(0)));
[a67d19]427 DoLog(0) && (Log() << Verbose(0) << endl);
[cee0b57]428
429 // step on to next root
[9879f6]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++;
[cee0b57]434 }
435 }
436 // set cyclic bond criterium on "same LP" basis
[266237]437 CyclicBondAnalysis();
438
[e138de]439 OutputGraphInfoPerAtom();
[266237]440
[e138de]441 OutputGraphInfoPerBond();
[266237]442
443 // free all and exit
[e138de]444 DepthFirstSearchAnalysis_Finalize(DFS);
[a67d19]445 DoLog(0) && (Log() << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl);
[266237]446 return SubGraphs;
[9eefda]447}
448;
[266237]449
450/** Scans through all bonds and set bond::Cyclic to true where atom::LowpointNr of both ends is equal: LP criterion.
451 */
[fa649a]452void molecule::CyclicBondAnalysis() const
[266237]453{
454 NoCyclicBonds = 0;
[9d83b6]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)
[e08c46]460 if ((*BondRunner)->leftatom == *AtomRunner)
461 if ((*BondRunner)->rightatom->LowpointNr == (*BondRunner)->leftatom->LowpointNr) { // cyclic ??
462 (*BondRunner)->Cyclic = true;
463 NoCyclicBonds++;
464 }
[9d83b6]465 }
[9eefda]466}
467;
[cee0b57]468
[266237]469/** Output graph information per atom.
470 */
[e138de]471void molecule::OutputGraphInfoPerAtom() const
[266237]472{
[a67d19]473 DoLog(1) && (Log() << Verbose(1) << "Final graph info for each atom is:" << endl);
[c743f8]474 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::OutputGraphInfo));
[9eefda]475}
476;
[cee0b57]477
[266237]478/** Output graph information per bond.
479 */
[e138de]480void molecule::OutputGraphInfoPerBond() const
[266237]481{
[a67d19]482 DoLog(1) && (Log() << Verbose(1) << "Final graph info for each bond is:" << endl);
[9d83b6]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)
[e08c46]488 if ((*BondRunner)->leftatom == *AtomRunner) {
[9d83b6]489 const bond *Binder = *BondRunner;
[f9183b]490 if (DoLog(2)) {
491 ostream &out = (Log() << Verbose(2));
[129204]492 out << ((Binder->Type == GraphEdge::TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
[f9183b]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 }
[e08c46]500 if (Binder->Cyclic) // cyclic ??
501 DoLog(3) && (Log() << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl);
502 }
[9d83b6]503 }
[9eefda]504}
505;
506
[cee0b57]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
[5309ba]510 * \param Nr number to use
[cee0b57]511 */
[fa649a]512void molecule::SetNextComponentNumber(atom *vertex, int nr) const
[cee0b57]513{
[9eefda]514 size_t i = 0;
[cee0b57]515 if (vertex != NULL) {
[9d83b6]516 const BondList& ListOfBonds = vertex->getListOfBonds();
517 for (; i < ListOfBonds.size(); i++) {
[9eefda]518 if (vertex->ComponentNr[i] == -1) { // check if not yet used
[cee0b57]519 vertex->ComponentNr[i] = nr;
520 break;
[9eefda]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!
[cee0b57]523 }
[9d83b6]524 if (i == ListOfBonds.size()) {
[58ed4a]525 DoeLog(0) && (eLog()<< Verbose(0) << "Error: All Component entries are already occupied!" << endl);
[e359a8]526 performCriticalExit();
527 }
528 } else {
[58ed4a]529 DoeLog(0) && (eLog()<< Verbose(0) << "Error: Given vertex is NULL!" << endl);
[e359a8]530 performCriticalExit();
531 }
[9eefda]532}
533;
[cee0b57]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 */
[fa649a]539bond * molecule::FindNextUnused(atom *vertex) const
[cee0b57]540{
[9d83b6]541 const BondList& ListOfBonds = vertex->getListOfBonds();
542 for (BondList::const_iterator Runner = ListOfBonds.begin();
543 Runner != ListOfBonds.end();
544 ++Runner)
[129204]545 if ((*Runner)->IsUsed() == GraphEdge::white)
[9eefda]546 return ((*Runner));
[cee0b57]547 return NULL;
[9eefda]548}
549;
[cee0b57]550
551/** Resets bond::Used flag of all bonds in this molecule.
552 * \return true - success, false - -failure
553 */
[fa649a]554void molecule::ResetAllBondsToUnused() const
[cee0b57]555{
[9d83b6]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)
[e08c46]561 if ((*BondRunner)->leftatom == *AtomRunner)
562 (*BondRunner)->ResetUsed();
[9d83b6]563 }
[9eefda]564}
565;
[cee0b57]566
567/** Output a list of flags, stating whether the bond was visited or not.
[9d37ac]568 * \param *list list to print
[cee0b57]569 */
[e138de]570void OutputAlreadyVisited(int *list)
[cee0b57]571{
[a67d19]572 DoLog(4) && (Log() << Verbose(4) << "Already Visited Bonds:\t");
[9eefda]573 for (int i = 1; i <= list[0]; i++)
[a67d19]574 DoLog(0) && (Log() << Verbose(0) << list[i] << " ");
575 DoLog(0) && (Log() << Verbose(0) << endl);
[9eefda]576}
577;
[cee0b57]578
579/** Storing the bond structure of a molecule to file.
[5309ba]580 * Simply stores Atom::Nr and then the Atom::Nr of all bond partners per line.
[35b698]581 * \param &filename name of file
582 * \param path path to file, defaults to empty
[cee0b57]583 * \return true - file written successfully, false - writing failed
584 */
[e4afb4]585bool molecule::StoreAdjacencyToFile(std::string filename, std::string path)
[cee0b57]586{
587 ofstream AdjacencyFile;
[35b698]588 string line;
[cee0b57]589 bool status = true;
590
[35b698]591 if (path != "")
592 line = path + "/" + filename;
[8ab0407]593 else
[35b698]594 line = filename;
595 AdjacencyFile.open(line.c_str(), ios::out);
[acf800]596 DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl);
[35b698]597 if (AdjacencyFile.good()) {
[1f1b23]598 AdjacencyFile << "m\tn" << endl;
[00ef5c]599 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputAdjacency),&AdjacencyFile));
[cee0b57]600 AdjacencyFile.close();
[acf800]601 DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl);
[cee0b57]602 } else {
[35b698]603 DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl);
[cee0b57]604 status = false;
605 }
606
607 return status;
[9eefda]608}
609;
[cee0b57]610
[1f1b23]611/** Storing the bond structure of a molecule to file.
[5309ba]612 * Simply stores Atom::Nr and then the Atom::Nr of all bond partners, one per line.
[35b698]613 * \param &filename name of file
614 * \param path path to file, defaults to empty
[1f1b23]615 * \return true - file written successfully, false - writing failed
616 */
[e4afb4]617bool molecule::StoreBondsToFile(std::string filename, std::string path)
[1f1b23]618{
619 ofstream BondFile;
[35b698]620 string line;
[1f1b23]621 bool status = true;
622
[35b698]623 if (path != "")
624 line = path + "/" + filename;
[8ab0407]625 else
[35b698]626 line = filename;
627 BondFile.open(line.c_str(), ios::out);
[acf800]628 DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl);
[35b698]629 if (BondFile.good()) {
[1f1b23]630 BondFile << "m\tn" << endl;
[00ef5c]631 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputBonds),&BondFile));
[1f1b23]632 BondFile.close();
[acf800]633 DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl);
[1f1b23]634 } else {
[35b698]635 DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl);
[1f1b23]636 status = false;
637 }
638
639 return status;
640}
641;
642
[35b698]643bool CheckAdjacencyFileAgainstMolecule_Init(std::string &path, ifstream &File, int *&CurrentBonds)
[ba4170]644{
[35b698]645 string filename;
646 filename = path + ADJACENCYFILE;
647 File.open(filename.c_str(), ios::out);
[0de7e8]648 DoLog(1) && (Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl);
[35b698]649 if (File.fail())
[ba4170]650 return false;
651
652 // allocate storage structure
[1d5afa5]653 CurrentBonds = new int[MAXBONDS]; // contains parsed bonds of current atom
654 for(int i=0;i<MAXBONDS;i++)
[920c70]655 CurrentBonds[i] = 0;
[ba4170]656 return true;
[9eefda]657}
658;
[ba4170]659
[e138de]660void CheckAdjacencyFileAgainstMolecule_Finalize(ifstream &File, int *&CurrentBonds)
[ba4170]661{
662 File.close();
663 File.clear();
[920c70]664 delete[](CurrentBonds);
[9eefda]665}
666;
[ba4170]667
[e138de]668void CheckAdjacencyFileAgainstMolecule_CompareBonds(bool &status, int &NonMatchNumber, atom *&Walker, size_t &CurrentBondsOfAtom, int AtomNr, int *&CurrentBonds, atom **ListOfAtoms)
[ba4170]669{
670 size_t j = 0;
671 int id = -1;
672
[e138de]673 //Log() << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
[9d83b6]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) {
[735b1c]679 id = (*Runner)->GetOtherAtom(Walker)->getNr();
[ba4170]680 j = 0;
[9eefda]681 for (; (j < CurrentBondsOfAtom) && (CurrentBonds[j++] != id);)
[ba4170]682 ; // check against all parsed bonds
[9eefda]683 if (CurrentBonds[j - 1] != id) { // no match ? Then mark in ListOfAtoms
[ba4170]684 ListOfAtoms[AtomNr] = NULL;
685 NonMatchNumber++;
686 status = false;
[0de7e8]687 DoeLog(2) && (eLog() << Verbose(2) << id << " can not be found in list." << endl);
[ba4170]688 } else {
[0de7e8]689 //Log() << Verbose(0) << "[" << id << "]\t";
[ba4170]690 }
691 }
[e138de]692 //Log() << Verbose(0) << endl;
[ba4170]693 } else {
[9d83b6]694 DoLog(0) && (Log() << Verbose(0) << "Number of bonds for Atom " << *Walker << " does not match, parsed " << CurrentBondsOfAtom << " against " << ListOfBonds.size() << "." << endl);
[ba4170]695 status = false;
696 }
[9eefda]697}
698;
[ba4170]699
[cee0b57]700/** Checks contents of adjacency file against bond structure in structure molecule.
701 * \param *path path to file
[5309ba]702 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::Nr) to *Atom
[cee0b57]703 * \return true - structure is equal, false - not equivalence
704 */
[35b698]705bool molecule::CheckAdjacencyFileAgainstMolecule(std::string &path, atom **ListOfAtoms)
[cee0b57]706{
707 ifstream File;
708 bool status = true;
[266237]709 atom *Walker = NULL;
[ba4170]710 int *CurrentBonds = NULL;
[9eefda]711 int NonMatchNumber = 0; // will number of atoms with differing bond structure
[ba4170]712 size_t CurrentBondsOfAtom = -1;
[0de7e8]713 const int AtomCount = getAtomCount();
[cee0b57]714
[e138de]715 if (!CheckAdjacencyFileAgainstMolecule_Init(path, File, CurrentBonds)) {
[a67d19]716 DoLog(1) && (Log() << Verbose(1) << "Adjacency file not found." << endl);
[ba4170]717 return true;
718 }
719
[920c70]720 char buffer[MAXSTRINGSIZE];
[1d5afa5]721 int tmp;
[ba4170]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
[0de7e8]731 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
[ba4170]732 Walker = ListOfAtoms[AtomNr];
[1d5afa5]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 }
[ba4170]740 // compare against present bonds
[e138de]741 CheckAdjacencyFileAgainstMolecule_CompareBonds(status, NonMatchNumber, Walker, CurrentBondsOfAtom, AtomNr, CurrentBonds, ListOfAtoms);
[0de7e8]742 } else {
743 if (AtomNr != -1)
744 DoeLog(2) && (eLog() << Verbose(2) << AtomNr << " is not valid in the range of ids [" << 0 << "," << AtomCount << ")." << endl);
[ba4170]745 }
[cee0b57]746 }
[e138de]747 CheckAdjacencyFileAgainstMolecule_Finalize(File, CurrentBonds);
[cee0b57]748
[ba4170]749 if (status) { // if equal we parse the KeySetFile
[a67d19]750 DoLog(1) && (Log() << Verbose(1) << "done: Equal." << endl);
[ba4170]751 } else
[a67d19]752 DoLog(1) && (Log() << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl);
[cee0b57]753 return status;
[9eefda]754}
755;
[cee0b57]756
757/** Picks from a global stack with all back edges the ones in the fragment.
[5309ba]758 * \param **ListOfLocalAtoms array of father atom::Nr to local atom::Nr (reverse of atom::father)
[cee0b57]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 */
[a564be]763bool molecule::PickLocalBackEdges(atom **ListOfLocalAtoms, std::deque<bond *> *&ReferenceStack, std::deque<bond *> *&LocalStack) const
[cee0b57]764{
765 bool status = true;
[a564be]766 if (ReferenceStack->empty()) {
[a67d19]767 DoLog(1) && (Log() << Verbose(1) << "ReferenceStack is empty!" << endl);
[cee0b57]768 return false;
769 }
[a564be]770 bond *Binder = ReferenceStack->front();
771 ReferenceStack->pop_front();
[9eefda]772 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
[cee0b57]773 atom *Walker = NULL, *OtherAtom = NULL;
[a564be]774 ReferenceStack->push_front(Binder);
[cee0b57]775
[9eefda]776 do { // go through all bonds and push local ones
[735b1c]777 Walker = ListOfLocalAtoms[Binder->leftatom->getNr()]; // get one atom in the reference molecule
[9d83b6]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) {
[266237]783 OtherAtom = (*Runner)->GetOtherAtom(Walker);
[735b1c]784 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->getNr()]) { // found the bond
[a564be]785 LocalStack->push_front((*Runner));
[a67d19]786 DoLog(3) && (Log() << Verbose(3) << "Found local edge " << *(*Runner) << "." << endl);
[cee0b57]787 break;
788 }
789 }
[9d83b6]790 }
[a564be]791 ASSERT(!ReferenceStack->empty(), "molecule::PickLocalBackEdges() - ReferenceStack is empty!");
792 Binder = ReferenceStack->front(); // loop the stack for next item
793 ReferenceStack->pop_front();
[a67d19]794 DoLog(3) && (Log() << Verbose(3) << "Current candidate edge " << Binder << "." << endl);
[a564be]795 ReferenceStack->push_front(Binder);
[cee0b57]796 } while (FirstBond != Binder);
797
798 return status;
[9eefda]799}
800;
[ce7cc5]801
[266237]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;
[9eefda]814}
815;
[266237]816
[e138de]817void BuildInducedSubgraph_Init(atom **&ParentList, int AtomCount)
[cee0b57]818{
819 // reset parent list
[920c70]820 ParentList = new atom*[AtomCount];
821 for (int i=0;i<AtomCount;i++)
822 ParentList[i] = NULL;
[a67d19]823 DoLog(3) && (Log() << Verbose(3) << "Resetting ParentList." << endl);
[9eefda]824}
825;
[cee0b57]826
[e138de]827void BuildInducedSubgraph_FillParentList(const molecule *mol, const molecule *Father, atom **&ParentList)
[43587e]828{
[cee0b57]829 // fill parent list with sons
[a67d19]830 DoLog(3) && (Log() << Verbose(3) << "Filling Parent List." << endl);
[9879f6]831 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
[735b1c]832 ParentList[(*iter)->father->getNr()] = (*iter);
[cee0b57]833 // Outputting List for debugging
[735b1c]834 DoLog(4) && (Log() << Verbose(4) << "Son[" << (*iter)->father->getNr() << "] of " << (*iter)->father << " is " << ParentList[(*iter)->father->getNr()] << "." << endl);
[cee0b57]835 }
[a7b761b]836};
[43587e]837
[e138de]838void BuildInducedSubgraph_Finalize(atom **&ParentList)
[43587e]839{
[920c70]840 delete[](ParentList);
[9eefda]841}
842;
[43587e]843
[e138de]844bool BuildInducedSubgraph_CreateBondsFromParent(molecule *mol, const molecule *Father, atom **&ParentList)
[43587e]845{
846 bool status = true;
847 atom *OtherAtom = NULL;
[cee0b57]848 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
[a67d19]849 DoLog(3) && (Log() << Verbose(3) << "Creating bonds." << endl);
[9879f6]850 for (molecule::const_iterator iter = Father->begin(); iter != Father->end(); ++iter) {
[735b1c]851 if (ParentList[(*iter)->getNr()] != NULL) {
852 if (ParentList[(*iter)->getNr()]->father != (*iter)) {
[cee0b57]853 status = false;
854 } else {
[9d83b6]855 const BondList& ListOfBonds = (*iter)->getListOfBonds();
856 for (BondList::const_iterator Runner = ListOfBonds.begin();
857 Runner != ListOfBonds.end();
858 ++Runner) {
[9879f6]859 OtherAtom = (*Runner)->GetOtherAtom((*iter));
[735b1c]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);
[cee0b57]863 }
864 }
865 }
866 }
867 }
[43587e]868 return status;
[9eefda]869}
870;
[cee0b57]871
[43587e]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 */
[9d37ac]880bool molecule::BuildInducedSubgraph(const molecule *Father){
[43587e]881 bool status = true;
882 atom **ParentList = NULL;
[a67d19]883 DoLog(2) && (Log() << Verbose(2) << "Begin of BuildInducedSubgraph." << endl);
[ea7176]884 BuildInducedSubgraph_Init(ParentList, Father->getAtomCount());
[e138de]885 BuildInducedSubgraph_FillParentList(this, Father, ParentList);
886 status = BuildInducedSubgraph_CreateBondsFromParent(this, Father, ParentList);
887 BuildInducedSubgraph_Finalize(ParentList);
[a67d19]888 DoLog(2) && (Log() << Verbose(2) << "End of BuildInducedSubgraph." << endl);
[cee0b57]889 return status;
[9eefda]890}
891;
[cee0b57]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 */
[e138de]898bool molecule::CheckForConnectedSubgraph(KeySet *Fragment)
[cee0b57]899{
900 atom *Walker = NULL, *Walker2 = NULL;
901 bool BondStatus = false;
902 int size;
903
[a67d19]904 DoLog(1) && (Log() << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl);
905 DoLog(2) && (Log() << Verbose(2) << "Disconnected atom: ");
[cee0b57]906
907 // count number of atoms in graph
908 size = 0;
[9eefda]909 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
[cee0b57]910 size++;
911 if (size > 1)
[9eefda]912 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
[cee0b57]913 Walker = FindAtom(*runner);
914 BondStatus = false;
[9eefda]915 for (KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
[cee0b57]916 Walker2 = FindAtom(*runners);
[9d83b6]917 const BondList& ListOfBonds = Walker->getListOfBonds();
918 for (BondList::const_iterator Runner = ListOfBonds.begin();
919 Runner != ListOfBonds.end();
920 ++Runner) {
[266237]921 if ((*Runner)->GetOtherAtom(Walker) == Walker2) {
[cee0b57]922 BondStatus = true;
923 break;
924 }
925 if (BondStatus)
926 break;
927 }
928 }
929 if (!BondStatus) {
[a67d19]930 DoLog(0) && (Log() << Verbose(0) << (*Walker) << endl);
[cee0b57]931 return false;
932 }
933 }
934 else {
[a67d19]935 DoLog(0) && (Log() << Verbose(0) << "none." << endl);
[cee0b57]936 return true;
937 }
[a67d19]938 DoLog(0) && (Log() << Verbose(0) << "none." << endl);
[cee0b57]939
[a67d19]940 DoLog(1) && (Log() << Verbose(1) << "End of CheckForConnectedSubgraph" << endl);
[cee0b57]941
942 return true;
943}
[c6123b]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.