source: src/Analysis/analysis_bonds.cpp@ 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 94d5ac6, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: As we use GSL internally, we are as of now required to use GPL v2 license.

  • GNU Scientific Library is used at every place in the code, especially the sub-package LinearAlgebra is based on it which in turn is used really everywhere in the remainder of MoleCuilder. Hence, we have to use the GPL license for the whole of MoleCuilder. In effect, GPL's COPYING was present all along and stated the terms of the GPL v2 license.
  • Hence, I added the default GPL v2 disclaimer to every source file and removed the note about a (actually missing) LICENSE file.
  • also, I added a help-redistribute action which again gives the disclaimer of the GPL v2.
  • also, I changed in the disclaimer that is printed at every program start in builder_init.cpp.
  • TEST: Added check on GPL statement present in every module to test CodeChecks project-disclaimer.
  • 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 = (*MolWalker)->begin();
185 Walker!=(*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.