source: src/Graph/DepthFirstSearchAnalysis.cpp@ d3abb1

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

Extracted MoleculeLeafClass into own module.

  • removed some unnecessary includes in moleculelist.cpp.
  • Property mode set to 100644
File size: 16.3 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * DepthFirstSearchAnalysis.cpp
10 *
11 * Created on: Feb 16, 2011
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include "DepthFirstSearchAnalysis.hpp"
23
24#include <algorithm>
25#include <functional>
26
27#include "atom.hpp"
28#include "Bond/bond.hpp"
29#include "CodePatterns/Assert.hpp"
30#include "CodePatterns/Info.hpp"
31#include "CodePatterns/Log.hpp"
32#include "CodePatterns/Verbose.hpp"
33#include "Descriptors/AtomDescriptor.hpp"
34#include "molecule.hpp"
35#include "MoleculeLeafClass.hpp"
36#include "World.hpp"
37
38DepthFirstSearchAnalysis::DepthFirstSearchAnalysis() :
39 CurrentGraphNr(0),
40 ComponentNumber(0),
41 BackStepping(false)
42{
43 ResetAllBondsToUnused();
44}
45
46DepthFirstSearchAnalysis::~DepthFirstSearchAnalysis()
47{}
48
49void DepthFirstSearchAnalysis::Init()
50{
51 CurrentGraphNr = 0;
52 ComponentNumber = 0;
53 BackStepping = false;
54 std::for_each(World::getInstance().getAtomIter(),World::getInstance().atomEnd(),
55 std::mem_fun(&atom::resetGraphNr));
56 std::for_each(World::getInstance().getAtomIter(),World::getInstance().atomEnd(),
57 std::mem_fun(&atom::InitComponentNr));
58}
59
60
61bond * DepthFirstSearchAnalysis::FindNextUnused(atom *vertex) const
62{
63 const BondList& ListOfBonds = vertex->getListOfBonds();
64 for (BondList::const_iterator Runner = ListOfBonds.begin();
65 Runner != ListOfBonds.end();
66 ++Runner)
67 if ((*Runner)->IsUsed() == GraphEdge::white)
68 return ((*Runner));
69 return NULL;
70}
71
72
73void DepthFirstSearchAnalysis::ResetAllBondsToUnused() const
74{
75 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
76 for(World::AtomComposite::const_iterator AtomRunner = allatoms.begin();
77 AtomRunner != allatoms.end();
78 ++AtomRunner) {
79 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
80 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
81 BondRunner != ListOfBonds.end();
82 ++BondRunner)
83 if ((*BondRunner)->leftatom == *AtomRunner)
84 (*BondRunner)->ResetUsed();
85 }
86}
87
88void DepthFirstSearchAnalysis::SetNextComponentNumber(atom *vertex, int nr) const
89{
90 size_t i = 0;
91 ASSERT(vertex != NULL,
92 "DepthFirstSearchAnalysis::SetNextComponentNumber() - Given vertex is NULL!");
93 const BondList& ListOfBonds = vertex->getListOfBonds();
94 for (; i < ListOfBonds.size(); i++) {
95 if (vertex->ComponentNr[i] == -1) { // check if not yet used
96 vertex->ComponentNr[i] = nr;
97 break;
98 } else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
99 break; // breaking here will not cause error!
100 }
101 ASSERT(i < ListOfBonds.size(),
102 "DepthFirstSearchAnalysis::SetNextComponentNumber() - All Component entries are already occupied!");
103}
104
105
106bool DepthFirstSearchAnalysis::PickLocalBackEdges(atom **ListOfLocalAtoms, std::deque<bond *> *&LocalStack) const
107{
108 bool status = true;
109 if (BackEdgeStack.empty()) {
110 ELOG(1, "Reference BackEdgeStack is empty!");
111 return false;
112 }
113 bond *Binder = BackEdgeStack.front();
114 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
115 atom *Walker = NULL, *OtherAtom = NULL;
116
117 do { // go through all bonds and push local ones
118 Walker = ListOfLocalAtoms[Binder->leftatom->getNr()]; // get one atom in the reference molecule
119 if (Walker != NULL) { // if this Walker exists in the subgraph ...
120 const BondList& ListOfBonds = Walker->getListOfBonds();
121 for (BondList::const_iterator Runner = ListOfBonds.begin();
122 Runner != ListOfBonds.end();
123 ++Runner) {
124 OtherAtom = (*Runner)->GetOtherAtom(Walker);
125 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->getNr()]) { // found the bond
126 LocalStack->push_front((*Runner));
127 LOG(3, "INFO: Found local edge " << *(*Runner) << ".");
128 break;
129 }
130 }
131 }
132 ASSERT(!BackEdgeStack.empty(), "DepthFirstSearchAnalysis::PickLocalBackEdges() - ReferenceStack is empty!");
133 Binder = BackEdgeStack.front(); // loop the stack for next item
134 LOG(3, "Current candidate edge " << Binder << ".");
135 } while (FirstBond != Binder);
136
137 return status;
138}
139
140
141
142void DepthFirstSearchAnalysis::OutputGraphInfoPerAtom() const
143{
144 LOG(1, "Final graph info for each atom is:");
145 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
146 for_each(allatoms.begin(),allatoms.end(),mem_fun(&atom::OutputGraphInfo));
147}
148
149
150void DepthFirstSearchAnalysis::OutputGraphInfoPerBond() const
151{
152 LOG(1, "Final graph info for each bond is:");
153 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
154 for(World::AtomComposite::const_iterator AtomRunner = allatoms.begin();
155 AtomRunner != allatoms.end();
156 ++AtomRunner) {
157 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
158 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
159 BondRunner != ListOfBonds.end();
160 ++BondRunner)
161 if ((*BondRunner)->leftatom == *AtomRunner) {
162 const bond *Binder = *BondRunner;
163 if (DoLog(2)) {
164 ostream &out = (Log() << Verbose(2));
165 out << ((Binder->Type == GraphEdge::TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
166 out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
167 Binder->leftatom->OutputComponentNumber(&out);
168 out << " === ";
169 out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
170 Binder->rightatom->OutputComponentNumber(&out);
171 out << ">." << endl;
172 }
173 if (Binder->Cyclic) // cyclic ??
174 LOG(3, "Lowpoint at each side are equal: CYCLIC!");
175 }
176 }
177}
178
179
180unsigned int DepthFirstSearchAnalysis::CyclicBondAnalysis() const
181{
182 unsigned int NoCyclicBonds = 0;
183 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
184 for(World::AtomComposite::const_iterator AtomRunner = allatoms.begin();
185 AtomRunner != allatoms.end();
186 ++AtomRunner) {
187 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
188 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
189 BondRunner != ListOfBonds.end();
190 ++BondRunner)
191 if ((*BondRunner)->leftatom == *AtomRunner)
192 if ((*BondRunner)->rightatom->LowpointNr == (*BondRunner)->leftatom->LowpointNr) { // cyclic ??
193 (*BondRunner)->Cyclic = true;
194 NoCyclicBonds++;
195 }
196 }
197 return NoCyclicBonds;
198}
199
200
201void DepthFirstSearchAnalysis::SetWalkersGraphNr(atom *&Walker)
202{
203 if (!BackStepping) { // if we don't just return from (8)
204 Walker->GraphNr = CurrentGraphNr;
205 Walker->LowpointNr = CurrentGraphNr;
206 LOG(1, "Setting Walker[" << Walker->getName() << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << ".");
207 AtomStack.push_front(Walker);
208 CurrentGraphNr++;
209 }
210}
211
212
213void DepthFirstSearchAnalysis::ProbeAlongUnusedBond(atom *&Walker, bond *&Binder)
214{
215 atom *OtherAtom = NULL;
216
217 do { // (3) if Walker has no unused egdes, go to (5)
218 BackStepping = false; // reset backstepping flag for (8)
219 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
220 Binder = FindNextUnused(Walker);
221 if (Binder == NULL)
222 break;
223 LOG(2, "Current Unused Bond is " << *Binder << ".");
224 // (4) Mark Binder used, ...
225 Binder->MarkUsed(GraphEdge::black);
226 OtherAtom = Binder->GetOtherAtom(Walker);
227 LOG(2, "(4) OtherAtom is " << OtherAtom->getName() << ".");
228 if (OtherAtom->GraphNr != -1) {
229 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
230 Binder->Type = GraphEdge::BackEdge;
231 BackEdgeStack.push_front(Binder);
232 Walker->LowpointNr = (Walker->LowpointNr < OtherAtom->GraphNr) ? Walker->LowpointNr : OtherAtom->GraphNr;
233 LOG(3, "(4a) Visited: Setting Lowpoint of Walker[" << Walker->getName() << "] to " << Walker->LowpointNr << ".");
234 } else {
235 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
236 Binder->Type = GraphEdge::TreeEdge;
237 OtherAtom->Ancestor = Walker;
238 Walker = OtherAtom;
239 LOG(3, "(4b) Not Visited: OtherAtom[" << OtherAtom->getName() << "]'s Ancestor is now " << OtherAtom->Ancestor->getName() << ", Walker is OtherAtom " << OtherAtom->getName() << ".");
240 break;
241 }
242 Binder = NULL;
243 } while (1); // (3)
244}
245
246
247void DepthFirstSearchAnalysis::CheckForaNewComponent(atom *&Walker, ConnectedSubgraph &Subgraph)
248{
249 atom *OtherAtom = NULL;
250
251 // (5) if Ancestor of Walker is ...
252 LOG(1, "(5) Number of Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "] is " << Walker->Ancestor->GraphNr << ".");
253
254 if (Walker->Ancestor->GraphNr != Root->GraphNr) {
255 // (6) (Ancestor of Walker is not Root)
256 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
257 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
258 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
259 LOG(2, "(6) Setting Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << ".");
260 } else {
261 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
262 Walker->Ancestor->SeparationVertex = true;
263 LOG(2, "(7) Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s is a separating vertex, creating component.");
264 SetNextComponentNumber(Walker->Ancestor, ComponentNumber);
265 LOG(3, "(7) Walker[" << Walker->getName() << "]'s Ancestor's Compont is " << ComponentNumber << ".");
266 SetNextComponentNumber(Walker, ComponentNumber);
267 LOG(3, "(7) Walker[" << Walker->getName() << "]'s Compont is " << ComponentNumber << ".");
268 do {
269 ASSERT(!AtomStack.empty(), "DepthFirstSearchAnalysis_CheckForaNewComponent() - AtomStack is empty!");
270 OtherAtom = AtomStack.front();
271 AtomStack.pop_front();
272 Subgraph.push_back(OtherAtom);
273 SetNextComponentNumber(OtherAtom, ComponentNumber);
274 LOG(3, "(7) Other[" << OtherAtom->getName() << "]'s Compont is " << ComponentNumber << ".");
275 } while (OtherAtom != Walker);
276 ComponentNumber++;
277 }
278 // (8) Walker becomes its Ancestor, go to (3)
279 LOG(2, "(8) Walker[" << Walker->getName() << "] is now its Ancestor " << Walker->Ancestor->getName() << ", backstepping. ");
280 Walker = Walker->Ancestor;
281 BackStepping = true;
282 }
283}
284
285
286void DepthFirstSearchAnalysis::CleanRootStackDownTillWalker(atom *&Walker, bond *&Binder, ConnectedSubgraph &Subgraph)
287{
288 atom *OtherAtom = NULL;
289
290 if (!BackStepping) { // coming from (8) want to go to (3)
291 // (9) remove all from stack till Walker (including), these and Root form a component
292 //AtomStack.Output(out);
293 SetNextComponentNumber(Root, ComponentNumber);
294 LOG(3, "(9) Root[" << Root->getName() << "]'s Component is " << ComponentNumber << ".");
295 SetNextComponentNumber(Walker, ComponentNumber);
296 LOG(3, "(9) Walker[" << Walker->getName() << "]'s Component is " << ComponentNumber << ".");
297 do {
298 ASSERT(!AtomStack.empty(), "DepthFirstSearchAnalysis::CleanRootStackDownTillWalker() - AtomStack is empty!");
299 OtherAtom = AtomStack.front();
300 AtomStack.pop_front();
301 Subgraph.push_back(OtherAtom);
302 SetNextComponentNumber(OtherAtom, ComponentNumber);
303 LOG(3, "(7) Other[" << OtherAtom->getName() << "]'s Component is " << ComponentNumber << ".");
304 } while (OtherAtom != Walker);
305 ComponentNumber++;
306
307 // (11) Root is separation vertex, set Walker to Root and go to (4)
308 Walker = Root;
309 Binder = FindNextUnused(Walker);
310 if (Binder != NULL) { // Root is separation vertex
311 LOG(1, "(10) Walker is Root[" << Root->getName() << "], next Unused Bond is " << *Binder << ".");
312 LOG(1, "(11) Root is a separation vertex.");
313 Walker->SeparationVertex = true;
314 } else {
315 LOG(1, "(10) Walker is Root[" << Root->getName() << "], no next Unused Bond.");
316 }
317 }
318}
319
320
321const std::deque<bond *>& DepthFirstSearchAnalysis::getBackEdgeStack() const
322{
323 return BackEdgeStack;
324}
325
326
327void DepthFirstSearchAnalysis::operator()()
328{
329 Info FunctionInfo("DepthFirstSearchAnalysis");
330 ListOfConnectedSubgraphs.clear();
331 int OldGraphNr = 0;
332 atom *Walker = NULL;
333 bond *Binder = NULL;
334
335 if (World::getInstance().numAtoms() == 0)
336 return;
337
338 Init();
339
340 LOG(0, "STATUS: Start walking the bond graph.");
341 for(World::AtomIterator iter = World::getInstance().getAtomIter();
342 iter != World::getInstance().atomEnd();) { // don't advance, is done at the end
343 Root = *iter;
344 // (1) mark all edges unused, empty stack, set atom->GraphNr = -1 for all
345 AtomStack.clear();
346
347 // put into new subgraph molecule and add this to list of subgraphs
348 ConnectedSubgraph CurrentSubgraph;
349 CurrentSubgraph.push_back(Root);
350
351 OldGraphNr = CurrentGraphNr;
352 Walker = Root;
353 do { // (10)
354 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
355 SetWalkersGraphNr(Walker);
356
357 ProbeAlongUnusedBond(Walker, Binder);
358
359 if (Binder == NULL) {
360 LOG(2, "No more Unused Bonds.");
361 break;
362 } else
363 Binder = NULL;
364 } while (1); // (2)
365
366 // 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!
367 if ((Walker == Root) && (Binder == NULL))
368 break;
369
370 CheckForaNewComponent( Walker, CurrentSubgraph);
371
372 CleanRootStackDownTillWalker(Walker, Binder, CurrentSubgraph);
373
374 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
375
376 ListOfConnectedSubgraphs.push_back(CurrentSubgraph);
377 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
378 std::stringstream output;
379 output << CurrentSubgraph;
380 LOG(0, "STATUS: Disconnected subgraph ranges from " << OldGraphNr << " to "
381 << CurrentGraphNr-1 << ": " << output.str());
382
383 // step on to next root
384 while (iter != World::getInstance().atomEnd()) {
385 if ((*iter)->GraphNr != -1) { // if already discovered, step on
386 iter++;
387 } else {
388 LOG(1,"Current next subgraph root candidate is " << (*iter)->getName()
389 << " with GraphNr " << (*iter)->GraphNr << ".");
390 break;
391 }
392 }
393 }
394 LOG(0, "STATUS: Done walking the bond graph.");
395
396 // set cyclic bond criterium on "same LP" basis
397 CyclicBondAnalysis();
398
399 OutputGraphInfoPerAtom();
400
401 OutputGraphInfoPerBond();
402}
403
404void DepthFirstSearchAnalysis::UpdateMoleculeStructure() const
405{
406 // remove all of World's molecules
407 for (World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
408 World::getInstance().getMoleculeIter() != World::getInstance().moleculeEnd();
409 iter = World::getInstance().getMoleculeIter()) {
410 World::getInstance().getMolecules()->erase(*iter);
411 World::getInstance().destroyMolecule(*iter);
412 }
413 // instantiate new molecules
414 molecule *newmol = NULL;
415 for (ConnectedSubgraphList::const_iterator iter = ListOfConnectedSubgraphs.begin();
416 iter != ListOfConnectedSubgraphs.end();
417 ++iter) {
418 LOG(0, "STATUS: Creating new molecule:");
419 std::stringstream output;
420 newmol = (*iter).getMolecule();
421 newmol->Output(&output);
422 std::stringstream outstream(output.str());
423 std::string line;
424 while (getline(outstream, line)) {
425 LOG(0, "\t"+line);
426 }
427 }
428}
429
430MoleculeLeafClass *DepthFirstSearchAnalysis::getMoleculeStructure() const
431{
432 MoleculeLeafClass *Subgraphs = new MoleculeLeafClass(NULL);
433 MoleculeLeafClass *MolecularWalker = Subgraphs;
434 for (World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
435 iter != World::getInstance().moleculeEnd();
436 ++iter) {
437 // TODO: Remove the insertion into molecule when saving does not depend on them anymore. Also, remove molecule.hpp include
438 MolecularWalker = new MoleculeLeafClass(MolecularWalker);
439 MolecularWalker->Leaf = (*iter);
440 }
441 return Subgraphs;
442}
443
Note: See TracBrowser for help on using the repository browser.