| [bcf653] | 1 | /*
 | 
|---|
 | 2 |  * Project: MoleCuilder
 | 
|---|
 | 3 |  * Description: creates and alters molecular systems
 | 
|---|
| [0aa122] | 4 |  * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 | 
|---|
| [94d5ac6] | 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/>.
 | 
|---|
| [bcf653] | 21 |  */
 | 
|---|
 | 22 | 
 | 
|---|
| [b70721] | 23 | /*
 | 
|---|
 | 24 |  * bondgraph.cpp
 | 
|---|
 | 25 |  *
 | 
|---|
 | 26 |  *  Created on: Oct 29, 2009
 | 
|---|
 | 27 |  *      Author: heber
 | 
|---|
 | 28 |  */
 | 
|---|
 | 29 | 
 | 
|---|
| [bf3817] | 30 | // include config.h
 | 
|---|
 | 31 | #ifdef HAVE_CONFIG_H
 | 
|---|
 | 32 | #include <config.h>
 | 
|---|
 | 33 | #endif
 | 
|---|
 | 34 | 
 | 
|---|
| [4f04ab8] | 35 | // boost::graph uses placement new
 | 
|---|
 | 36 | #include <boost/graph/adjacency_list.hpp>
 | 
|---|
 | 37 | 
 | 
|---|
| [ad011c] | 38 | #include "CodePatterns/MemDebug.hpp"
 | 
|---|
| [112b09] | 39 | 
 | 
|---|
| [4f04ab8] | 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>
 | 
|---|
| [326000] | 46 | #include <deque>
 | 
|---|
| [b70721] | 47 | #include <iostream>
 | 
|---|
 | 48 | 
 | 
|---|
| [6f0841] | 49 | #include "Atom/atom.hpp"
 | 
|---|
| [129204] | 50 | #include "Bond/bond.hpp"
 | 
|---|
| [632508] | 51 | #include "Graph/BondGraph.hpp"
 | 
|---|
| [3738f0] | 52 | #include "Box.hpp"
 | 
|---|
| [3bdb6d] | 53 | #include "Element/element.hpp"
 | 
|---|
| [ad011c] | 54 | #include "CodePatterns/Info.hpp"
 | 
|---|
 | 55 | #include "CodePatterns/Log.hpp"
 | 
|---|
| [3738f0] | 56 | #include "CodePatterns/Range.hpp"
 | 
|---|
 | 57 | #include "CodePatterns/Verbose.hpp"
 | 
|---|
| [b70721] | 58 | #include "molecule.hpp"
 | 
|---|
| [3bdb6d] | 59 | #include "Element/periodentafel.hpp"
 | 
|---|
| [a9b86d] | 60 | #include "Fragmentation/MatrixContainer.hpp"
 | 
|---|
| [326000] | 61 | #include "Graph/DepthFirstSearchAnalysis.hpp"
 | 
|---|
| [57f243] | 62 | #include "LinearAlgebra/Vector.hpp"
 | 
|---|
| [3738f0] | 63 | #include "World.hpp"
 | 
|---|
 | 64 | #include "WorldTime.hpp"
 | 
|---|
| [b70721] | 65 | 
 | 
|---|
| [88b400] | 66 | 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
 | 
|---|
 | 67 | 
 | 
|---|
| [f007a1] | 68 | BondGraph::BondGraph() :
 | 
|---|
 | 69 |     BondLengthMatrix(NULL),
 | 
|---|
 | 70 |     IsAngstroem(true)
 | 
|---|
 | 71 | {}
 | 
|---|
 | 72 | 
 | 
|---|
| [97b825] | 73 | BondGraph::BondGraph(bool IsA) :
 | 
|---|
 | 74 |     BondLengthMatrix(NULL),
 | 
|---|
 | 75 |     IsAngstroem(IsA)
 | 
|---|
| [3738f0] | 76 | {}
 | 
|---|
| [b70721] | 77 | 
 | 
|---|
 | 78 | BondGraph::~BondGraph()
 | 
|---|
| [829761] | 79 | {
 | 
|---|
 | 80 |   CleanupBondLengthTable();
 | 
|---|
 | 81 | }
 | 
|---|
 | 82 | 
 | 
|---|
 | 83 | void BondGraph::CleanupBondLengthTable()
 | 
