source: src/Fragmentation/Exporters/SaturatedFragment.cpp@ 27e6a7

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator 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_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions 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 GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 27e6a7 was ce70d25, checked in by Frederik Heber <heber@…>, 9 years ago

Added some asserts and checks in context of SaturatedFragment and appendToHomologies().

  • appendToHomologies() now gives boolean return value which results in failure or success of the action, namely all asserts are now ifs (because if we mark the regression tests as XFAIL then debug and release must fail).
  • TESTFIX: Marked all AnalyseFragmentationResults regression test as XFAIL for the moment.
  • Property mode set to 100644
File size: 25.0 KB
RevLine 
[7d5fcd]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2013 University of Bonn. All rights reserved.
[5aaa43]5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
[7d5fcd]6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * SaturatedFragment.cpp
26 *
27 * Created on: Mar 3, 2013
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "CodePatterns/MemDebug.hpp"
37
38#include "SaturatedFragment.hpp"
39
[c39675]40#include <cmath>
41#include <iostream>
42
[7d5fcd]43#include "CodePatterns/Assert.hpp"
[c39675]44#include "CodePatterns/Log.hpp"
45
46#include "LinearAlgebra/Exceptions.hpp"
47#include "LinearAlgebra/Plane.hpp"
48#include "LinearAlgebra/RealSpaceMatrix.hpp"
49#include "LinearAlgebra/Vector.hpp"
[7d5fcd]50
[c39675]51#include "Atom/atom.hpp"
52#include "Bond/bond.hpp"
53#include "config.hpp"
54#include "Descriptors/AtomIdDescriptor.hpp"
[7d5fcd]55#include "Fragmentation/Exporters/HydrogenPool.hpp"
[c39675]56#include "Fragmentation/HydrogenSaturation_enum.hpp"
57#include "Graph/BondGraph.hpp"
58#include "World.hpp"
[7d5fcd]59
60SaturatedFragment::SaturatedFragment(
61 const KeySet &_set,
62 KeySetsInUse_t &_container,
[c39675]63 HydrogenPool &_hydrogens,
64 const enum HydrogenTreatment _treatment,
[98a293b]65 const enum HydrogenSaturation _saturation,
66 const GlobalSaturationPositions_t &_globalsaturationpositions) :
[7d5fcd]67 container(_container),
68 set(_set),
69 hydrogens(_hydrogens),
[c39675]70 FullMolecule(set),
71 treatment(_treatment),
72 saturation(_saturation)
[7d5fcd]73{
74 // add to in-use container
75 ASSERT( container.find(set) == container.end(),
76 "SaturatedFragment::SaturatedFragment() - the set "
77 +toString(set)+" is already marked as in use.");
78 container.insert(set);
79
[98a293b]80 // prepare saturation hydrogens, either using global information
81 // or if not given, local information (created in the function)
82 if (_globalsaturationpositions.empty())
83 saturate();
84 else
85 saturate(_globalsaturationpositions);
[7d5fcd]86}
87
88SaturatedFragment::~SaturatedFragment()
89{
90 // release all saturation hydrogens if present
91 for (KeySet::iterator iter = SaturationHydrogens.begin();
92 !SaturationHydrogens.empty();
93 iter = SaturationHydrogens.begin()) {
94 hydrogens.releaseHydrogen(*iter);
95 SaturationHydrogens.erase(iter);
96 }
97
98 // remove ourselves from in-use container
99 KeySetsInUse_t::iterator iter = container.find(set);
100 ASSERT( container.find(set) != container.end(),
101 "SaturatedFragment::SaturatedFragment() - the set "
102 +toString(set)+" is not marked as in use.");
103 container.erase(iter);
104}
[c39675]105
[98a293b]106typedef std::vector<atom *> atoms_t;
107
108atoms_t gatherAllAtoms(const KeySet &_FullMolecule)
[c39675]109{
[98a293b]110 atoms_t atoms;
111 for (KeySet::const_iterator iter = _FullMolecule.begin();
112 iter != _FullMolecule.end();
[c39675]113 ++iter) {
114 atom * const Walker = World::getInstance().getAtom(AtomById(*iter));
115 ASSERT( Walker != NULL,
[98a293b]116 "gatherAllAtoms() - id "
[c39675]117 +toString(*iter)+" is unknown to World.");
118 atoms.push_back(Walker);
119 }
120
[98a293b]121 return atoms;
122}
123
124typedef std::map<atom *, BondList > CutBonds_t;
125
126CutBonds_t gatherCutBonds(
127 const atoms_t &_atoms,
128 const KeySet &_set,
129 const enum HydrogenTreatment _treatment)
130{
131 // bool LonelyFlag = false;
[9d3264]132 CutBonds_t CutBonds;
[98a293b]133 for (atoms_t::const_iterator iter = _atoms.begin();
134 iter != _atoms.end();
[c39675]135 ++iter) {
136 atom * const Walker = *iter;
137
138 // go through all bonds
139 const BondList& ListOfBonds = Walker->getListOfBonds();
140 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
141 BondRunner != ListOfBonds.end();
142 ++BondRunner) {
143 atom * const OtherWalker = (*BondRunner)->GetOtherAtom(Walker);
[98a293b]144 // if other atom is in key set or is a specially treated hydrogen
145 if (_set.find(OtherWalker->getId()) != _set.end()) {
[c39675]146 LOG(4, "DEBUG: Walker " << *Walker << " is bound to " << *OtherWalker << ".");
[98a293b]147 } else if ((_treatment == ExcludeHydrogen)
148 && (OtherWalker->getElementNo() == (atomicNumber_t)1)) {
149 LOG(4, "DEBUG: Walker " << *Walker << " is bound to specially treated hydrogen " <<
150 *OtherWalker << ".");
[c39675]151 } else {
152 LOG(4, "DEBUG: Walker " << *Walker << " is bound to "
153 << *OtherWalker << ", who is not in this fragment molecule.");
[9d3264]154 if (CutBonds.count(Walker) == 0)
155 CutBonds.insert( std::make_pair(Walker, BondList() ));
156 CutBonds[Walker].push_back(*BondRunner);
[c39675]157 }
158 }
159 }
[9d3264]160
[98a293b]161 return CutBonds;
162}
163
164typedef std::vector<atomId_t> atomids_t;
165
166atomids_t gatherPresentExcludedHydrogens(
167 const atoms_t &_atoms,
168 const KeySet &_set,
169 const enum HydrogenTreatment _treatment)
170{
171 // bool LonelyFlag = false;
172 atomids_t ExcludedHydrogens;
173 for (atoms_t::const_iterator iter = _atoms.begin();
174 iter != _atoms.end();
175 ++iter) {
176 atom * const Walker = *iter;
177
178 // go through all bonds
179 const BondList& ListOfBonds = Walker->getListOfBonds();
180 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
181 BondRunner != ListOfBonds.end();
182 ++BondRunner) {
183 atom * const OtherWalker = (*BondRunner)->GetOtherAtom(Walker);
184 // if other atom is in key set or is a specially treated hydrogen
185 if (_set.find(OtherWalker->getId()) != _set.end()) {
186 LOG(6, "DEBUG: OtherWalker " << *OtherWalker << " is in set already.");
187 } else if ((_treatment == ExcludeHydrogen)
188 && (OtherWalker->getElementNo() == (atomicNumber_t)1)) {
189 LOG(5, "DEBUG: Adding excluded hydrogen OtherWalker " << *OtherWalker << ".");
190 ExcludedHydrogens.push_back(OtherWalker->getId());
191 } else {
192 LOG(6, "DEBUG: OtherWalker " << *Walker << " is not in this fragment molecule and no hydrogen.");
193 }
194 }
195 }
196
197 return ExcludedHydrogens;
198}
199
200void SaturatedFragment::saturate()
201{
202 // so far, we just have a set of keys. Hence, convert to atom refs
203 // and gather all atoms in a vector
204 std::vector<atom *> atoms = gatherAllAtoms(FullMolecule);
205
206 // go through each atom of the fragment and gather all cut bonds in list
207 CutBonds_t CutBonds = gatherCutBonds(atoms, set, treatment);
208
209 // add excluded hydrogens to FullMolecule if treated specially
210 if (treatment == ExcludeHydrogen) {
211 atomids_t ExcludedHydrogens = gatherPresentExcludedHydrogens(atoms, set, treatment);
212 FullMolecule.insert(ExcludedHydrogens.begin(), ExcludedHydrogens.end());
213 }
214
[9d3264]215 // go through all cut bonds and replace with a hydrogen
216 for (CutBonds_t::const_iterator atomiter = CutBonds.begin();
217 atomiter != CutBonds.end(); ++atomiter) {
218 atom * const Walker = atomiter->first;
[de2cbf]219 if (!saturateAtom(Walker, atomiter->second))
220 exit(1);
221 }
222}
223
[98a293b]224void SaturatedFragment::saturate(
225 const GlobalSaturationPositions_t &_globalsaturationpositions)
226{
227 // so far, we just have a set of keys. Hence, convert to atom refs
228 // and gather all atoms in a vector
229 std::vector<atom *> atoms = gatherAllAtoms(FullMolecule);
230
231 // go through each atom of the fragment and gather all cut bonds in list
232 CutBonds_t CutBonds = gatherCutBonds(atoms, set, treatment);
233
234 // add excluded hydrogens to FullMolecule if treated specially
235 if (treatment == ExcludeHydrogen) {
236 atomids_t ExcludedHydrogens = gatherPresentExcludedHydrogens(atoms, set, treatment);
237 FullMolecule.insert(ExcludedHydrogens.begin(), ExcludedHydrogens.end());
238 }
239
240 // go through all cut bonds and replace with a hydrogen
241 if (saturation == DoSaturate) {
242 for (CutBonds_t::const_iterator atomiter = CutBonds.begin();
243 atomiter != CutBonds.end(); ++atomiter) {
244 atom * const Walker = atomiter->first;
[ce70d25]245 ASSERT( set.find(Walker->getId()) != set.end(),
246 "SaturatedFragment::saturate() - key "
247 +toString(*Walker)+"not in set?");
[98a293b]248 LOG(4, "DEBUG: We are now saturating dangling bonds of " << *Walker);
249
250 // gather set of positions for this atom from global map
251 GlobalSaturationPositions_t::const_iterator mapiter =
252 _globalsaturationpositions.find(Walker->getId());
253 ASSERT( mapiter != _globalsaturationpositions.end(),
254 "SaturatedFragment::saturate() - no global information for "
255 +toString(*Walker));
256 const SaturationsPositionsPerNeighbor_t &saturationpositions =
257 mapiter->second;
258
259 // go through all cut bonds for this atom
260 for (BondList::const_iterator bonditer = atomiter->second.begin();
261 bonditer != atomiter->second.end(); ++bonditer) {
262 atom * const OtherWalker = (*bonditer)->GetOtherAtom(Walker);
263
264 // get positions from global map
265 SaturationsPositionsPerNeighbor_t::const_iterator positionsiter =
266 saturationpositions.find(OtherWalker->getId());
267 ASSERT(positionsiter != saturationpositions.end(),
268 "SaturatedFragment::saturate() - no information on bond neighbor "
269 +toString(*OtherWalker)+" to atom "+toString(*Walker));
270 ASSERT(!positionsiter->second.empty(),
271 "SaturatedFragment::saturate() - no positions for saturating bond to"
272 +toString(*OtherWalker)+" to atom "+toString(*Walker));
273
[5d5550]274// // get typical bond distance from elements database
275// double BondDistance = Walker->getType()->getHBondDistance(positionsiter->second.size()-1);
276// if (BondDistance < 0.) {
277// ELOG(2, "saturateAtoms() - no typical hydrogen bond distance of degree "
278// +toString(positionsiter->second.size())+" for element "
279// +toString(Walker->getType()->getName()));
280// // try bond degree 1 distance
281// BondDistance = Walker->getType()->getHBondDistance(1-1);
282// if (BondDistance < 0.) {
283// ELOG(1, "saturateAtoms() - no typical hydrogen bond distance for element "
284// +toString(Walker->getType()->getName()));
285// BondDistance = 1.;
286// }
287// }
[98a293b]288
289 // place hydrogen at each point
290 LOG(4, "DEBUG: Places to saturate for atom " << *OtherWalker
291 << " are " << positionsiter->second);
292 atom * const father = Walker;
293 for (SaturationsPositions_t::const_iterator positer = positionsiter->second.begin();
294 positer != positionsiter->second.end(); ++positer) {
295 const atom& hydrogen =
[5d5550]296 setHydrogenReplacement(Walker, *positer, 1., father);
[98a293b]297 FullMolecule.insert(hydrogen.getId());
298 }
299 }
300 }
301 } else
302 LOG(3, "INFO: We are not saturating cut bonds.");
303}
304
305const atom& SaturatedFragment::setHydrogenReplacement(
306 const atom * const _OwnerAtom,
307 const Vector &_position,
308 const double _distance,
309 atom * const _father)
310{
311 atom * const _atom = hydrogens.leaseHydrogen(); // new atom
312 _atom->setPosition( _OwnerAtom->getPosition() + _distance * _position );
313 // always set as fixed ion (not moving during molecular dynamics simulation)
314 _atom->setFixedIon(true);
315 // if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father
[910a5d]316 _atom->setFather(_father);
[98a293b]317 SaturationHydrogens.insert(_atom->getId());
318
319 return *_atom;
320}
321
[de2cbf]322bool SaturatedFragment::saturateAtom(
323 atom * const _atom,
324 const BondList &_cutbonds)
325{
326 // go through each bond and replace
327 for (BondList::const_iterator bonditer = _cutbonds.begin();
328 bonditer != _cutbonds.end(); ++bonditer) {
329 atom * const OtherWalker = (*bonditer)->GetOtherAtom(_atom);
330 if (!AddHydrogenReplacementAtom(
331 (*bonditer),
332 _atom,
333 OtherWalker,
334 World::getInstance().getConfig()->IsAngstroem == 1))
335 return false;
[9d3264]336 }
[de2cbf]337 return true;
[c39675]338}
339
340bool SaturatedFragment::OutputConfig(
341 std::ostream &out,
342 const ParserTypes _type) const
343{
344 // gather all atoms in a vector
[fac58f]345 std::vector<const atom *> atoms;
[c39675]346 for (KeySet::const_iterator iter = FullMolecule.begin();
347 iter != FullMolecule.end();
348 ++iter) {
[fac58f]349 const atom * const Walker = const_cast<const World &>(World::getInstance()).
350 getAtom(AtomById(*iter));
[c39675]351 ASSERT( Walker != NULL,
352 "SaturatedFragment::OutputConfig() - id "
353 +toString(*iter)+" is unknown to World.");
354 atoms.push_back(Walker);
355 }
356
357 // TODO: ScanForPeriodicCorrection() is missing so far!
358 // note however that this is not straight-forward for the following reasons:
359 // - we do not copy all atoms anymore, hence we are forced to shift the real
360 // atoms hither and back again
361 // - we use a long-range potential that supports periodic boundary conditions.
362 // Hence, there we would like the original configuration (split through the
363 // the periodic boundaries). Otherwise, we would have to shift (and probably
364 // interpolate) the potential with OBCs applying.
365
366 // list atoms in fragment for debugging
367 {
368 std::stringstream output;
369 output << "INFO: Contained atoms: ";
[fac58f]370 for (std::vector<const atom *>::const_iterator iter = atoms.begin();
[c39675]371 iter != atoms.end(); ++iter) {
372 output << (*iter)->getName() << " ";
373 }
374 LOG(3, output.str());
375 }
376
377 // store to stream via FragmentParser
378 const bool intermediateResult =
379 FormatParserStorage::getInstance().save(
380 out,
381 FormatParserStorage::getInstance().getSuffixFromType(_type),
382 atoms);
383
384 return intermediateResult;
385}
386
387atom * const SaturatedFragment::getHydrogenReplacement(atom * const replacement)
388{
389 atom * const _atom = hydrogens.leaseHydrogen(); // new atom
390 _atom->setAtomicVelocity(replacement->getAtomicVelocity()); // copy velocity
391 _atom->setFixedIon(replacement->getFixedIon());
392 // if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father
[910a5d]393 _atom->setFather(replacement);
[c39675]394 SaturationHydrogens.insert(_atom->getId());
395 return _atom;
396}
397
398bool SaturatedFragment::AddHydrogenReplacementAtom(
399 bond::ptr TopBond,
400 atom *Origin,
401 atom *Replacement,
402 bool IsAngstroem)
403{
404// Info info(__func__);
405 bool AllWentWell = true; // flag gathering the boolean return value of molecule::AddAtom and other functions, as return value on exit
406 double bondlength; // bond length of the bond to be replaced/cut
407 double bondangle; // bond angle of the bond to be replaced/cut
408 double BondRescale; // rescale value for the hydrogen bond length
409 bond::ptr FirstBond;
410 bond::ptr SecondBond; // Other bonds in double bond case to determine "other" plane
411 atom *FirstOtherAtom = NULL, *SecondOtherAtom = NULL, *ThirdOtherAtom = NULL; // pointer to hydrogen atoms to be added
412 double b,l,d,f,g, alpha, factors[NDIM]; // hold temporary values in triple bond case for coordination determination
413 Vector Orthovector1, Orthovector2; // temporary vectors in coordination construction
414 Vector InBondvector; // vector in direction of *Bond
415 const RealSpaceMatrix &matrix = World::getInstance().getDomain().getM();
416 bond::ptr Binder;
417
418 // create vector in direction of bond
419 InBondvector = Replacement->getPosition() - Origin->getPosition();
420 bondlength = InBondvector.Norm();
421
422 // is greater than typical bond distance? Then we have to correct periodically
423 // the problem is not the H being out of the box, but InBondvector have the wrong direction
424 // due to Replacement or Origin being on the wrong side!
425 const BondGraph * const BG = World::getInstance().getBondGraph();
426 const range<double> MinMaxBondDistance(
427 BG->getMinMaxDistance(Origin,Replacement));
428 if (!MinMaxBondDistance.isInRange(bondlength)) {
429// LOG(4, "InBondvector is: " << InBondvector << ".");
430 Orthovector1.Zero();
431 for (int i=NDIM;i--;) {
432 l = Replacement->at(i) - Origin->at(i);
433 if (fabs(l) > MinMaxBondDistance.last) { // is component greater than bond distance (check against min not useful here)
434 Orthovector1[i] = (l < 0) ? -1. : +1.;
435 } // (signs are correct, was tested!)
436 }
437 Orthovector1 *= matrix;
438 InBondvector -= Orthovector1; // subtract just the additional translation
439 bondlength = InBondvector.Norm();
440// LOG(4, "INFO: Corrected InBondvector is now: " << InBondvector << ".");
441 } // periodic correction finished
442
443 InBondvector.Normalize();
444 // get typical bond length and store as scale factor for later
445 ASSERT(Origin->getType() != NULL,
446 "SaturatedFragment::AddHydrogenReplacementAtom() - element of Origin is not given.");
[1f693d]447 BondRescale = Origin->getType()->getHBondDistance(TopBond->getDegree()-1);
[c39675]448 if (BondRescale == -1) {
[1f693d]449 ELOG(1, "There is no typical hydrogen bond distance in replacing bond (" << Origin->getName() << "<->" << Replacement->getName() << ") of degree " << TopBond->getDegree() << "!");
[3fbdca]450 BondRescale = Origin->getType()->getHBondDistance(TopBond->getDegree());
451 if (BondRescale == -1) {
452 ELOG(1, "There is no typical hydrogen bond distance in replacing bond (" << Origin->getName() << "<->" << Replacement->getName() << ") of any degree!");
453 return false;
454 BondRescale = bondlength;
455 }
[c39675]456 } else {
457 if (!IsAngstroem)
458 BondRescale /= (1.*AtomicLengthToAngstroem);
459 }
460
461 // discern single, double and triple bonds
[1f693d]462 switch(TopBond->getDegree()) {
[c39675]463 case 1:
464 // check whether replacement has been an excluded hydrogen
465 if (Replacement->getType()->getAtomicNumber() == HydrogenPool::HYDROGEN) { // neither rescale nor replace if it's already hydrogen
466 FirstOtherAtom = Replacement;
467 BondRescale = bondlength;
468 } else {
469 FirstOtherAtom = getHydrogenReplacement(Replacement);
470 InBondvector *= BondRescale; // rescale the distance vector to Hydrogen bond length
471 FirstOtherAtom->setPosition(Origin->getPosition() + InBondvector); // set coordination to origin and add distance vector to replacement atom
472 }
473 FullMolecule.insert(FirstOtherAtom->getId());
474// LOG(4, "INFO: Added " << *FirstOtherAtom << " at: " << FirstOtherAtom->x << ".");
475 break;
476 case 2:
477 {
478 // determine two other bonds (warning if there are more than two other) plus valence sanity check
479 const BondList& ListOfBonds = Origin->getListOfBonds();
480 for (BondList::const_iterator Runner = ListOfBonds.begin();
481 Runner != ListOfBonds.end();
482 ++Runner) {
483 if ((*Runner) != TopBond) {
484 if (FirstBond == NULL) {
485 FirstBond = (*Runner);
486 FirstOtherAtom = (*Runner)->GetOtherAtom(Origin);
487 } else if (SecondBond == NULL) {
488 SecondBond = (*Runner);
489 SecondOtherAtom = (*Runner)->GetOtherAtom(Origin);
490 } else {
491 ELOG(2, "Detected more than four bonds for atom " << Origin->getName());
492 }
493 }
494 }
495 }
496 if (SecondOtherAtom == NULL) { // then we have an atom with valence four, but only 3 bonds: one to replace and one which is TopBond (third is FirstBond)
497 SecondBond = TopBond;
498 SecondOtherAtom = Replacement;
499 }
500 if (FirstOtherAtom != NULL) { // then we just have this double bond and the plane does not matter at all
501// LOG(3, "Regarding the double bond (" << Origin->Name << "<->" << Replacement->Name << ") to be constructed: Taking " << FirstOtherAtom->Name << " and " << SecondOtherAtom->Name << " along with " << Origin->Name << " to determine orthogonal plane.");
502
503 // determine the plane of these two with the *origin
504 try {
505 Orthovector1 = Plane(Origin->getPosition(), FirstOtherAtom->getPosition(), SecondOtherAtom->getPosition()).getNormal();
506 }
507 catch(LinearDependenceException &excp){
508 LOG(0, boost::diagnostic_information(excp));
509 // TODO: figure out what to do with the Orthovector in this case
510 AllWentWell = false;
511 }
512 } else {
513 Orthovector1.GetOneNormalVector(InBondvector);
514 }
515 //LOG(3, "INFO: Orthovector1: " << Orthovector1 << ".");
516 // orthogonal vector and bond vector between origin and replacement form the new plane
517 Orthovector1.MakeNormalTo(InBondvector);
518 Orthovector1.Normalize();
519 //LOG(3, "ReScaleCheck: " << Orthovector1.Norm() << " and " << InBondvector.Norm() << ".");
520
521 // create the two Hydrogens ...
522 FirstOtherAtom = getHydrogenReplacement(Replacement);
523 SecondOtherAtom = getHydrogenReplacement(Replacement);
524 FullMolecule.insert(FirstOtherAtom->getId());
525 FullMolecule.insert(SecondOtherAtom->getId());
526 bondangle = Origin->getType()->getHBondAngle(1);
527 if (bondangle == -1) {
[1f693d]528 ELOG(1, "There is no typical hydrogen bond angle in replacing bond (" << Origin->getName() << "<->" << Replacement->getName() << ") of degree " << TopBond->getDegree() << "!");
[c39675]529 return false;
530 bondangle = 0;
531 }
532 bondangle *= M_PI/180./2.;
533// LOG(3, "INFO: ReScaleCheck: InBondvector " << InBondvector << ", " << Orthovector1 << ".");
534// LOG(3, "Half the bond angle is " << bondangle << ", sin and cos of it: " << sin(bondangle) << ", " << cos(bondangle));
535 FirstOtherAtom->Zero();
536 SecondOtherAtom->Zero();
537 for(int i=NDIM;i--;) { // rotate by half the bond angle in both directions (InBondvector is bondangle = 0 direction)
538 FirstOtherAtom->set(i, InBondvector[i] * cos(bondangle) + Orthovector1[i] * (sin(bondangle)));
539 SecondOtherAtom->set(i, InBondvector[i] * cos(bondangle) + Orthovector1[i] * (-sin(bondangle)));
540 }
541 FirstOtherAtom->Scale(BondRescale); // rescale by correct BondDistance
542 SecondOtherAtom->Scale(BondRescale);
543 //LOG(3, "ReScaleCheck: " << FirstOtherAtom->x.Norm() << " and " << SecondOtherAtom->x.Norm() << ".");
544 *FirstOtherAtom += Origin->getPosition();
545 *SecondOtherAtom += Origin->getPosition();
546 // ... and add to molecule
547// LOG(4, "INFO: Added " << *FirstOtherAtom << " at: " << FirstOtherAtom->x << ".");
548// LOG(4, "INFO: Added " << *SecondOtherAtom << " at: " << SecondOtherAtom->x << ".");
549 break;
550 case 3:
551 // take the "usual" tetraoidal angle and add the three Hydrogen in direction of the bond (height of the tetraoid)
552 FirstOtherAtom = getHydrogenReplacement(Replacement);
553 SecondOtherAtom = getHydrogenReplacement(Replacement);
554 ThirdOtherAtom = getHydrogenReplacement(Replacement);
555 FullMolecule.insert(FirstOtherAtom->getId());
556 FullMolecule.insert(SecondOtherAtom->getId());
557 FullMolecule.insert(ThirdOtherAtom->getId());
558
559 // we need to vectors orthonormal the InBondvector
560 AllWentWell = AllWentWell && Orthovector1.GetOneNormalVector(InBondvector);
561// LOG(3, "INFO: Orthovector1: " << Orthovector1 << ".");
562 try{
563 Orthovector2 = Plane(InBondvector, Orthovector1,0).getNormal();
564 }
565 catch(LinearDependenceException &excp) {
566 LOG(0, boost::diagnostic_information(excp));
567 AllWentWell = false;
568 }
569// LOG(3, "INFO: Orthovector2: " << Orthovector2 << ".")
570
571 // create correct coordination for the three atoms
572 alpha = (Origin->getType()->getHBondAngle(2))/180.*M_PI/2.; // retrieve triple bond angle from database
573 l = BondRescale; // desired bond length
574 b = 2.*l*sin(alpha); // base length of isosceles triangle
575 d = l*sqrt(cos(alpha)*cos(alpha) - sin(alpha)*sin(alpha)/3.); // length for InBondvector
576 f = b/sqrt(3.); // length for Orthvector1
577 g = b/2.; // length for Orthvector2
578// LOG(3, "Bond length and half-angle: " << l << ", " << alpha << "\t (b,d,f,g) = " << b << ", " << d << ", " << f << ", " << g << ", ");
579// LOG(3, "The three Bond lengths: " << sqrt(d*d+f*f) << ", " << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g) << ", " << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g));
580 factors[0] = d;
581 factors[1] = f;
582 factors[2] = 0.;
583 FirstOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
584 factors[1] = -0.5*f;
585 factors[2] = g;
586 SecondOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
587 factors[2] = -g;
588 ThirdOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
589
590 // rescale each to correct BondDistance
591// FirstOtherAtom->x.Scale(&BondRescale);
592// SecondOtherAtom->x.Scale(&BondRescale);
593// ThirdOtherAtom->x.Scale(&BondRescale);
594
595 // and relative to *origin atom
596 *FirstOtherAtom += Origin->getPosition();
597 *SecondOtherAtom += Origin->getPosition();
598 *ThirdOtherAtom += Origin->getPosition();
599
600 // ... and add to molecule
601// LOG(4, "INFO: Added " << *FirstOtherAtom << " at: " << FirstOtherAtom->x << ".");
602// LOG(4, "INFO: Added " << *SecondOtherAtom << " at: " << SecondOtherAtom->x << ".");
603// LOG(4, "INFO: Added " << *ThirdOtherAtom << " at: " << ThirdOtherAtom->x << ".");
604 break;
605 default:
606 ELOG(1, "BondDegree does not state single, double or triple bond!");
607 AllWentWell = false;
608 break;
609 }
610
611 return AllWentWell;
612};
Note: See TracBrowser for help on using the repository browser.