source: src/Analysis/analysis_bonds.cpp@ a58c16

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 a58c16 was f01769, checked in by Frederik Heber <heber@…>, 9 years ago

Replaced World::getAtom() wherever possible by const version.

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