|---|
| [b70721] | 84 | {
 | 
|---|
 | 85 |   if (BondLengthMatrix != NULL) {
 | 
|---|
 | 86 |     delete(BondLengthMatrix);
 | 
|---|
 | 87 |   }
 | 
|---|
| [3738f0] | 88 | }
 | 
|---|
| [b70721] | 89 | 
 | 
|---|
| [111f4a] | 90 | bool BondGraph::LoadBondLengthTable(
 | 
|---|
 | 91 |     std::istream &input)
 | 
|---|
| [b70721] | 92 | {
 | 
|---|
| [244a84] | 93 |   Info FunctionInfo(__func__);
 | 
|---|
| [b70721] | 94 |   bool status = true;
 | 
|---|
| [34e0013] | 95 |   MatrixContainer *TempContainer = NULL;
 | 
|---|
| [b70721] | 96 | 
 | 
|---|
 | 97 |   // allocate MatrixContainer
 | 
|---|
 | 98 |   if (BondLengthMatrix != NULL) {
 | 
|---|
| [3738f0] | 99 |     LOG(1, "MatrixContainer for Bond length already present, removing.");
 | 
|---|
| [b70721] | 100 |     delete(BondLengthMatrix);
 | 
|---|
| [829761] | 101 |     BondLengthMatrix = NULL;
 | 
|---|
| [b70721] | 102 |   }
 | 
|---|
| [34e0013] | 103 |   TempContainer = new MatrixContainer;
 | 
|---|
| [b70721] | 104 | 
 | 
|---|
 | 105 |   // parse in matrix
 | 
|---|
| [4e855e] | 106 |   if ((input.good()) && (status = TempContainer->ParseMatrix(input, 0, 1, 0))) {
 | 
|---|
| [3738f0] | 107 |     LOG(1, "Parsing bond length matrix successful.");
 | 
|---|
| [244a84] | 108 |   } else {
 | 
|---|
| [47d041] | 109 |     ELOG(1, "Parsing bond length matrix failed.");
 | 
|---|
| [4e855e] | 110 |     status = false;
 | 
|---|
| [244a84] | 111 |   }
 | 
|---|
| [b70721] | 112 | 
 | 
|---|
| [34e0013] | 113 |   if (status) // set to not NULL only if matrix was parsed
 | 
|---|
 | 114 |     BondLengthMatrix = TempContainer;
 | 
|---|
 | 115 |   else {
 | 
|---|
 | 116 |     BondLengthMatrix = NULL;
 | 
|---|
 | 117 |     delete(TempContainer);
 | 
|---|
 | 118 |   }
 | 
|---|
| [b70721] | 119 |   return status;
 | 
|---|
| [3738f0] | 120 | }
 | 
|---|
| [b70721] | 121 | 
 | 
|---|
| [300220] | 122 | double BondGraph::GetBondLength(
 | 
|---|
 | 123 |     int firstZ,
 | 
|---|
 | 124 |     int secondZ) const
 | 
|---|
| [b70721] | 125 | {
 | 
|---|
| [826e8c] | 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.;
 | 
|---|
| [4e855e] | 131 |   if (BondLengthMatrix == NULL) {
 | 
|---|
| [826e8c] | 132 |     return_length = -1.;
 | 
|---|
| [4e855e] | 133 |   } else {
 | 
|---|
| [826e8c] | 134 |     return_length = BondLengthMatrix->Matrix[0][firstZ][secondZ];
 | 
|---|
| [4e855e] | 135 |   }
 | 
|---|
| [826e8c] | 136 |   LOG(4, "INFO: Request for length between " << firstZ << " and "
 | 
|---|
 | 137 |       << secondZ << ": " << return_length << ".");
 | 
|---|
 | 138 |   return return_length;
 | 
|---|
| [3738f0] | 139 | }
 | 
|---|
| [ae38fb] | 140 | 
 | 
|---|
| [607eab] | 141 | range<double> BondGraph::CovalentMinMaxDistance(
 | 
|---|
| [300220] | 142 |     const element * const Walker,
 | 
|---|
| [607eab] | 143 |     const element * const OtherWalker) const
 | 
