source: src/Graph/BondGraph.hpp@ b4f72c

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

FIX: Rewrite of BondGraph's CreateAdjacency() and getMaxPossibleBondDistance().

  • getMaxPossibleBondDistance() is not templated anymore but expects simply a set of atomicNumber_t.
  • new helper function BondGraph::getElementSetFromNumbers() which converts a set of atomicNumber_t into a set of elements.
  • createAdjacency now prepares initially the set of atomicNumber_t and from it the set of elements such that no further element lookups are necessary except once for each atom's element.
  • Property mode set to 100644
File size: 19.6 KB
Line 
1/*
2 * bondgraph.hpp
3 *
4 * Created on: Oct 29, 2009
5 * Author: heber
6 */
7
8#ifndef BONDGRAPH_HPP_
9#define BONDGRAPH_HPP_
10
11using namespace std;
12
13/*********************************************** includes ***********************************/
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include <iosfwd>
21#include <set>
22
23#include <boost/serialization/array.hpp>
24
25#include "Atom/AtomSet.hpp"
26#include "Bond/bond.hpp"
27#include "Box.hpp"
28#include "CodePatterns/Assert.hpp"
29#include "CodePatterns/Log.hpp"
30#include "CodePatterns/Range.hpp"
31#include "Element/element.hpp"
32#include "Fragmentation/MatrixContainer.hpp"
33#include "Helpers/defs.hpp"
34#include "LinkedCell/LinkedCell_View.hpp"
35#include "LinkedCell/IPointCloud.hpp"
36#include "LinkedCell/PointCloudAdaptor.hpp"
37#include "WorldTime.hpp"
38
39/****************************************** forward declarations *****************************/
40
41class molecule;
42class BondedParticle;
43class MatrixContainer;
44
45/********************************************** definitions *********************************/
46
47/********************************************** declarations *******************************/
48
49
50class BondGraph {
51 //!> analysis bonds unit test should be friend to access private parts.
52 friend class AnalysisBondsTest;
53 //!> own bond graph unit test should be friend to access private parts.
54 friend class BondGraphTest;
55public:
56 /** Constructor of class BondGraph.
57 * This classes contains typical bond lengths and thus may be used to construct a bond graph for a given molecule.
58 */
59 BondGraph(bool IsA);
60
61 /** Destructor of class BondGraph.
62 */
63 ~BondGraph();
64
65 /** Parses the bond lengths in a given file and puts them int a matrix form.
66 * Allocates \a MatrixContainer for BondGraph::BondLengthMatrix, using MatrixContainer::ParseMatrix(),
67 * but only if parsing is successful. Otherwise variable is left as NULL.
68 * \param &input input stream to parse table from
69 * \return true - success in parsing file, false - failed to parse the file
70 */
71 bool LoadBondLengthTable(std::istream &input);
72
73 /** Removes allocated bond length table.
74 *
75 */
76 void CleanupBondLengthTable();
77
78 /** Internal helper to convert a set of atomicNumber_t to element refs.
79 *
80 * @param Set set of atomicNumber_t
81 * @return set of element refs
82 */
83 std::set< const element *> getElementSetFromNumbers(const std::set<atomicNumber_t> &Set) const;
84
85 /** Determines the maximum of all element::CovalentRadius for elements present in \a &Set.
86 *
87 * I.e. the function returns a sensible cutoff criteria for bond recognition,
88 * e.g. to be used for LinkedCell_deprecated or others.
89 *
90 * \param &PresentElements set of elements whose maximal pair to find
91 */
92 double getMaxPossibleBondDistance(
93 const std::set< const element *> &PresentElements) const
94 {
95 double max_distance = 0.;
96
97 // create all element combinations
98 for (std::set< const element *>::const_iterator iter = PresentElements.begin();
99 iter != PresentElements.end();
100 ++iter) {
101 for (std::set< const element *>::const_iterator otheriter = iter;
102 otheriter != PresentElements.end();
103 ++otheriter) {
104 const range<double> MinMaxDistance(getMinMaxDistance((*iter),(*otheriter)));
105 if (MinMaxDistance.last > max_distance)
106 max_distance = MinMaxDistance.last;
107 }
108 }
109 return max_distance;
110 }
111
112 /** Determines the maximum of all element::CovalentRadius for elements present in \a &Set.
113 *
114 * I.e. the function returns a sensible cutoff criteria for bond recognition,
115 * e.g. to be used for LinkedCell_deprecated or others.
116 *
117 * \param Walker element first element in the pair
118 * \param &PresentElements set of elements whose maximal pair to find
119 */
120 double getMaxPossibleBondDistance(
121 const element * const Walker,
122 const std::set< const element *> &PresentElements) const
123 {
124 double max_distance = 0.;
125
126 // create all element combinations
127 for (std::set< const element *>::const_iterator iter = PresentElements.begin();
128 iter != PresentElements.end();
129 ++iter) {
130 const range<double> MinMaxDistance(getMinMaxDistance((*iter),Walker));
131 if (MinMaxDistance.last > max_distance)
132 max_distance = MinMaxDistance.last;
133 }
134 return max_distance;
135 }
136
137 /** Returns bond criterion for given pair based on a bond length matrix.
138 * This calls element-version of getMinMaxDistance().
139 * \param *Walker first BondedParticle
140 * \param *OtherWalker second BondedParticle
141 * \return Range with bond interval
142 */
143 range<double> getMinMaxDistance(
144 const BondedParticle * const Walker,
145 const BondedParticle * const OtherWalker) const;
146
147 /** Returns SQUARED bond criterion for given pair based on a bond length matrix.
148 * This calls element-version of getMinMaxDistance() and squares the values
149 * of either interval end.
150 * \param *Walker first BondedParticle
151 * \param *OtherWalker second BondedParticle
152 * \return Range with bond interval
153 */
154 range<double> getMinMaxDistanceSquared(
155 const BondedParticle * const Walker,
156 const BondedParticle * const OtherWalker) const;
157
158 /** Creates an adjacency list of the molecule.
159 * Generally, we use the CSD approach to bond recognition, that is the the distance
160 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
161 * a threshold t = 0.4 Angstroem.
162 * To make it O(N log N) the function uses the linked-cell technique as follows:
163 * The procedure is step-wise:
164 * -# Remove every bond in list
165 * -# go through every atom in given \a set, check the atoms therein against all possible bond partners, add bond if true
166 * -# correct the bond degree iteratively (single->double->triple bond)
167 * -# finally print the bond list to \a *out if desired
168 * \param &set Container with all atoms to create adjacency for
169 */
170 template <class container_type,
171 class iterator_type,
172 class const_iterator_type>
173 void CreateAdjacency(
174 AtomSetMixin<container_type,iterator_type,const_iterator_type> &Set) const
175 {
176 LOG(1, "STATUS: Removing all present bonds.");
177 cleanAdjacencyList(Set);
178
179 // gather set of all present elements
180 std::set<atomicNumber_t> elements;
181 for(typename AtomSetMixin<container_type,iterator_type,const_iterator_type>::iterator iter = Set.begin();
182 iter != Set.end(); ++iter) {
183 const atom * const Walker = dynamic_cast<const atom *>(*iter);
184 ASSERT(Walker != NULL,
185 "BondGraph::CreateAdjacency() - TesselPoint "
186 +(*iter)->getName()+" that was not an atom retrieved from given set");
187 elements.insert( Walker->getElementNo() );
188 }
189 // get all elements
190 std::set< const element *> PresentElements = getElementSetFromNumbers(elements);
191
192 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering)
193 const unsigned int counter = Set.size();
194 if (counter > 1) {
195 LOG(1, "STATUS: Setting max bond distance.");
196 LinkedCell::LinkedCell_View LC = getLinkedCell(getMaxPossibleBondDistance(PresentElements));
197
198 LOG(1, "STATUS: Creating LinkedCell structure for given " << counter << " atoms.");
199
200 Box &domain = getDomain();
201 unsigned int CurrentTime = getTime();
202
203 unsigned int BondCount = 0;
204 // go through every atom in the set (observed cause we change its bonds)
205 for(typename AtomSetMixin<container_type,iterator_type,const_iterator_type>::iterator iter = Set.begin();
206 iter != Set.end(); ++iter) {
207 const atom * const Walker = dynamic_cast<const atom *>(*iter);
208 ASSERT(Walker != NULL,
209 "BondGraph::CreateAdjacency() - TesselPoint "
210 +(*iter)->getName()+" that was not an atom retrieved from given set");
211 LOG(2, "INFO: Current Atom is " << *Walker << ".");
212
213 // obtain all possible neighbors
214 LinkedCell::LinkedList ListOfNeighbors = LC.getAllNeighbors(
215 getMaxPossibleBondDistance(Walker->getType(), PresentElements),
216 Walker->getPosition());
217 if (!ListOfNeighbors.empty()) {
218 // we have some possible candidates, go through each
219 for (LinkedCell::LinkedList::const_iterator neighboriter = ListOfNeighbors.begin();
220 neighboriter != ListOfNeighbors.end();
221 ++neighboriter) {
222 if ((*neighboriter) > Walker) { // just to not add bonds from both sides
223 const atom * const OtherWalker = dynamic_cast<const atom *>(*neighboriter);
224 ASSERT(OtherWalker != NULL,
225 "BondGraph::CreateAdjacency() - TesselPoint "
226 +(*neighboriter)->getName()+" that was not an atom retrieved from LinkedList");
227 LOG(3, "INFO: Current other atom is " << *OtherWalker << ".");
228
229 const range<double> MinMaxDistanceSquared(
230 getMinMaxDistanceSquared(Walker, OtherWalker));
231 const double distance = domain.periodicDistanceSquared(OtherWalker->getPosition(),Walker->getPosition());
232 LOG(3, "INFO: Checking squared distance " << distance << " against typical bond length of " << MinMaxDistanceSquared << ".");
233 const bool status = MinMaxDistanceSquared.isInRange(distance);
234 if (status) { // create bond if distance is smaller
235 LOG(1, "ACCEPT: Adding Bond between " << *Walker << " and " << *OtherWalker << " in distance " << sqrt(distance) << ".");
236 // directly use iter to avoid const_cast'ing Walker, too
237 //const bond * Binder =
238 const_cast<atom *>(Walker)->addBond(CurrentTime, const_cast<atom *>(OtherWalker));
239 ++BondCount;
240 } else {
241 LOG(2, "REJECT: Squared distance "
242 << distance << " is out of squared covalent bounds "
243 << MinMaxDistanceSquared << ".");
244 }
245
246 } else {
247 LOG(5, "REJECT: Not Adding: Wrong order.");
248 }
249 }
250 }
251 }
252 LOG(1, "I detected " << BondCount << " bonds in the molecule.");
253
254 // correct bond degree by comparing valence and bond degree
255 LOG(1, "STATUS: Correcting bond degree.");
256 CorrectBondDegree(Set);
257
258 // output bonds for debugging (if bond chain list was correctly installed)
259 LOG(2, "STATUS: Printing list of created bonds.");
260 std::stringstream output;
261 for(const_iterator_type AtomRunner = Set.begin(); AtomRunner != Set.end(); ++AtomRunner) {
262 (*AtomRunner)->OutputBondOfAtom(output);
263 output << std::endl << "\t\t";
264 }
265 LOG(2, output.str());
266 } else {
267 LOG(1, "REJECT: AtomCount is " << counter << ", thus no bonds, no connections.");
268 }
269 }
270
271 /** Creates an adjacency list of the given \a Set of atoms.
272 *
273 * Note that the input stream is required to refer to the same number of
274 * atoms also contained in \a Set.
275 *
276 * \param &Set container with atoms
277 * \param *input input stream to parse
278 * \param skiplines how many header lines to skip
279 * \param id_offset is base id compared to World startin at 0
280 */
281 template <class container_type,
282 class iterator_type,
283 class const_iterator_type>
284 void CreateAdjacencyListFromDbondFile(
285 AtomSetMixin<container_type,iterator_type,const_iterator_type> &Set,
286 ifstream *input,
287 unsigned int skiplines,
288 int id_offset) const
289 {
290 char line[MAXSTRINGSIZE];
291
292 // check input stream
293 if (input->fail()) {
294 ELOG(0, "Opening of bond file failed \n");
295 return;
296 };
297 // skip headers
298 for (unsigned int i=0;i<skiplines;i++)
299 input->getline(line,MAXSTRINGSIZE);
300
301 // create lookup map
302 LOG(1, "STATUS: Creating lookup map.");
303 std::map< unsigned int, atom *> AtomLookup;
304 unsigned int counter = id_offset; // if ids do not start at 0
305 for (iterator_type iter = Set.begin(); iter != Set.end(); ++iter) {
306 AtomLookup.insert( make_pair( counter++, *iter) );
307 }
308 LOG(2, "INFO: There are " << counter << " atoms in the given set.");
309
310 LOG(1, "STATUS: Scanning file.");
311 unsigned int atom1, atom2;
312 unsigned int bondcounter = 0;
313 while (!input->eof()) // Check whether we read everything already
314 {
315 input->getline(line,MAXSTRINGSIZE);
316 stringstream zeile(line);
317 if (zeile.str().empty())
318 continue;
319 zeile >> atom1;
320 zeile >> atom2;
321
322 LOG(4, "INFO: Looking for atoms " << atom1 << " and " << atom2 << ".");
323 if (atom2 < atom1) //Sort indices of atoms in order
324 std::swap(atom1, atom2);
325 ASSERT(atom2 < counter,
326 "BondGraph::CreateAdjacencyListFromDbondFile() - ID "
327 +toString(atom2)+" exceeds number of present atoms "+toString(counter)+".");
328 ASSERT(AtomLookup.count(atom1),
329 "BondGraph::CreateAdjacencyListFromDbondFile() - Could not find an atom with the ID given in dbond file");
330 ASSERT(AtomLookup.count(atom2),
331 "BondGraph::CreateAdjacencyListFromDbondFile() - Could not find an atom with the ID given in dbond file");
332 atom * const Walker = AtomLookup[atom1];
333 atom * const OtherWalker = AtomLookup[atom2];
334
335 LOG(3, "INFO: Creating bond between atoms " << atom1 << " and " << atom2 << ".");
336 //const bond * Binder =
337 Walker->addBond(WorldTime::getTime(), OtherWalker);
338 bondcounter++;
339 }
340 LOG(1, "STATUS: "<< bondcounter << " bonds have been parsed.");
341 }
342
343 /** Removes all bonds within the given set of iterable atoms.
344 *
345 * @param Set Range with atoms
346 */
347 template <class container_type,
348 class iterator_type,
349 class const_iterator_type>
350 void cleanAdjacencyList(
351 AtomSetMixin<container_type,iterator_type,const_iterator_type> &Set) const
352 {
353 // remove every bond from the list
354 for(iterator_type AtomRunner = Set.begin(); AtomRunner != Set.end(); ++AtomRunner) {
355 (*AtomRunner)->removeAllBonds();
356// BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
357// for(BondList::iterator BondRunner = ListOfBonds.begin();
358// !ListOfBonds.empty();
359// BondRunner = ListOfBonds.begin()) {
360// ASSERT((*BondRunner)->Contains(*AtomRunner),
361// "BondGraph::cleanAdjacencyList() - "+
362// toString(*BondRunner)+" does not contain "+
363// toString(*AtomRunner)+".");
364// delete((*BondRunner));
365// }
366 }
367 }
368
369 /** correct bond degree by comparing valence and bond degree.
370 * correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees,
371 * iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene
372 * preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of
373 * double bonds as was expected.
374 * @param Set Range with atoms
375 * \return number of bonds that could not be corrected
376 */
377 template <class container_type,
378 class iterator_type,
379 class const_iterator_type>
380 int CorrectBondDegree(
381 AtomSetMixin<container_type,iterator_type,const_iterator_type> &Set) const
382 {
383 // reset
384 resetBondDegree(Set);
385 // re-calculate
386 return calculateBondDegree(Set);
387 }
388
389 /** Equality comparator for class BondGraph.
390 *
391 * @param other other instance to compare to
392 * @return true - if equal in every member variable, except static
393 * \a BondGraph::BondThreshold.
394 */
395 bool operator==(const BondGraph &other) const;
396
397 /** Unequality comparator for class BondGraph.
398 *
399 * @param other other instance to compare to
400 * @return false - if equal in every member variable, except static
401 * \a BondGraph::BondThreshold.
402 */
403 bool operator!=(const BondGraph &other) const {
404 return !(*this == other);
405 }
406
407private:
408 /** Convenience function to place access to World::getLinkedCell() into source module.
409 *
410 * @return ref to LinkedCell_View
411 */
412 LinkedCell::LinkedCell_View getLinkedCell(const double max_distance) const;
413
414 /** Convenience function to place access to World::getDomain() into source module.
415 *
416 * @return ref to Box
417 */
418 Box &getDomain() const;
419
420 /** Convenience function to place access to WorldTime::getTime() into source module.
421 *
422 * @return current time step
423 */
424 unsigned int getTime() const;
425
426 /** Returns the BondLengthMatrix entry for a given index pair.
427 * \param firstelement index/atom number of first element (row index)
428 * \param secondelement index/atom number of second element (column index)
429 * \note matrix is of course symmetric.
430 */
431 double GetBondLength(
432 int firstelement,
433 int secondelement) const;
434
435 /** Returns bond criterion for given pair based on a bond length matrix.
436 * This calls either the covalent or the bond matrix criterion.
437 * \param *Walker first BondedParticle
438 * \param *OtherWalker second BondedParticle
439 * \return Range with bond interval
440 */
441 range<double> getMinMaxDistance(
442 const element * const Walker,
443 const element * const OtherWalker) const;
444
445 /** Returns bond criterion for given pair of elements based on a bond length matrix.
446 * The matrix should be contained in \a this BondGraph and contain an element-
447 * to-element length.
448 * \param *Walker first element
449 * \param *OtherWalker second element
450 * \return Range with bond interval
451 */
452 range<double> BondLengthMatrixMinMaxDistance(
453 const element * const Walker,
454 const element * const OtherWalker) const;
455
456 /** Returns bond criterion for given pair of elements based on covalent radius.
457 * \param *Walker first element
458 * \param *OtherWalker second element
459 * \return Range with bond interval
460 */
461 range<double> CovalentMinMaxDistance(
462 const element * const Walker,
463 const element * const OtherWalker) const;
464
465
466 /** Resets the bond::BondDegree of all atoms in the set to 1.
467 *
468 * @param Set Range with atoms
469 */
470 template <class container_type,
471 class iterator_type,
472 class const_iterator_type>
473 void resetBondDegree(
474 AtomSetMixin<container_type,iterator_type,const_iterator_type> &Set) const
475 {
476 // reset bond degrees
477 for(iterator_type AtomRunner = Set.begin(); AtomRunner != Set.end(); ++AtomRunner) {
478 (*AtomRunner)->resetBondDegree();
479 }
480 }
481
482 /** Calculates the bond degree for each atom on the set.
483 *
484 * @param Set Range with atoms
485 * @return number of non-matching bonds
486 */
487 template <class container_type,
488 class iterator_type,
489 class const_iterator_type>
490 int calculateBondDegree(
491 AtomSetMixin<container_type,iterator_type,const_iterator_type> &Set) const
492 {
493 //LOG(1, "Correcting Bond degree of each bond ... ");
494 int No = 0, OldNo = -1;
495 do {
496 OldNo = No;
497 No=0;
498 for(iterator_type AtomRunner = Set.begin(); AtomRunner != Set.end(); ++AtomRunner) {
499 No+=(*AtomRunner)->CorrectBondDegree();
500 }
501 } while (OldNo != No);
502 //LOG(0, " done.");
503 return No;
504 }
505
506 bool operator==(const periodentafel &other) const;
507
508 bool operator!=(const periodentafel &other) const {
509 return !(*this == other);
510 }
511
512private:
513 // default constructor for serialization
514 BondGraph();
515
516 friend class boost::serialization::access;
517 // serialization
518 template<class Archive>
519 void serialize(Archive & ar, const unsigned int version)
520 {
521 //ar & const_cast<double &>(BondThreshold);
522 ar & BondLengthMatrix;
523 ar & IsAngstroem;
524 }
525
526 //!> half width of the interval for allowed bond distances
527 static const double BondThreshold;
528 //!> Matrix with bond lenth per two elements
529 MatrixContainer *BondLengthMatrix;
530 //!> distance units are angstroem (true), bohr radii (false)
531 bool IsAngstroem;
532};
533
534#endif /* BONDGRAPH_HPP_ */
Note: See TracBrowser for help on using the repository browser.