source: src/Analysis/analysis_bonds.cpp@ aec098

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

Rewrote CountHydrogenBridgeBonds() to use new LinkedCell construct.

  • Property mode set to 100644
File size: 13.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 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * analysis_bonds.cpp
10 *
11 * Created on: Nov 7, 2009
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include "analysis_bonds.hpp"
23#include "Atom/atom.hpp"
24#include "Bond/bond.hpp"
25#include "Element/element.hpp"
26#include "CodePatterns/Info.hpp"
27#include "CodePatterns/Verbose.hpp"
28#include "CodePatterns/Log.hpp"
29#include "molecule.hpp"
30#include "MoleculeListClass.hpp"
31
32/** Calculates the min, mean and maximum bond counts for the given molecule.
33 * \param *mol molecule with atoms and atom::ListOfBonds
34 * \param &Min minimum count on return
35 * \param &Mean mean count on return
36 * \param &Max maximum count on return
37 */
38void GetMaxMinMeanBondCount(const molecule * const mol, double &Min, double &Mean, double &Max)
39{
40 Min = 2e+6;
41 Max = -2e+5;
42 Mean = 0.;
43
44 int AtomCount = 0;
45 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
46 const BondList& ListOfBonds = (*iter)->getListOfBonds();
47 const int count = ListOfBonds.size();
48 if (Max < count)
49 Max = count;
50 if (Min > count)
51 Min = count;
52 Mean += count;
53 AtomCount++;
54 }
55 if (((int)Mean % 2) != 0)
56 ELOG(1, "Something is wrong with the bond structure, the number of bonds is not even!");
57 Mean /= (double)AtomCount;
58};
59
60/** Calculates the min and max bond distance of all atoms of two given elements.
61 * \param *mol molecule with atoms
62 * \param *type1 one element
63 * \param *type2 other element
64 * \param &Min minimum distance on return, 0 if no bond between the two elements
65 * \param &Mean mean distance (i.e. sum of distance for matching element pairs, divided by number) on return, 0 if no bond between the two elements
66 * \param &Max maximum distance on return, 0 if no bond between the two elements
67 */
68void MinMeanMaxBondDistanceBetweenElements(const molecule *mol, const element *type1, const element *type2, double &Min, double &Mean, double &Max)
69{
70 Min = 2e+6;
71 Mean = 0.;
72 Max = -2e+6;
73
74 int AtomNo = 0;
75 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
76 if ((*iter)->getType() == type1) {
77 const BondList& ListOfBonds = (*iter)->getListOfBonds();
78 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
79 BondRunner != ListOfBonds.end();
80 BondRunner++)
81 if ((*BondRunner)->GetOtherAtom((*iter))->getType() == type2) {
82 const double distance = (*BondRunner)->GetDistanceSquared();
83 if (Min > distance)
84 Min = distance;
85 if (Max < distance)
86 Max = distance;
87 Mean += sqrt(distance);
88 AtomNo++;
89 }
90 }
91 }
92 if (Max < 0) {
93 Max = Min = 0.;
94 } else {
95 Max = sqrt(Max);
96 Min = sqrt(Min);
97 Mean = Mean/(double)AtomNo;
98 }
99};
100
101/** Calculate the angle between \a *first and \a *origin and \a *second and \a *origin.
102 * \param *first first Vector
103 * \param *origin origin of angle taking
104 * \param *second second Vector
105 * \return angle between \a *first and \a *second, both relative to origin at \a *origin.
106 */
107double CalculateAngle(const Vector &first, const Vector &central, const Vector &second)
108{
109 Vector OHBond;
110 Vector OOBond;
111
112 OHBond = first - central;
113 OOBond = second - central;
114 const double angle = OHBond.Angle(OOBond);
115 return angle;
116};
117
118/** Checks whether the angle between \a *Oxygen and \a *Hydrogen and \a *Oxygen and \a *OtherOxygen is less than 30 degrees.
119 * Note that distance criterion is not checked.
120 * \param *Oxygen first oxygen atom, bonded to \a *Hydrogen
121 * \param *Hydrogen hydrogen bonded to \a *Oxygen
122 * \param *OtherOxygen other oxygen atom
123 * \return true - angle criteria fulfilled, false - criteria not fulfilled, angle greater than 30 degrees.
124 */
125bool CheckHydrogenBridgeBondAngle(const atom & Oxygen, const atom & Hydrogen, const atom & OtherOxygen)
126{
127 Info FunctionInfo(__func__);
128
129 // check angle
130 const double angle = CalculateAngle(
131 Hydrogen.getPosition(),
132 Oxygen.getPosition(),
133 OtherOxygen.getPosition());
134 LOG(3, "INFO: Hydrogen bridge bond angle is " << angle << ", < " << M_PI*(30./180.) << "?");
135 if (angle < M_PI*(30./180.)) {
136 return true;
137 } else {
138 return false;
139 }
140};
141
142/** Counts the number of hydrogen bridge bonds.
143 * With \a *InterfaceElement an extra element can be specified that identifies some boundary.
144 * Then, counting is for the h-bridges that connect to interface only.
145 * \param *molecules molecules to count bonds
146 * \param *InterfaceElement or NULL
147 * \param *Interface2Element or NULL
148 */
149int CountHydrogenBridgeBonds(MoleculeListClass *molecules, const element * InterfaceElement = NULL, const element * Interface2Element = NULL)
150{
151 Info FunctionInfo(__func__);
152
153 int count = 0;
154 int OtherHydrogens = 0;
155 double Otherangle = 0.;
156 bool InterfaceFlag = false;
157 bool Interface2Flag = false;
158 bool OtherHydrogenFlag = true;
159 LinkedCell::LinkedCell_View LC = World::getInstance().getLinkedCell(HBRIDGEDISTANCE);
160
161 // go through every molecule
162 for (MoleculeList::const_iterator MolWalker = molecules->ListOfMolecules.begin();
163 MolWalker != molecules->ListOfMolecules.end();
164 ++MolWalker) {
165 LOG(2, "INFO: Current molecule is " << (*MolWalker)->getName() << ".");
166
167 // go through every atom
168 typedef std::set<const molecule *> Moleculeset;
169 for(molecule::const_iterator Walker = (*MolWalker)->begin();
170 Walker!=(*MolWalker)->end();
171 ++Walker) {
172 // go through every oxygen
173 if ((*Walker)->getType()->getAtomicNumber() == 8) {
174 LOG(2, "INFO: Current oxygen atom is " << *(*Walker) << ".");
175
176 // get all its neighbors
177 LinkedCell::LinkedList NeighborList = LC.getAllNeighbors(HBRIDGEDISTANCE, (*Walker)->getPosition());
178 // go through each candidate and gather the molecules of all other oxygens
179 Moleculeset MoleculeNeighbors;
180 for(LinkedCell::LinkedList::const_iterator Runner = NeighborList.begin();
181 Runner != NeighborList.end(); ++Runner) {
182 const atom * const OtherAtom = dynamic_cast<const atom *>(*Runner);
183 if ((OtherAtom->getType()->getAtomicNumber() == 8) &&
184 (OtherAtom->getMolecule() != (*MolWalker))) {
185 LOG(3, "INFO: Possible neighboring molecule is " << OtherAtom->getMolecule()->getName() << ".");
186 MoleculeNeighbors.insert(OtherAtom->getMolecule());
187 }
188 }
189
190 // now go through the molecules
191 for (Moleculeset::const_iterator moliter = MoleculeNeighbors.begin();
192 moliter != MoleculeNeighbors.end();
193 ++moliter) {
194 LOG(2, "INFO: Current other molecule is " << (*moliter)->getName() << ".");
195
196 // go through every other atom
197 for(molecule::const_iterator Runner = (*moliter)->begin();
198 Runner != (*moliter)->end();
199 ++Runner) {
200 // go through each oxygen
201 if ((*Runner)->getType()->getAtomicNumber() == 8) {
202
203 // check distance
204 const double distance = (*Runner)->DistanceSquared(*(*Walker));
205 if ((distance > MYEPSILON) && (distance < HBRIDGEDISTANCE*HBRIDGEDISTANCE)) {
206 LOG(2, "INFO: Distance between oxygen atom "
207 << (*Walker)->getName() << " and "
208 << (*Runner)->getName() << " is "
209 << sqrt(distance) << ".");
210 // distance >0 means different atoms
211 // on other atom(Runner) we check for bond to interface element and
212 // check that O-O line is not in between the shanks of the two connected hydrogens (Otherangle > 104.5)
213 OtherHydrogenFlag = true;
214 Otherangle = 0.;
215 OtherHydrogens = 0;
216 InterfaceFlag = (InterfaceElement == NULL);
217 Interface2Flag = (Interface2Element == NULL);
218 const BondList& ListOfBonds = (*Runner)->getListOfBonds();
219 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
220 BondRunner != ListOfBonds.end();
221 BondRunner++) {
222 atom * const OtherAtom = (*BondRunner)->GetOtherAtom(*Runner);
223 // if hydrogen, check angle to be greater(!) than 30 degrees
224 if (OtherAtom->getType()->getAtomicNumber() == 1) {
225 const double angle = CalculateAngle(OtherAtom->getPosition(), (*Runner)->getPosition(), (*Walker)->getPosition());
226 OtherHydrogenFlag = OtherHydrogenFlag && (angle > M_PI*(30./180.) + MYEPSILON);
227 Otherangle += angle;
228 OtherHydrogens++;
229 }
230 InterfaceFlag = InterfaceFlag || (OtherAtom->getType() == InterfaceElement);
231 Interface2Flag = Interface2Flag || (OtherAtom->getType() == Interface2Element);
232 }
233 LOG(1, "Otherangle is " << Otherangle << " for " << OtherHydrogens << " hydrogens.");
234 switch (OtherHydrogens) {
235 case 0:
236 case 1:
237 break;
238 case 2:
239 OtherHydrogenFlag = OtherHydrogenFlag && (Otherangle > M_PI*(104.5/180.) + MYEPSILON);
240 break;
241 default: // 3 or more hydrogens ...
242 OtherHydrogenFlag = false;
243 break;
244 }
245 if (InterfaceFlag && Interface2Flag && OtherHydrogenFlag) {
246 // on this element (Walker) we check for bond to hydrogen, i.e. part of water molecule
247 const BondList& ListOfBonds = (*Walker)->getListOfBonds();
248 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
249 BondRunner != ListOfBonds.end();
250 BondRunner++) {
251 atom * const OtherAtom = (*BondRunner)->GetOtherAtom(*Walker);
252 if (OtherAtom->getType()->getAtomicNumber() == 1) {
253 // check angle
254 if (CheckHydrogenBridgeBondAngle(*(*Walker), *OtherAtom, *(*Runner))) {
255 count++;
256 break;
257 }
258 }
259 }
260 }
261 }
262 }
263 } // end go through molecules
264 } // end gather molecules
265 } // end go through every oxygen
266 } // end go through every atom
267 }
268 return count;
269}
270
271/** Counts the number of bonds between two given elements.
272 * \param *molecules list of molecules with all atoms
273 * \param *first pointer to first element
274 * \param *second pointer to second element
275 * \return number of found bonds (\a *first-\a *second)
276 */
277int CountBondsOfTwo(MoleculeListClass * const molecules, const element * const first, const element * const second)
278{
279 int count = 0;
280
281 for (MoleculeList::const_iterator MolWalker = molecules->ListOfMolecules.begin();MolWalker != molecules->ListOfMolecules.end(); MolWalker++) {
282 molecule::iterator Walker = (*MolWalker)->begin();
283 for(;Walker!=(*MolWalker)->end();++Walker){
284 atom * theAtom = *Walker;
285 if ((theAtom->getType() == first) || (theAtom->getType() == second)) { // first element matches
286 const BondList& ListOfBonds = theAtom->getListOfBonds();
287 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
288 BondRunner != ListOfBonds.end();
289 BondRunner++) {
290 atom * const OtherAtom = (*BondRunner)->GetOtherAtom(theAtom);
291 if (((OtherAtom->getType() == first) || (OtherAtom->getType() == second)) && (theAtom->getNr() < OtherAtom->getNr())) {
292 count++;
293 LOG(1, *first << "-" << *second << " bond found between " << *Walker << " and " << *OtherAtom << ".");
294 }
295 }
296 }
297 }
298 }
299 return count;
300};
301
302/** Counts the number of bonds between three given elements.
303 * Note that we do not look for arbitrary sequence of given bonds, but \a *second will be the central atom and we check
304 * whether it has bonds to both \a *first and \a *third.
305 * \param *molecules list of molecules with all atoms
306 * \param *first pointer to first element
307 * \param *second pointer to second element
308 * \param *third pointer to third element
309 * \return number of found bonds (\a *first-\a *second-\a *third, \a *third-\a *second-\a *first, respectively)
310 */
311int CountBondsOfThree(MoleculeListClass * const molecules, const element * const first, const element * const second, const element * const third)
312{
313 int count = 0;
314 bool MatchFlag[2];
315 bool result = false;
316 const element * ElementArray[2];
317 ElementArray[0] = first;
318 ElementArray[1] = third;
319
320 for (MoleculeList::const_iterator MolWalker = molecules->ListOfMolecules.begin();MolWalker != molecules->ListOfMolecules.end(); MolWalker++) {
321 molecule::iterator Walker = (*MolWalker)->begin();
322 for(;Walker!=(*MolWalker)->end();++Walker){
323 atom *theAtom = *Walker;
324 if (theAtom->getType() == second) { // first element matches
325 for (int i=0;i<2;i++)
326 MatchFlag[i] = false;
327 const BondList& ListOfBonds = theAtom->getListOfBonds();
328 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
329 BondRunner != ListOfBonds.end();
330 BondRunner++) {
331 atom * const OtherAtom = (*BondRunner)->GetOtherAtom(theAtom);
332 for (int i=0;i<2;i++)
333 if ((!MatchFlag[i]) && (OtherAtom->getType() == ElementArray[i])) {
334 MatchFlag[i] = true;
335 break; // each bonding atom can match at most one element we are looking for
336 }
337 }
338 result = true;
339 for (int i=0;i<2;i++) // gather results
340 result = result && MatchFlag[i];
341 if (result) { // check results
342 count++;
343 LOG(1, *first << "-" << *second << "-" << *third << " bond found at " << *Walker << ".");
344 }
345 }
346 }
347 }
348 return count;
349};
Note: See TracBrowser for help on using the repository browser.