|---|
| [b70721] | 144 | {
 | 
|---|
| [607eab] | 145 |   range<double> MinMaxDistance(0.,0.);
 | 
|---|
| [300220] | 146 |   MinMaxDistance.first = OtherWalker->getCovalentRadius() + Walker->getCovalentRadius();
 | 
|---|
 | 147 |   MinMaxDistance.first *= (IsAngstroem) ? 1. : 1. / AtomicLengthToAngstroem;
 | 
|---|
 | 148 |   MinMaxDistance.last = MinMaxDistance.first + BondThreshold;
 | 
|---|
 | 149 |   MinMaxDistance.first -= BondThreshold;
 | 
|---|
| [607eab] | 150 |   return MinMaxDistance;
 | 
|---|
| [3738f0] | 151 | }
 | 
|---|
| [b70721] | 152 | 
 | 
|---|
| [607eab] | 153 | range<double> BondGraph::BondLengthMatrixMinMaxDistance(
 | 
|---|
| [300220] | 154 |     const element * const Walker,
 | 
|---|
| [607eab] | 155 |     const element * const OtherWalker) const
 | 
|---|
| [72d90e] | 156 | {
 | 
|---|
| [300220] | 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.");
 | 
|---|
| [607eab] | 160 |   range<double> MinMaxDistance(0.,0.);
 | 
|---|
| [300220] | 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;
 | 
|---|
| [607eab] | 165 |   return MinMaxDistance;
 | 
|---|
| [3738f0] | 166 | }
 | 
|---|
| [72d90e] | 167 | 
 | 
|---|
| [607eab] | 168 | range<double> BondGraph::getMinMaxDistance(
 | 
|---|
| [300220] | 169 |     const element * const Walker,
 | 
|---|
| [607eab] | 170 |     const element * const OtherWalker) const
 | 
|---|
| [b70721] | 171 | {
 | 
|---|
| [607eab] | 172 |   range<double> MinMaxDistance(0.,0.);
 | 
|---|
| [34e0013] | 173 |   if (BondLengthMatrix == NULL) {// safety measure if no matrix has been parsed yet
 | 
|---|
| [8ac66b4] | 174 |     LOG(5, "DEBUG: Using Covalent radii criterion for [min,max) distances.");
 | 
|---|
| [607eab] | 175 |     MinMaxDistance = CovalentMinMaxDistance(Walker, OtherWalker);
 | 
|---|
| [b21a64] | 176 |   } else {
 | 
|---|
| [8ac66b4] | 177 |     LOG(5, "DEBUG: Using tabulated bond table criterion for [min,max) distances.");
 | 
|---|
| [607eab] | 178 |     MinMaxDistance = BondLengthMatrixMinMaxDistance(Walker, OtherWalker);
 | 
|---|
| [b21a64] | 179 |   }
 | 
|---|
| [607eab] | 180 |   return MinMaxDistance;
 | 
|---|
| [72d90e] | 181 | }
 | 
|---|
| [3738f0] | 182 | 
 | 
|---|
| [607eab] | 183 | range<double> BondGraph::getMinMaxDistance(
 | 
|---|
| [300220] | 184 |     const BondedParticle * const Walker,
 | 
|---|
| [607eab] | 185 |     const BondedParticle * const OtherWalker) const
 | 
|---|
| [300220] | 186 | {
 | 
|---|
| [607eab] | 187 |   return getMinMaxDistance(Walker->getType(), OtherWalker->getType());
 | 
|---|
| [300220] | 188 | }
 | 
|---|
 | 189 | 
 | 
|---|
| [607eab] | 190 | range<double> BondGraph::getMinMaxDistanceSquared(
 | 
|---|
| [300220] | 191 |     const BondedParticle * const Walker,
 | 
|---|
| [607eab] | 192 |     const BondedParticle * const OtherWalker) const
 | 
|---|
| [300220] | 193 | {
 | 
|---|
 | 194 |   // use non-squared version
 | 
|---|
| [607eab] | 195 |   range<double> MinMaxDistance(getMinMaxDistance(Walker, OtherWalker));
 | 
|---|
| [300220] | 196 |   // and square
 | 
|---|
 | 197 |   MinMaxDistance.first *= MinMaxDistance.first;
 | 
|---|
 | 198 |   MinMaxDistance.last *= MinMaxDistance.last;
 | 
|---|
| [607eab] | 199 |   return MinMaxDistance;
 | 
|---|
| [300220] | 200 | }
 | 
|---|
 | 201 | 
 | 
|---|
| [826e8c] | 202 | LinkedCell::LinkedCell_View BondGraph::getLinkedCell(const double max_distance) const
 | 
