source: src/Graph/BondGraph.cpp@ 48d20d

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 48d20d was 4f04ab8, checked in by Frederik Heber <heber@…>, 12 years ago

Using boost::graph to obtain maximum matching for bond degree correction.

  • added bimap to boost.m4, added boost_bimap and boost_graph to configure.ac.
  • rewrote createMatching() in BondGraph with boost::graph, code mostly taken from maximum cardinality matching example.
  • Property mode set to 100644
File size: 17.9 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * bondgraph.cpp
25 *
26 * Created on: Oct 29, 2009
27 * Author: heber
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35// boost::graph uses placement new
36#include <boost/graph/adjacency_list.hpp>
37
38#include "CodePatterns/MemDebug.hpp"
39
40#include <algorithm>
41#include <boost/bimap.hpp>
42#include <boost/bind.hpp>
43#include <boost/foreach.hpp>
44#include <boost/function.hpp>
45#include <boost/graph/max_cardinality_matching.hpp>
46#include <deque>
47#include <iostream>
48
49#include "Atom/atom.hpp"
50#include "Bond/bond.hpp"
51#include "Graph/BondGraph.hpp"
52#include "Box.hpp"
53#include "Element/element.hpp"
54#include "CodePatterns/Info.hpp"
55#include "CodePatterns/Log.hpp"
56#include "CodePatterns/Range.hpp"
57#include "CodePatterns/Verbose.hpp"
58#include "molecule.hpp"
59#include "Element/periodentafel.hpp"
60#include "Fragmentation/MatrixContainer.hpp"
61#include "Graph/DepthFirstSearchAnalysis.hpp"
62#include "LinearAlgebra/Vector.hpp"
63#include "World.hpp"
64#include "WorldTime.hpp"
65
66const double BondGraph::BondThreshold = 0.4; //!< CSD threshold in bond check which is the width of the interval whose center is the sum of the covalent radii
67
68BondGraph::BondGraph() :
69 BondLengthMatrix(NULL),
70 IsAngstroem(true)
71{}
72
73BondGraph::BondGraph(bool IsA) :
74 BondLengthMatrix(NULL),
75 IsAngstroem(IsA)
76{}
77
78BondGraph::~BondGraph()
79{
80 CleanupBondLengthTable();
81}
82
83void BondGraph::CleanupBondLengthTable()
84{
85 if (BondLengthMatrix != NULL) {
86 delete(BondLengthMatrix);
87 }
88}
89
90bool BondGraph::LoadBondLengthTable(
91 std::istream &input)
92{
93 Info FunctionInfo(__func__);
94 bool status = true;
95 MatrixContainer *TempContainer = NULL;
96
97 // allocate MatrixContainer
98 if (BondLengthMatrix != NULL) {
99 LOG(1, "MatrixContainer for Bond length already present, removing.");
100 delete(BondLengthMatrix);
101 BondLengthMatrix = NULL;
102 }
103 TempContainer = new MatrixContainer;
104
105 // parse in matrix
106 if ((input.good()) && (status = TempContainer->ParseMatrix(input, 0, 1, 0))) {
107 LOG(1, "Parsing bond length matrix successful.");
108 } else {
109 ELOG(1, "Parsing bond length matrix failed.");
110 status = false;
111 }
112
113 if (status) // set to not NULL only if matrix was parsed
114 BondLengthMatrix = TempContainer;
115 else {
116 BondLengthMatrix = NULL;
117 delete(TempContainer);
118 }
119 return status;
120}
121
122double BondGraph::GetBondLength(
123 int firstZ,
124 int secondZ) const
125{
126 double return_length;
127 if ((firstZ < 0) || (firstZ >= (int)BondLengthMatrix->Matrix[0].size()))
128 return -1.;
129 if ((secondZ < 0) || (secondZ >= (int)BondLengthMatrix->Matrix[0][firstZ].size()))
130 return -1.;
131 if (BondLengthMatrix == NULL) {
132 return_length = -1.;
133 } else {
134 return_length = BondLengthMatrix->Matrix[0][firstZ][secondZ];
135 }
136 LOG(4, "INFO: Request for length between " << firstZ << " and "
137 << secondZ << ": " << return_length << ".");
138 return return_length;
139}
140
141range<double> BondGraph::CovalentMinMaxDistance(
142 const element * const Walker,
143 const element * const OtherWalker) const
144{
145 range<double> MinMaxDistance(0.,0.);
146 MinMaxDistance.first = OtherWalker->getCovalentRadius() + Walker->getCovalentRadius();
147 MinMaxDistance.first *= (IsAngstroem) ? 1. : 1. / AtomicLengthToAngstroem;
148 MinMaxDistance.last = MinMaxDistance.first + BondThreshold;
149 MinMaxDistance.first -= BondThreshold;
150 return MinMaxDistance;
151}
152
153range<double> BondGraph::BondLengthMatrixMinMaxDistance(
154 const element * const Walker,
155 const element * const OtherWalker) const
156{
157 ASSERT(BondLengthMatrix, "BondGraph::BondLengthMatrixMinMaxDistance() called without NULL BondLengthMatrix.");
158 ASSERT(Walker, "BondGraph::BondLengthMatrixMinMaxDistance() - illegal element given.");
159 ASSERT(OtherWalker, "BondGraph::BondLengthMatrixMinMaxDistance() - illegal other element given.");
160 range<double> MinMaxDistance(0.,0.);
161 MinMaxDistance.first = GetBondLength(Walker->getAtomicNumber()-1, OtherWalker->getAtomicNumber()-1);
162 MinMaxDistance.first *= (IsAngstroem) ? 1. : 1. / AtomicLengthToAngstroem;
163 MinMaxDistance.last = MinMaxDistance.first + BondThreshold;
164 MinMaxDistance.first -= BondThreshold;
165 return MinMaxDistance;
166}
167
168range<double> BondGraph::getMinMaxDistance(
169 const element * const Walker,
170 const element * const OtherWalker) const
171{
172 range<double> MinMaxDistance(0.,0.);
173 if (BondLengthMatrix == NULL) {// safety measure if no matrix has been parsed yet
174 LOG(5, "DEBUG: Using Covalent radii criterion for [min,max) distances.");
175 MinMaxDistance = CovalentMinMaxDistance(Walker, OtherWalker);
176 } else {
177 LOG(5, "DEBUG: Using tabulated bond table criterion for [min,max) distances.");
178 MinMaxDistance = BondLengthMatrixMinMaxDistance(Walker, OtherWalker);
179 }
180 return MinMaxDistance;
181}
182
183range<double> BondGraph::getMinMaxDistance(
184 const BondedParticle * const Walker,
185 const BondedParticle * const OtherWalker) const
186{
187 return getMinMaxDistance(Walker->getType(), OtherWalker->getType());
188}
189
190range<double> BondGraph::getMinMaxDistanceSquared(
191 const BondedParticle * const Walker,
192 const BondedParticle * const OtherWalker) const
193{
194 // use non-squared version
195 range<double> MinMaxDistance(getMinMaxDistance(Walker, OtherWalker));
196 // and square
197 MinMaxDistance.first *= MinMaxDistance.first;
198 MinMaxDistance.last *= MinMaxDistance.last;
199 return MinMaxDistance;
200}
201
202LinkedCell::LinkedCell_View BondGraph::getLinkedCell(const double max_distance) const
203{
204 return World::getInstance().getLinkedCell(max_distance);
205}
206
207std::set< const element *> BondGraph::getElementSetFromNumbers(const std::set<atomicNumber_t> &Set) const
208{
209 std::set< const element *> PresentElements;
210 for(std::set<atomicNumber_t>::const_iterator iter = Set.begin(); iter != Set.end(); ++iter)
211 PresentElements.insert( World::getInstance().getPeriode()->FindElement(*iter) );
212 return PresentElements;
213}
214
215Box &BondGraph::getDomain() const
216{
217 return World::getInstance().getDomain();
218}
219
220unsigned int BondGraph::getTime() const
221{
222 return WorldTime::getTime();
223}
224
225bool BondGraph::operator==(const BondGraph &other) const
226{
227 if (IsAngstroem != other.IsAngstroem)
228 return false;
229 if (((BondLengthMatrix != NULL) && (other.BondLengthMatrix == NULL))
230 || ((BondLengthMatrix == NULL) && (other.BondLengthMatrix != NULL)))
231 return false;
232 if ((BondLengthMatrix != NULL) && (other.BondLengthMatrix != NULL))
233 if (*BondLengthMatrix != *other.BondLengthMatrix)
234 return false;
235 return true;
236}
237
238/** Corrects the bond degree by one at most if necessary.
239 *
240 * We are constraint to bonds in \a egdes, if the candidate bond is in edges, we
241 * just don't increment its bond degree. We do not choose an alternative for this
242 * atom.
243 *
244 * \param edges only these edges can be updated
245 * \return number of corrections done
246 */
247int BondGraph::CorrectBondDegree(atom *_atom, const std::set<bond::ptr>& edges) const
248{
249 int NoBonds = 0;
250 int OtherNoBonds = 0;
251 int FalseBondDegree = 0;
252 int CandidateDeltaNoBonds = -1;
253 atom *OtherWalker = NULL;
254 bond::ptr CandidateBond;
255
256 NoBonds = _atom->CountBonds();
257 LOG(3, "Walker " << *_atom << ": " << (int)_atom->getType()->getNoValenceOrbitals() << " > " << NoBonds << "?");
258 const int DeltaNoBonds = (int)(_atom->getType()->getNoValenceOrbitals()) - NoBonds;
259 if (DeltaNoBonds > 0) { // we have a mismatch, check all bonding partners for mismatch
260 const BondList& ListOfBonds = _atom->getListOfBonds();
261 for (BondList::const_iterator Runner = ListOfBonds.begin(); Runner != ListOfBonds.end(); (++Runner)) {
262 OtherWalker = (*Runner)->GetOtherAtom(_atom);
263 OtherNoBonds = OtherWalker->CountBonds();
264 const int OtherDeltaNoBonds = (int)(OtherWalker->getType()->getNoValenceOrbitals()) - OtherNoBonds;
265 LOG(3, "OtherWalker " << *OtherWalker << ": " << (int)OtherWalker->getType()->getNoValenceOrbitals() << " > " << OtherNoBonds << "?");
266 if (OtherDeltaNoBonds > 0) { // check if possible candidate
267 const BondList& OtherListOfBonds = OtherWalker->getListOfBonds();
268 if ((CandidateBond == NULL)
269 || (ListOfBonds.size() > OtherListOfBonds.size()) // pick the one with fewer number of bonds first
270 || ((CandidateDeltaNoBonds < 0) || (CandidateDeltaNoBonds > OtherDeltaNoBonds)) ) // pick the one closer to fulfilling its valence first
271 {
272 CandidateDeltaNoBonds = OtherDeltaNoBonds;
273 CandidateBond = (*Runner);
274 LOG(3, "New candidate is " << *CandidateBond << ".");
275 }
276 }
277 }
278 if ((CandidateBond != NULL)) {
279 if (edges.find(CandidateBond) != edges.end()) {
280 CandidateBond->setDegree(CandidateBond->getDegree()+1);
281 LOG(2, "Increased bond degree for bond " << *CandidateBond << ".");
282 } else
283 LOG(2, "Bond " << *CandidateBond << " is not in edges.");
284 } else {
285 ELOG(2, "Could not find correct degree for atom " << *_atom << ".");
286 FalseBondDegree++;
287 }
288 }
289 return FalseBondDegree;
290}
291
292/** Sets the weight of all connected bonds to one.
293 */
294void BondGraph::resetBondDegree(atom *_atom) const
295{
296 const BondList &ListOfBonds = _atom->getListOfBonds();
297 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
298 BondRunner != ListOfBonds.end();
299 ++BondRunner)
300 (*BondRunner)->setDegree(1);
301}
302
303std::set<bond::ptr> BondGraph::getBackEdges() const
304{
305 DepthFirstSearchAnalysis DFS;
306 DFS();
307
308 const std::deque<bond::ptr>& backedgestack = DFS.getBackEdgeStack();
309 std::set<bond::ptr> backedges(backedgestack.begin(), backedgestack.end());
310
311 return backedges;
312}
313
314std::set<bond::ptr> BondGraph::getTreeEdges() const
315{
316 const std::set<bond::ptr> backedges = getBackEdges();
317 std::set<bond::ptr> alledges;
318 const World& world = World::getInstance();
319 for(World::AtomConstIterator iter = world.getAtomIter();
320 iter != world.atomEnd(); ++iter) {
321 const BondList &ListOfBonds = (*iter)->getListOfBonds();
322 alledges.insert(ListOfBonds.begin(), ListOfBonds.end());
323 }
324 std::set<bond::ptr> treeedges;
325 std::set_difference(
326 alledges.begin(), alledges.end(),
327 backedges.begin(), backedges.end(),
328 std::inserter(treeedges, treeedges.begin()));
329 return treeedges;
330}
331
332struct hasDelta {
333 bool operator()(atom *_atom) {
334 const double delta =
335 _atom->getType()->getNoValenceOrbitals() - _atom->CountBonds();
336 return (fabs(delta) > 0);
337 }
338};
339
340typedef std::set<atom *> deltaatoms_t;
341typedef std::set<bond::ptr> deltaedges_t;
342
343static int gatherAllDeltaAtoms(
344 const deltaatoms_t &allatoms,
345 deltaatoms_t &deltaatoms)
346{
347 static hasDelta delta;
348 deltaatoms.clear();
349 for (deltaatoms_t::const_iterator iter = allatoms.begin();
350 iter != allatoms.end(); ++iter) {
351 if (delta(*iter))
352 deltaatoms.insert(*iter);
353 }
354 return deltaatoms.size();
355}
356
357typedef boost::bimap<int,atom*> AtomIndexLookup_t;
358
359static AtomIndexLookup_t createAtomIndexLookup(
360 const deltaedges_t &edges)
361{
362 AtomIndexLookup_t AtomIndexLookup;
363 size_t index = 0;
364 for (deltaedges_t::const_iterator edgeiter = edges.begin();
365 edgeiter != edges.end(); ++edgeiter) {
366 const bond::ptr & _bond = *edgeiter;
367
368 // insert left into lookup
369 std::pair< AtomIndexLookup_t::iterator, bool > inserter =
370 AtomIndexLookup.insert( AtomIndexLookup_t::value_type(index, _bond->leftatom) );
371 if (inserter.second)
372 ++index;
373
374 // insert right into lookup
375 inserter = AtomIndexLookup.insert( AtomIndexLookup_t::value_type(index, _bond->rightatom) );
376 if (inserter.second)
377 ++index;
378 }
379 return AtomIndexLookup;
380}
381
382typedef std::map< std::pair<atom *, atom*>, bond::ptr> BondLookup_t;
383static BondLookup_t createBondLookup(
384 const deltaedges_t &edges)
385{
386 BondLookup_t BondLookup;
387 for (deltaedges_t::const_iterator edgeiter = edges.begin();
388 edgeiter != edges.end(); ++edgeiter) {
389 const bond::ptr & _bond = *edgeiter;
390
391 // insert bond into pair lookup
392 BondLookup.insert(
393 std::make_pair(
394 std::make_pair(_bond->leftatom, _bond->rightatom),
395 _bond)
396 );
397 }
398 return BondLookup;
399}
400
401typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> graph_t;
402typedef std::vector<boost::graph_traits<graph_t>::vertex_descriptor> mate_t;
403
404static void fillEdgesIntoMatching(
405 graph_t &g,
406 mate_t &mate,
407 const AtomIndexLookup_t &AtomIndexLookup,
408 const BondLookup_t &BondLookup,
409 deltaedges_t &matching
410 )
411{
412 matching.clear();
413 boost::graph_traits<graph_t>::vertex_iterator vi, vi_end;
414 for(tie(vi,vi_end) = boost::vertices(g); vi != vi_end; ++vi)
415 if (mate[*vi] != boost::graph_traits<graph_t>::null_vertex() && *vi < mate[*vi]) {
416 atom * leftatom = AtomIndexLookup.left.at(*vi);
417 atom * rightatom = AtomIndexLookup.left.at(mate[*vi]);
418 std::pair<atom *,atom *> AtomPair(leftatom, rightatom);
419 std::pair<atom *,atom *> reverseAtomPair(rightatom, leftatom);
420 BondLookup_t::const_iterator iter = BondLookup.find(AtomPair);
421 if (iter != BondLookup.end()) {
422 matching.insert(iter->second);
423 } else {
424 iter = BondLookup.find(reverseAtomPair);
425 if (iter != BondLookup.end()) {
426 matching.insert(iter->second);
427 } else
428 ASSERT(0, "fillEdgesIntoMatching() - cannot find ("+toString(*vi)+","
429 +toString(mate[*vi])+") in BondLookup.");
430 }
431 }
432}
433
434static bool createMatching(
435 deltaedges_t &deltaedges,
436 deltaedges_t &matching
437 )
438{
439 // gather all vertices for graph in a lookup structure
440 // to translate the graphs indices to atoms and also to associated bonds
441 AtomIndexLookup_t AtomIndexLookup = createAtomIndexLookup(deltaedges);
442 BondLookup_t BondLookup = createBondLookup(deltaedges);
443 const int n_vertices = AtomIndexLookup.size();
444
445 // construct graph
446 graph_t g(n_vertices);
447
448 // add edges to graph
449 for (deltaedges_t::const_iterator edgeiter = deltaedges.begin();
450 edgeiter != deltaedges.end(); ++edgeiter) {
451 const bond::ptr & _bond = *edgeiter;
452 boost::add_edge(
453 AtomIndexLookup.right.at(_bond->leftatom),
454 AtomIndexLookup.right.at(_bond->rightatom),
455 g);
456 }
457
458 // mate structure contains unique edge partner to every vertex in matching
459 mate_t mate(n_vertices);
460
461 // get maximum matching over given edges
462 bool success = boost::checked_edmonds_maximum_cardinality_matching(g, &mate[0]);
463
464 if (success) {
465 LOG(1, "STATUS: Found a matching of size " << matching_size(g, &mate[0]) << ".");
466 fillEdgesIntoMatching(g, mate, AtomIndexLookup, BondLookup, matching);
467 } else {
468 ELOG(2, "Failed to find maximum matching.");
469 }
470
471 return success;
472}
473
474
475int BondGraph::calculateBondDegree(const deltaatoms_t &allatoms) const
476{
477 deltaatoms_t deltaatoms;
478 deltaedges_t deltaedges;
479 deltaedges_t matching;
480
481 LOG(1, "STATUS: Calculating bond degrees.");
482 if (DoLog(2)) {
483 std::stringstream output;
484 output << "INFO: All atoms are: ";
485 BOOST_FOREACH( atom *_atom, allatoms) {
486 output << *_atom << " ";
487 }
488 LOG(2, output.str());
489 }
490
491 size_t IterCount = 0;
492 // 1. gather all atoms with delta > 0
493 while ((gatherAllDeltaAtoms(allatoms, deltaatoms) != 0) && (IterCount < 100)) {
494 if (DoLog(3)) {
495 std::stringstream output;
496 output << "DEBUG: Current delta atoms are: ";
497 BOOST_FOREACH( atom *_atom, deltaatoms) {
498 output << *_atom << " ";
499 }
500 LOG(3, output.str());
501 }
502
503 // 2. gather all edges that connect atoms with both(!) having delta > 0
504 deltaedges.clear();
505 for (deltaatoms_t::const_iterator atomiter = deltaatoms.begin();
506 atomiter != deltaatoms.end(); ++atomiter) {
507 const atom * const _atom = *atomiter;
508 const BondList& ListOfBonds = (*atomiter)->getListOfBonds();
509 for (BondList::const_iterator bonditer = ListOfBonds.begin();
510 bonditer != ListOfBonds.end();++bonditer) {
511 const bond::ptr _bond = *bonditer;
512 if ((_bond->leftatom == _atom) && (deltaatoms.find(_bond->rightatom) != deltaatoms.end()))
513 deltaedges.insert(_bond);
514 else if ((_bond->rightatom == _atom) && (deltaatoms.find(_bond->leftatom) != deltaatoms.end()))
515 deltaedges.insert(_bond);
516 }
517 }
518 if (DoLog(3)) {
519 std::stringstream output;
520 output << "DEBUG: Current delta bonds are: ";
521 BOOST_FOREACH( bond::ptr _bond, deltaedges) {
522 output << *_bond << " ";
523 }
524 LOG(3, output.str());
525 }
526 if (deltaedges.empty())
527 break;
528
529 // 3. build matching over these edges
530 if (!createMatching(deltaedges, matching))
531 break;
532 if (DoLog(2)) {
533 std::stringstream output;
534 output << "DEBUG: Resulting matching is: ";
535 BOOST_FOREACH( bond::ptr _bond, matching) {
536 output << *_bond << " ";
537 }
538 LOG(2, output.str());
539 }
540
541 // 4. increase degree for each edge of the matching
542 LOG(2, "DEBUG: Increasing bond degrees by one.");
543 for (deltaedges_t::iterator edgeiter = matching.begin();
544 edgeiter != matching.end(); ++edgeiter) {
545 (*edgeiter)->setDegree( (*edgeiter)->getDegree()+1 );
546 }
547
548 // 6. stop after a given number of iterations or when all atoms are happy.
549 ++IterCount;
550 };
551
552 // check whether we still have deltaatoms
553 {
554 hasDelta delta;
555 for (deltaatoms_t::const_iterator iter = allatoms.begin();
556 iter != allatoms.end(); ++iter)
557 if (delta(*iter))
558 ELOG(2, "Could not find satisfy charge neutrality for atom " << **iter << ".");
559 }
560
561 return deltaedges.size();
562}
Note: See TracBrowser for help on using the repository browser.