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