|---|
| [3738f0] | 203 | {
 | 
|---|
| [826e8c] | 204 |   return World::getInstance().getLinkedCell(max_distance);
 | 
|---|
 | 205 | }
 | 
|---|
 | 206 | 
 | 
|---|
| [108968] | 207 | std::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 | 
 | 
|---|
| [826e8c] | 215 | Box &BondGraph::getDomain() const
 | 
|---|
 | 216 | {
 | 
|---|
 | 217 |   return World::getInstance().getDomain();
 | 
|---|
 | 218 | }
 | 
|---|
 | 219 | 
 | 
|---|
 | 220 | unsigned int BondGraph::getTime() const
 | 
|---|
 | 221 | {
 | 
|---|
 | 222 |   return WorldTime::getTime();
 | 
|---|
| [3738f0] | 223 | }
 | 
|---|
| [0cbad2] | 224 | 
 | 
|---|
| [9b6663] | 225 | bool 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 | }
 | 
|---|
| [378fc6b] | 237 | 
 | 
|---|
 | 238 | /** Corrects the bond degree by one at most if necessary.
 | 
|---|
| [326000] | 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
 | 
|---|
| [378fc6b] | 245 |  * \return number of corrections done
 | 
|---|
 | 246 |  */
 | 
|---|
| [326000] | 247 | int BondGraph::CorrectBondDegree(atom *_atom, const std::set<bond::ptr>& edges) const
 | 
|---|
| [378fc6b] | 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)) {
 | 
|---|
| [326000] | 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.");
 | 
|---|
| [378fc6b] | 284 |     } else {
 | 
|---|
 | 285 |       ELOG(2, "Could not find correct degree for atom " << *_atom << ".");
 | 
|---|
 | 286 |       FalseBondDegree++;
 | 
|---|
 | 287 |     }
 | 
|---|
 | 288 |   }
 | 
|---|
 | 289 |   return FalseBondDegree;
 | 
|---|
| [326000] | 290 | }
 | 
|---|
| [378fc6b] | 291 | 
 | 
|---|
 | 292 | /** Sets the weight of all connected bonds to one.
 | 
|---|
 | 293 |  */
 | 
|---|
 | 294 | void 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);
 | 
|---|
| [326000] | 301 | }
 | 
|---|
 | 302 | 
 | 
|---|
 | 303 | std::set<bond::ptr> BondGraph::getBackEdges() const
 | 
|---|
 | 304 | {
 | 
|---|
 | 305 |   DepthFirstSearchAnalysis DFS;
 | 
|---|
 | 306 |   DFS();
 | 
|---|
| [378fc6b] | 307 | 
 | 
|---|
| [326000] | 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 | 
 | 
|---|
 | 314 | std::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 | }
 | 
|---|
| [4f04ab8] | 331 | 
 | 
|---|
 | 332 | struct hasDelta {
 | 
|---|
 | 333 |   bool operator()(atom *_atom) {
 | 
|---|
 | 334 |     const double delta =
 | 
|---|
 | 335 |         _atom->getType()->getNoValenceOrbitals() - _atom->CountBonds();
 | 
|---|
 | 336 |     return (fabs(delta) > 0);
 | 
|---|
 | 337 |   }
 | 
|---|
 | 338 | };
 | 
|---|
 | 339 | 
 | 
|---|
 | 340 | typedef std::set<atom *> deltaatoms_t;
 | 
|---|
 | 341 | typedef std::set<bond::ptr> deltaedges_t;
 | 
|---|
 | 342 | 
 | 
|---|
 | 343 | static 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 | 
 | 
|---|
 | 357 | typedef boost::bimap<int,atom*> AtomIndexLookup_t;
 | 
|---|
 | 358 | 
 | 
|---|
 | 359 | static 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 | 
 | 
|---|
 | 382 | typedef std::map< std::pair<atom *, atom*>, bond::ptr> BondLookup_t;
 | 
|---|
 | 383 | static 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 | 
 | 
|---|
 | 401 | typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> graph_t;
 | 
|---|
 | 402 | typedef std::vector<boost::graph_traits<graph_t>::vertex_descriptor> mate_t;
 | 
|---|
 | 403 | 
 | 
|---|
 | 404 | static 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 | 
 | 
|---|
 | 434 | static 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 | 
 | 
|---|
 | 475 | int 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 | }
 | 
|---|