source: src/molecule.cpp@ 0cbad2

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 Candidate_v1.7.0 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 0cbad2 was 3738f0, checked in by Frederik Heber <heber@…>, 15 years ago

Moved molecule::CreateAdjacencyList over to class BondGraph.

to make this possible we had to:

other changes:

TESTFIXES:

  • the regression test for all Actions mentioned above that don't create adjacency themselves anymore needed to be prepended with --select-all-atoms --create-adjacency.
  • Property mode set to 100755
File size: 41.2 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/** \file molecules.cpp
9 *
10 * Functions for the class molecule.
11 *
12 */
13
14// include config.h
15#ifdef HAVE_CONFIG_H
16#include <config.h>
17#endif
18
19#include "CodePatterns/MemDebug.hpp"
20
21#include <cstring>
22#include <boost/bind.hpp>
23#include <boost/foreach.hpp>
24
25#include <gsl/gsl_inline.h>
26#include <gsl/gsl_heapsort.h>
27
28#include "atom.hpp"
29#include "bond.hpp"
30#include "bondgraph.hpp"
31#include "Box.hpp"
32#include "CodePatterns/enumeration.hpp"
33#include "CodePatterns/Log.hpp"
34#include "config.hpp"
35#include "element.hpp"
36#include "Exceptions/LinearDependenceException.hpp"
37#include "graph.hpp"
38#include "Helpers/helpers.hpp"
39#include "LinearAlgebra/leastsquaremin.hpp"
40#include "LinearAlgebra/Plane.hpp"
41#include "LinearAlgebra/RealSpaceMatrix.hpp"
42#include "LinearAlgebra/Vector.hpp"
43#include "linkedcell.hpp"
44#include "molecule.hpp"
45#include "periodentafel.hpp"
46#include "tesselation.hpp"
47#include "World.hpp"
48#include "WorldTime.hpp"
49
50
51/************************************* Functions for class molecule *********************************/
52
53/** Constructor of class molecule.
54 * Initialises molecule list with correctly referenced start and end, and sets molecule::last_atom to zero.
55 */
56molecule::molecule(const periodentafel * const teil) :
57 Observable("molecule"),
58 elemente(teil),
59 MDSteps(0),
60 NoNonHydrogen(0),
61 NoNonBonds(0),
62 NoCyclicBonds(0),
63 ActiveFlag(false),
64 IndexNr(-1),
65 AtomCount(this,boost::bind(&molecule::doCountAtoms,this),"AtomCount"),
66 BondCount(this,boost::bind(&molecule::doCountBonds,this),"BondCount"),
67 last_atom(0)
68{
69
70 strcpy(name,World::getInstance().getDefaultName().c_str());
71};
72
73molecule *NewMolecule(){
74 return new molecule(World::getInstance().getPeriode());
75}
76
77/** Destructor of class molecule.
78 * Initialises molecule list with correctly referenced start and end, and sets molecule::last_atom to zero.
79 */
80molecule::~molecule()
81{
82 CleanupMolecule();
83};
84
85
86void DeleteMolecule(molecule *mol){
87 delete mol;
88}
89
90// getter and setter
91const std::string molecule::getName() const{
92 return std::string(name);
93}
94
95int molecule::getAtomCount() const{
96 return *AtomCount;
97}
98
99int molecule::getBondCount() const{
100 return *BondCount;
101}
102
103void molecule::setName(const std::string _name){
104 OBSERVE;
105 cout << "Set name of molecule " << getId() << " to " << _name << endl;
106 strncpy(name,_name.c_str(),MAXSTRINGSIZE);
107}
108
109bool molecule::changeId(moleculeId_t newId){
110 // first we move ourselves in the world
111 // the world lets us know if that succeeded
112 if(World::getInstance().changeMoleculeId(id,newId,this)){
113 id = newId;
114 return true;
115 }
116 else{
117 return false;
118 }
119}
120
121
122moleculeId_t molecule::getId() const {
123 return id;
124}
125
126void molecule::setId(moleculeId_t _id){
127 id =_id;
128}
129
130const Formula &molecule::getFormula() const {
131 return formula;
132}
133
134unsigned int molecule::getElementCount() const{
135 return formula.getElementCount();
136}
137
138bool molecule::hasElement(const element *element) const{
139 return formula.hasElement(element);
140}
141
142bool molecule::hasElement(atomicNumber_t Z) const{
143 return formula.hasElement(Z);
144}
145
146bool molecule::hasElement(const string &shorthand) const{
147 return formula.hasElement(shorthand);
148}
149
150/************************** Access to the List of Atoms ****************/
151
152
153molecule::iterator molecule::begin(){
154 return molecule::iterator(atoms.begin(),this);
155}
156
157molecule::const_iterator molecule::begin() const{
158 return atoms.begin();
159}
160
161molecule::iterator molecule::end(){
162 return molecule::iterator(atoms.end(),this);
163}
164
165molecule::const_iterator molecule::end() const{
166 return atoms.end();
167}
168
169bool molecule::empty() const
170{
171 return (begin() == end());
172}
173
174size_t molecule::size() const
175{
176 size_t counter = 0;
177 for (molecule::const_iterator iter = begin(); iter != end (); ++iter)
178 counter++;
179 return counter;
180}
181
182molecule::const_iterator molecule::erase( const_iterator loc )
183{
184 OBSERVE;
185 molecule::const_iterator iter = loc;
186 iter--;
187 atom* atom = *loc;
188 atomIds.erase( atom->getId() );
189 atoms.remove( atom );
190 formula-=atom->getType();
191 atom->removeFromMolecule();
192 return iter;
193}
194
195molecule::const_iterator molecule::erase( atom * key )
196{
197 OBSERVE;
198 molecule::const_iterator iter = find(key);
199 if (iter != end()){
200 atomIds.erase( key->getId() );
201 atoms.remove( key );
202 formula-=key->getType();
203 key->removeFromMolecule();
204 }
205 return iter;
206}
207
208molecule::const_iterator molecule::find ( atom * key ) const
209{
210 molecule::const_iterator iter;
211 for (molecule::const_iterator Runner = begin(); Runner != end(); ++Runner) {
212 if (*Runner == key)
213 return molecule::const_iterator(Runner);
214 }
215 return molecule::const_iterator(atoms.end());
216}
217
218pair<molecule::iterator,bool> molecule::insert ( atom * const key )
219{
220 OBSERVE;
221 pair<atomIdSet::iterator,bool> res = atomIds.insert(key->getId());
222 if (res.second) { // push atom if went well
223 atoms.push_back(key);
224 formula+=key->getType();
225 return pair<iterator,bool>(molecule::iterator(--end()),res.second);
226 } else {
227 return pair<iterator,bool>(molecule::iterator(end()),res.second);
228 }
229}
230
231bool molecule::containsAtom(atom* key){
232 return (find(key) != end());
233}
234
235molecule::atomVector molecule::getAtomSet() const
236{
237 atomVector vector_of_atoms;
238 BOOST_FOREACH(atom *_atom, atoms)
239 vector_of_atoms.push_back(_atom);
240 return vector_of_atoms;
241}
242
243/** Adds given atom \a *pointer from molecule list.
244 * Increases molecule::last_atom and gives last number to added atom and names it according to its element::abbrev and molecule::AtomCount
245 * \param *pointer allocated and set atom
246 * \return true - succeeded, false - atom not found in list
247 */
248bool molecule::AddAtom(atom *pointer)
249{
250 OBSERVE;
251 if (pointer != NULL) {
252 if (pointer->getType() != NULL) {
253 if (pointer->getType()->getAtomicNumber() != 1)
254 NoNonHydrogen++;
255 if(pointer->getName() == "Unknown"){
256 stringstream sstr;
257 sstr << pointer->getType()->getSymbol() << pointer->getNr()+1;
258 pointer->setName(sstr.str());
259 }
260 }
261 insert(pointer);
262 pointer->setMolecule(this);
263 }
264 return true;
265};
266
267/** Adds a copy of the given atom \a *pointer from molecule list.
268 * Increases molecule::last_atom and gives last number to added atom.
269 * \param *pointer allocated and set atom
270 * \return pointer to the newly added atom
271 */
272atom * molecule::AddCopyAtom(atom *pointer)
273{
274 atom *retval = NULL;
275 OBSERVE;
276 if (pointer != NULL) {
277 atom *walker = pointer->clone();
278 walker->setName(pointer->getName());
279 walker->setNr(last_atom++); // increase number within molecule
280 insert(walker);
281 if ((pointer->getType() != NULL) && (pointer->getType()->getAtomicNumber() != 1))
282 NoNonHydrogen++;
283 walker->setMolecule(this);
284 retval=walker;
285 }
286 return retval;
287};
288
289/** Adds a Hydrogen atom in replacement for the given atom \a *partner in bond with a *origin.
290 * Here, we have to distinguish between single, double or triple bonds as stated by \a BondDegree, that each demand
291 * a different scheme when adding \a *replacement atom for the given one.
292 * -# Single Bond: Simply add new atom with bond distance rescaled to typical hydrogen one
293 * -# Double Bond: Here, we need the **BondList of the \a *origin atom, by scanning for the other bonds instead of
294 * *Bond, we use the through these connected atoms to determine the plane they lie in, vector::MakeNormalvector().
295 * The orthonormal vector to this plane along with the vector in *Bond direction determines the plane the two
296 * replacing hydrogens shall lie in. Now, all remains to do is take the usual hydrogen double bond angle for the
297 * element of *origin and form the sin/cos admixture of both plane vectors for the new coordinates of the two
298 * hydrogens forming this angle with *origin.
299 * -# Triple Bond: The idea is to set up a tetraoid (C1-H1-H2-H3) (however the lengths \f$b\f$ of the sides of the base
300 * triangle formed by the to be added hydrogens are not equal to the typical bond distance \f$l\f$ but have to be
301 * determined from the typical angle \f$\alpha\f$ for a hydrogen triple connected to the element of *origin):
302 * We have the height \f$d\f$ as the vector in *Bond direction (from triangle C1-H1-H2).
303 * \f[ h = l \cdot \cos{\left (\frac{\alpha}{2} \right )} \qquad b = 2l \cdot \sin{\left (\frac{\alpha}{2} \right)} \quad \rightarrow \quad d = l \cdot \sqrt{\cos^2{\left (\frac{\alpha}{2} \right)}-\frac{1}{3}\cdot\sin^2{\left (\frac{\alpha}{2}\right )}}
304 * \f]
305 * vector::GetNormalvector() creates one orthonormal vector from this *Bond vector and vector::MakeNormalvector creates
306 * the third one from the former two vectors. The latter ones form the plane of the base triangle mentioned above.
307 * The lengths for these are \f$f\f$ and \f$g\f$ (from triangle H1-H2-(center of H1-H2-H3)) with knowledge that
308 * the median lines in an isosceles triangle meet in the center point with a ratio 2:1.
309 * \f[ f = \frac{b}{\sqrt{3}} \qquad g = \frac{b}{2}
310 * \f]
311 * as the coordination of all three atoms in the coordinate system of these three vectors:
312 * \f$\pmatrix{d & f & 0}\f$, \f$\pmatrix{d & -0.5 \cdot f & g}\f$ and \f$\pmatrix{d & -0.5 \cdot f & -g}\f$.
313 *
314 * \param *out output stream for debugging
315 * \param *Bond pointer to bond between \a *origin and \a *replacement
316 * \param *TopOrigin son of \a *origin of upper level molecule (the atom added to this molecule as a copy of \a *origin)
317 * \param *origin pointer to atom which acts as the origin for scaling the added hydrogen to correct bond length
318 * \param *replacement pointer to the atom which shall be copied as a hydrogen atom in this molecule
319 * \param isAngstroem whether the coordination of the given atoms is in AtomicLength (false) or Angstrom(true)
320 * \return number of atoms added, if < bond::BondDegree then something went wrong
321 * \todo double and triple bonds splitting (always use the tetraeder angle!)
322 */
323bool molecule::AddHydrogenReplacementAtom(bond *TopBond, atom *BottomOrigin, atom *TopOrigin, atom *TopReplacement, bool IsAngstroem)
324{
325 bool AllWentWell = true; // flag gathering the boolean return value of molecule::AddAtom and other functions, as return value on exit
326 OBSERVE;
327 double bondlength; // bond length of the bond to be replaced/cut
328 double bondangle; // bond angle of the bond to be replaced/cut
329 double BondRescale; // rescale value for the hydrogen bond length
330 bond *FirstBond = NULL, *SecondBond = NULL; // Other bonds in double bond case to determine "other" plane
331 atom *FirstOtherAtom = NULL, *SecondOtherAtom = NULL, *ThirdOtherAtom = NULL; // pointer to hydrogen atoms to be added
332 double b,l,d,f,g, alpha, factors[NDIM]; // hold temporary values in triple bond case for coordination determination
333 Vector Orthovector1, Orthovector2; // temporary vectors in coordination construction
334 Vector InBondvector; // vector in direction of *Bond
335 const RealSpaceMatrix &matrix = World::getInstance().getDomain().getM();
336 bond *Binder = NULL;
337
338// Log() << Verbose(3) << "Begin of AddHydrogenReplacementAtom." << endl;
339 // create vector in direction of bond
340 InBondvector = TopReplacement->getPosition() - TopOrigin->getPosition();
341 bondlength = InBondvector.Norm();
342
343 // is greater than typical bond distance? Then we have to correct periodically
344 // the problem is not the H being out of the box, but InBondvector have the wrong direction
345 // due to TopReplacement or Origin being on the wrong side!
346 double MinBondDistance;
347 double MaxBondDistance;
348 World::getInstance().getBondGraph()->getMinMaxDistance(
349 TopOrigin,
350 TopReplacement,
351 MinBondDistance,MaxBondDistance,IsAngstroem);
352 std::cout << "bondlength > MaxBondDistance: " << bondlength << " > " << MaxBondDistance << std::endl;
353 std::cout << "bondlength < MinBondDistance: " << bondlength << " < " << MinBondDistance << std::endl;
354 if ((bondlength < MinBondDistance) || (bondlength > MaxBondDistance)) {
355// Log() << Verbose(4) << "InBondvector is: ";
356// InBondvector.Output(out);
357// Log() << Verbose(0) << endl;
358 Orthovector1.Zero();
359 for (int i=NDIM;i--;) {
360 l = TopReplacement->at(i) - TopOrigin->at(i);
361 if (fabs(l) > MaxBondDistance) { // is component greater than bond distance (check against min not useful here)
362 Orthovector1[i] = (l < 0) ? -1. : +1.;
363 } // (signs are correct, was tested!)
364 }
365 Orthovector1 *= matrix;
366 InBondvector -= Orthovector1; // subtract just the additional translation
367 bondlength = InBondvector.Norm();
368// Log() << Verbose(4) << "Corrected InBondvector is now: ";
369// InBondvector.Output(out);
370// Log() << Verbose(0) << endl;
371 } // periodic correction finished
372
373 InBondvector.Normalize();
374 // get typical bond length and store as scale factor for later
375 ASSERT(TopOrigin->getType() != NULL, "AddHydrogenReplacementAtom: element of TopOrigin is not given.");
376 BondRescale = TopOrigin->getType()->getHBondDistance(TopBond->BondDegree-1);
377 if (BondRescale == -1) {
378 DoeLog(1) && (eLog()<< Verbose(1) << "There is no typical hydrogen bond distance in replacing bond (" << TopOrigin->getName() << "<->" << TopReplacement->getName() << ") of degree " << TopBond->BondDegree << "!" << endl);
379 return false;
380 BondRescale = bondlength;
381 } else {
382 if (!IsAngstroem)
383 BondRescale /= (1.*AtomicLengthToAngstroem);
384 }
385
386 // discern single, double and triple bonds
387 switch(TopBond->BondDegree) {
388 case 1:
389 FirstOtherAtom = World::getInstance().createAtom(); // new atom
390 FirstOtherAtom->setType(1); // element is Hydrogen
391 FirstOtherAtom->setAtomicVelocity(TopReplacement->getAtomicVelocity()); // copy velocity
392 FirstOtherAtom->setFixedIon(TopReplacement->getFixedIon());
393 if (TopReplacement->getType()->getAtomicNumber() == 1) { // neither rescale nor replace if it's already hydrogen
394 FirstOtherAtom->father = TopReplacement;
395 BondRescale = bondlength;
396 } else {
397 FirstOtherAtom->father = NULL; // if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father
398 }
399 InBondvector *= BondRescale; // rescale the distance vector to Hydrogen bond length
400 FirstOtherAtom->setPosition(TopOrigin->getPosition() + InBondvector); // set coordination to origin and add distance vector to replacement atom
401 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
402// Log() << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
403// FirstOtherAtom->x.Output(out);
404// Log() << Verbose(0) << endl;
405 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
406 Binder->Cyclic = false;
407 Binder->Type = bond::TreeEdge;
408 break;
409 case 2:
410 {
411 // determine two other bonds (warning if there are more than two other) plus valence sanity check
412 const BondList& ListOfBonds = TopOrigin->getListOfBonds();
413 for (BondList::const_iterator Runner = ListOfBonds.begin();
414 Runner != ListOfBonds.end();
415 ++Runner) {
416 if ((*Runner) != TopBond) {
417 if (FirstBond == NULL) {
418 FirstBond = (*Runner);
419 FirstOtherAtom = (*Runner)->GetOtherAtom(TopOrigin);
420 } else if (SecondBond == NULL) {
421 SecondBond = (*Runner);
422 SecondOtherAtom = (*Runner)->GetOtherAtom(TopOrigin);
423 } else {
424 DoeLog(2) && (eLog()<< Verbose(2) << "Detected more than four bonds for atom " << TopOrigin->getName());
425 }
426 }
427 }
428 }
429 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)
430 SecondBond = TopBond;
431 SecondOtherAtom = TopReplacement;
432 }
433 if (FirstOtherAtom != NULL) { // then we just have this double bond and the plane does not matter at all
434// Log() << Verbose(3) << "Regarding the double bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") to be constructed: Taking " << FirstOtherAtom->Name << " and " << SecondOtherAtom->Name << " along with " << TopOrigin->Name << " to determine orthogonal plane." << endl;
435
436 // determine the plane of these two with the *origin
437 try {
438 Orthovector1 =Plane(TopOrigin->getPosition(), FirstOtherAtom->getPosition(), SecondOtherAtom->getPosition()).getNormal();
439 }
440 catch(LinearDependenceException &excp){
441 Log() << Verbose(0) << excp;
442 // TODO: figure out what to do with the Orthovector in this case
443 AllWentWell = false;
444 }
445 } else {
446 Orthovector1.GetOneNormalVector(InBondvector);
447 }
448 //Log() << Verbose(3)<< "Orthovector1: ";
449 //Orthovector1.Output(out);
450 //Log() << Verbose(0) << endl;
451 // orthogonal vector and bond vector between origin and replacement form the new plane
452 Orthovector1.MakeNormalTo(InBondvector);
453 Orthovector1.Normalize();
454 //Log() << Verbose(3) << "ReScaleCheck: " << Orthovector1.Norm() << " and " << InBondvector.Norm() << "." << endl;
455
456 // create the two Hydrogens ...
457 FirstOtherAtom = World::getInstance().createAtom();
458 SecondOtherAtom = World::getInstance().createAtom();
459 FirstOtherAtom->setType(1);
460 SecondOtherAtom->setType(1);
461 FirstOtherAtom->setAtomicVelocity(TopReplacement->getAtomicVelocity()); // copy velocity
462 FirstOtherAtom->setFixedIon(TopReplacement->getFixedIon());
463 SecondOtherAtom->setAtomicVelocity(TopReplacement->getAtomicVelocity()); // copy velocity
464 SecondOtherAtom->setFixedIon(TopReplacement->getFixedIon());
465 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father
466 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father
467 bondangle = TopOrigin->getType()->getHBondAngle(1);
468 if (bondangle == -1) {
469 DoeLog(1) && (eLog()<< Verbose(1) << "There is no typical hydrogen bond angle in replacing bond (" << TopOrigin->getName() << "<->" << TopReplacement->getName() << ") of degree " << TopBond->BondDegree << "!" << endl);
470 return false;
471 bondangle = 0;
472 }
473 bondangle *= M_PI/180./2.;
474// Log() << Verbose(3) << "ReScaleCheck: InBondvector ";
475// InBondvector.Output(out);
476// Log() << Verbose(0) << endl;
477// Log() << Verbose(3) << "ReScaleCheck: Orthovector ";
478// Orthovector1.Output(out);
479// Log() << Verbose(0) << endl;
480// Log() << Verbose(3) << "Half the bond angle is " << bondangle << ", sin and cos of it: " << sin(bondangle) << ", " << cos(bondangle) << endl;
481 FirstOtherAtom->Zero();
482 SecondOtherAtom->Zero();
483 for(int i=NDIM;i--;) { // rotate by half the bond angle in both directions (InBondvector is bondangle = 0 direction)
484 FirstOtherAtom->set(i, InBondvector[i] * cos(bondangle) + Orthovector1[i] * (sin(bondangle)));
485 SecondOtherAtom->set(i, InBondvector[i] * cos(bondangle) + Orthovector1[i] * (-sin(bondangle)));
486 }
487 FirstOtherAtom->Scale(BondRescale); // rescale by correct BondDistance
488 SecondOtherAtom->Scale(BondRescale);
489 //Log() << Verbose(3) << "ReScaleCheck: " << FirstOtherAtom->x.Norm() << " and " << SecondOtherAtom->x.Norm() << "." << endl;
490 *FirstOtherAtom += TopOrigin->getPosition();
491 *SecondOtherAtom += TopOrigin->getPosition();
492 // ... and add to molecule
493 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
494 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom);
495// Log() << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
496// FirstOtherAtom->x.Output(out);
497// Log() << Verbose(0) << endl;
498// Log() << Verbose(4) << "Added " << *SecondOtherAtom << " at: ";
499// SecondOtherAtom->x.Output(out);
500// Log() << Verbose(0) << endl;
501 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
502 Binder->Cyclic = false;
503 Binder->Type = bond::TreeEdge;
504 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1);
505 Binder->Cyclic = false;
506 Binder->Type = bond::TreeEdge;
507 break;
508 case 3:
509 // take the "usual" tetraoidal angle and add the three Hydrogen in direction of the bond (height of the tetraoid)
510 FirstOtherAtom = World::getInstance().createAtom();
511 SecondOtherAtom = World::getInstance().createAtom();
512 ThirdOtherAtom = World::getInstance().createAtom();
513 FirstOtherAtom->setType(1);
514 SecondOtherAtom->setType(1);
515 ThirdOtherAtom->setType(1);
516 FirstOtherAtom->setAtomicVelocity(TopReplacement->getAtomicVelocity()); // copy velocity
517 FirstOtherAtom->setFixedIon(TopReplacement->getFixedIon());
518 SecondOtherAtom->setAtomicVelocity(TopReplacement->getAtomicVelocity()); // copy velocity
519 SecondOtherAtom->setFixedIon(TopReplacement->getFixedIon());
520 ThirdOtherAtom->setAtomicVelocity(TopReplacement->getAtomicVelocity()); // copy velocity
521 ThirdOtherAtom->setFixedIon(TopReplacement->getFixedIon());
522 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father
523 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father
524 ThirdOtherAtom->father = NULL; // we are just an added hydrogen with no father
525
526 // we need to vectors orthonormal the InBondvector
527 AllWentWell = AllWentWell && Orthovector1.GetOneNormalVector(InBondvector);
528// Log() << Verbose(3) << "Orthovector1: ";
529// Orthovector1.Output(out);
530// Log() << Verbose(0) << endl;
531 try{
532 Orthovector2 = Plane(InBondvector, Orthovector1,0).getNormal();
533 }
534 catch(LinearDependenceException &excp) {
535 Log() << Verbose(0) << excp;
536 AllWentWell = false;
537 }
538// Log() << Verbose(3) << "Orthovector2: ";
539// Orthovector2.Output(out);
540// Log() << Verbose(0) << endl;
541
542 // create correct coordination for the three atoms
543 alpha = (TopOrigin->getType()->getHBondAngle(2))/180.*M_PI/2.; // retrieve triple bond angle from database
544 l = BondRescale; // desired bond length
545 b = 2.*l*sin(alpha); // base length of isosceles triangle
546 d = l*sqrt(cos(alpha)*cos(alpha) - sin(alpha)*sin(alpha)/3.); // length for InBondvector
547 f = b/sqrt(3.); // length for Orthvector1
548 g = b/2.; // length for Orthvector2
549// Log() << Verbose(3) << "Bond length and half-angle: " << l << ", " << alpha << "\t (b,d,f,g) = " << b << ", " << d << ", " << f << ", " << g << ", " << endl;
550// Log() << Verbose(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) << endl;
551 factors[0] = d;
552 factors[1] = f;
553 factors[2] = 0.;
554 FirstOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
555 factors[1] = -0.5*f;
556 factors[2] = g;
557 SecondOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
558 factors[2] = -g;
559 ThirdOtherAtom->LinearCombinationOfVectors(InBondvector, Orthovector1, Orthovector2, factors);
560
561 // rescale each to correct BondDistance
562// FirstOtherAtom->x.Scale(&BondRescale);
563// SecondOtherAtom->x.Scale(&BondRescale);
564// ThirdOtherAtom->x.Scale(&BondRescale);
565
566 // and relative to *origin atom
567 *FirstOtherAtom += TopOrigin->getPosition();
568 *SecondOtherAtom += TopOrigin->getPosition();
569 *ThirdOtherAtom += TopOrigin->getPosition();
570
571 // ... and add to molecule
572 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
573 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom);
574 AllWentWell = AllWentWell && AddAtom(ThirdOtherAtom);
575// Log() << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
576// FirstOtherAtom->x.Output(out);
577// Log() << Verbose(0) << endl;
578// Log() << Verbose(4) << "Added " << *SecondOtherAtom << " at: ";
579// SecondOtherAtom->x.Output(out);
580// Log() << Verbose(0) << endl;
581// Log() << Verbose(4) << "Added " << *ThirdOtherAtom << " at: ";
582// ThirdOtherAtom->x.Output(out);
583// Log() << Verbose(0) << endl;
584 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
585 Binder->Cyclic = false;
586 Binder->Type = bond::TreeEdge;
587 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1);
588 Binder->Cyclic = false;
589 Binder->Type = bond::TreeEdge;
590 Binder = AddBond(BottomOrigin, ThirdOtherAtom, 1);
591 Binder->Cyclic = false;
592 Binder->Type = bond::TreeEdge;
593 break;
594 default:
595 DoeLog(1) && (eLog()<< Verbose(1) << "BondDegree does not state single, double or triple bond!" << endl);
596 AllWentWell = false;
597 break;
598 }
599
600// Log() << Verbose(3) << "End of AddHydrogenReplacementAtom." << endl;
601 return AllWentWell;
602};
603
604/** Adds given atom \a *pointer from molecule list.
605 * Increases molecule::last_atom and gives last number to added atom.
606 * \param filename name and path of xyz file
607 * \return true - succeeded, false - file not found
608 */
609bool molecule::AddXYZFile(string filename)
610{
611
612 istringstream *input = NULL;
613 int NumberOfAtoms = 0; // atom number in xyz read
614 int i; // loop variables
615 atom *Walker = NULL; // pointer to added atom
616 char shorthand[3]; // shorthand for atom name
617 ifstream xyzfile; // xyz file
618 string line; // currently parsed line
619 double x[3]; // atom coordinates
620
621 xyzfile.open(filename.c_str());
622 if (!xyzfile)
623 return false;
624
625 OBSERVE;
626 getline(xyzfile,line,'\n'); // Read numer of atoms in file
627 input = new istringstream(line);
628 *input >> NumberOfAtoms;
629 DoLog(0) && (Log() << Verbose(0) << "Parsing " << NumberOfAtoms << " atoms in file." << endl);
630 getline(xyzfile,line,'\n'); // Read comment
631 DoLog(1) && (Log() << Verbose(1) << "Comment: " << line << endl);
632
633 if (MDSteps == 0) // no atoms yet present
634 MDSteps++;
635 for(i=0;i<NumberOfAtoms;i++){
636 Walker = World::getInstance().createAtom();
637 getline(xyzfile,line,'\n');
638 istringstream *item = new istringstream(line);
639 //istringstream input(line);
640 //Log() << Verbose(1) << "Reading: " << line << endl;
641 *item >> shorthand;
642 *item >> x[0];
643 *item >> x[1];
644 *item >> x[2];
645 Walker->setType(elemente->FindElement(shorthand));
646 if (Walker->getType() == NULL) {
647 DoeLog(1) && (eLog()<< Verbose(1) << "Could not parse the element at line: '" << line << "', setting to H.");
648 Walker->setType(1);
649 }
650
651 Walker->setPosition(Vector(x));
652 Walker->setPositionAtStep(MDSteps-1, Vector(x));
653 Walker->setAtomicVelocityAtStep(MDSteps-1, zeroVec);
654 Walker->setAtomicForceAtStep(MDSteps-1, zeroVec);
655 AddAtom(Walker); // add to molecule
656 delete(item);
657 }
658 xyzfile.close();
659 delete(input);
660 return true;
661};
662
663/** Creates a copy of this molecule.
664 * \return copy of molecule
665 */
666molecule *molecule::CopyMolecule() const
667{
668 molecule *copy = World::getInstance().createMolecule();
669
670 // copy all atoms
671 for_each(atoms.begin(),atoms.end(),bind1st(mem_fun(&molecule::AddCopyAtom),copy));
672
673 // copy all bonds
674 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
675 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
676 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
677 BondRunner != ListOfBonds.end();
678 ++BondRunner)
679 if ((*BondRunner)->leftatom == *AtomRunner) {
680 bond *Binder = (*BondRunner);
681 // get the pendant atoms of current bond in the copy molecule
682 atomSet::iterator leftiter=find_if(copy->atoms.begin(),copy->atoms.end(),bind2nd(mem_fun(&atom::isFather),Binder->leftatom));
683 atomSet::iterator rightiter=find_if(copy->atoms.begin(),copy->atoms.end(),bind2nd(mem_fun(&atom::isFather),Binder->rightatom));
684 ASSERT(leftiter!=copy->atoms.end(),"No copy of original left atom for bond copy found");
685 ASSERT(leftiter!=copy->atoms.end(),"No copy of original right atom for bond copy found");
686 atom *LeftAtom = *leftiter;
687 atom *RightAtom = *rightiter;
688
689 bond *NewBond = copy->AddBond(LeftAtom, RightAtom, Binder->BondDegree);
690 NewBond->Cyclic = Binder->Cyclic;
691 if (Binder->Cyclic)
692 copy->NoCyclicBonds++;
693 NewBond->Type = Binder->Type;
694 }
695 }
696 // correct fathers
697 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::CorrectFather));
698
699 return copy;
700};
701
702
703/** Destroys all atoms inside this molecule.
704 */
705void molecule::removeAtomsinMolecule()
706{
707 // remove each atom from world
708 for(molecule::const_iterator AtomRunner = begin(); !empty(); AtomRunner = begin())
709 World::getInstance().destroyAtom(*AtomRunner);
710};
711
712
713/**
714 * Copies all atoms of a molecule which are within the defined parallelepiped.
715 *
716 * @param offest for the origin of the parallelepiped
717 * @param three vectors forming the matrix that defines the shape of the parallelpiped
718 */
719molecule* molecule::CopyMoleculeFromSubRegion(const Shape &region) const {
720 molecule *copy = World::getInstance().createMolecule();
721
722 BOOST_FOREACH(atom *iter,atoms){
723 if(iter->IsInShape(region)){
724 copy->AddCopyAtom(iter);
725 }
726 }
727
728 //TODO: copy->BuildInducedSubgraph(this);
729
730 return copy;
731}
732
733/** Adds a bond to a the molecule specified by two atoms, \a *first and \a *second.
734 * Also updates molecule::BondCount and molecule::NoNonBonds.
735 * \param *first first atom in bond
736 * \param *second atom in bond
737 * \return pointer to bond or NULL on failure
738 */
739bond * molecule::AddBond(atom *atom1, atom *atom2, int degree)
740{
741 OBSERVE;
742 bond *Binder = NULL;
743
744 // some checks to make sure we are able to create the bond
745 ASSERT(atom1, "First atom in bond-creation was an invalid pointer");
746 ASSERT(atom2, "Second atom in bond-creation was an invalid pointer");
747 ASSERT(FindAtom(atom1->getNr()),"First atom in bond-creation was not part of molecule");
748 ASSERT(FindAtom(atom2->getNr()),"Second atom in bond-creation was not part of molecule");
749
750 Binder = new bond(atom1, atom2, degree, getBondCount());
751 atom1->RegisterBond(WorldTime::getTime(), Binder);
752 atom2->RegisterBond(WorldTime::getTime(), Binder);
753 if ((atom1->getType() != NULL) && (atom1->getType()->getAtomicNumber() != 1) && (atom2->getType() != NULL) && (atom2->getType()->getAtomicNumber() != 1))
754 NoNonBonds++;
755
756 return Binder;
757};
758
759/** Remove bond from bond chain list and from the both atom::ListOfBonds.
760 * Bond::~Bond takes care of bond removal
761 * \param *pointer bond pointer
762 * \return true - bound found and removed, false - bond not found/removed
763 */
764bool molecule::RemoveBond(bond *pointer)
765{
766 //DoeLog(1) && (eLog()<< Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl);
767 delete(pointer);
768 return true;
769};
770
771/** Remove every bond from bond chain list that atom \a *BondPartner is a constituent of.
772 * \todo Function not implemented yet
773 * \param *BondPartner atom to be removed
774 * \return true - bounds found and removed, false - bonds not found/removed
775 */
776bool molecule::RemoveBonds(atom *BondPartner)
777{
778 //DoeLog(1) && (eLog()<< Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl);
779 BondList::const_iterator ForeRunner;
780 BondList& ListOfBonds = BondPartner->getListOfBonds();
781 while (!ListOfBonds.empty()) {
782 ForeRunner = ListOfBonds.begin();
783 RemoveBond(*ForeRunner);
784 }
785 return false;
786};
787
788/** Set molecule::name from the basename without suffix in the given \a *filename.
789 * \param *filename filename
790 */
791void molecule::SetNameFromFilename(const char *filename)
792{
793 int length = 0;
794 const char *molname = strrchr(filename, '/');
795 if (molname != NULL)
796 molname += sizeof(char); // search for filename without dirs
797 else
798 molname = filename; // contains no slashes
799 const char *endname = strchr(molname, '.');
800 if ((endname == NULL) || (endname < molname))
801 length = strlen(molname);
802 else
803 length = strlen(molname) - strlen(endname);
804 cout << "Set name of molecule " << getId() << " to " << molname << endl;
805 strncpy(name, molname, length);
806 name[length]='\0';
807};
808
809/** Sets the molecule::cell_size to the components of \a *dim (rectangular box)
810 * \param *dim vector class
811 */
812void molecule::SetBoxDimension(Vector *dim)
813{
814 RealSpaceMatrix domain;
815 for(int i =0; i<NDIM;++i)
816 domain.at(i,i) = dim->at(i);
817 World::getInstance().setDomain(domain);
818};
819
820/** Removes atom from molecule list and removes all of its bonds.
821 * \param *pointer atom to be removed
822 * \return true - succeeded, false - atom not found in list
823 */
824bool molecule::RemoveAtom(atom *pointer)
825{
826 ASSERT(pointer, "Null pointer passed to molecule::RemoveAtom().");
827 OBSERVE;
828 RemoveBonds(pointer);
829 erase(pointer);
830 return true;
831};
832
833/** Removes atom from molecule list, but does not delete it.
834 * \param *pointer atom to be removed
835 * \return true - succeeded, false - atom not found in list
836 */
837bool molecule::UnlinkAtom(atom *pointer)
838{
839 if (pointer == NULL)
840 return false;
841 erase(pointer);
842 return true;
843};
844
845/** Removes every atom from molecule list.
846 * \return true - succeeded, false - atom not found in list
847 */
848bool molecule::CleanupMolecule()
849{
850 for (molecule::iterator iter = begin(); !empty(); iter = begin())
851 erase(*iter);
852 return empty();
853};
854
855/** Finds an atom specified by its continuous number.
856 * \param Nr number of atom withim molecule
857 * \return pointer to atom or NULL
858 */
859atom * molecule::FindAtom(int Nr) const
860{
861 molecule::const_iterator iter = begin();
862 for (; iter != end(); ++iter)
863 if ((*iter)->getNr() == Nr)
864 break;
865 if (iter != end()) {
866 //Log() << Verbose(0) << "Found Atom Nr. " << walker->getNr() << endl;
867 return (*iter);
868 } else {
869 DoLog(0) && (Log() << Verbose(0) << "Atom not found in list." << endl);
870 return NULL;
871 }
872};
873
874/** Asks for atom number, and checks whether in list.
875 * \param *text question before entering
876 */
877atom * molecule::AskAtom(string text)
878{
879 int No;
880 atom *ion = NULL;
881 do {
882 //Log() << Verbose(0) << "============Atom list==========================" << endl;
883 //mol->Output((ofstream *)&cout);
884 //Log() << Verbose(0) << "===============================================" << endl;
885 DoLog(0) && (Log() << Verbose(0) << text);
886 cin >> No;
887 ion = this->FindAtom(No);
888 } while (ion == NULL);
889 return ion;
890};
891
892/** Checks if given coordinates are within cell volume.
893 * \param *x array of coordinates
894 * \return true - is within, false - out of cell
895 */
896bool molecule::CheckBounds(const Vector *x) const
897{
898 const RealSpaceMatrix &domain = World::getInstance().getDomain().getM();
899 bool result = true;
900 for (int i=0;i<NDIM;i++) {
901 result = result && ((x->at(i) >= 0) && (x->at(i) < domain.at(i,i)));
902 }
903 //return result;
904 return true; /// probably not gonna use the check no more
905};
906
907/** Prints molecule to *out.
908 * \param *out output stream
909 */
910bool molecule::Output(ostream * const output) const
911{
912 if (output == NULL) {
913 return false;
914 } else {
915 int AtomNo[MAX_ELEMENTS];
916 memset(AtomNo,0,(MAX_ELEMENTS-1)*sizeof(*AtomNo));
917 enumeration<const element*> elementLookup = formula.enumerateElements();
918 *output << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
919 for_each(atoms.begin(),atoms.end(),boost::bind(&atom::OutputArrayIndexed,_1,output,elementLookup,AtomNo,(const char*)0));
920 return true;
921 }
922};
923
924/** Prints molecule with all atomic trajectory positions to *out.
925 * \param *out output stream
926 */
927bool molecule::OutputTrajectories(ofstream * const output) const
928{
929 if (output == NULL) {
930 return false;
931 } else {
932 for (int step = 0; step < MDSteps; step++) {
933 if (step == 0) {
934 *output << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
935 } else {
936 *output << "# ====== MD step " << step << " =========" << endl;
937 }
938 int AtomNo[MAX_ELEMENTS];
939 memset(AtomNo,0,(MAX_ELEMENTS-1)*sizeof(*AtomNo));
940 enumeration<const element*> elementLookup = formula.enumerateElements();
941 for_each(atoms.begin(),atoms.end(),boost::bind(&atom::OutputTrajectory,_1,output,elementLookup, AtomNo, (const int)step));
942 }
943 return true;
944 }
945};
946
947/** Outputs contents of each atom::ListOfBonds.
948 * \param *out output stream
949 */
950void molecule::OutputListOfBonds() const
951{
952 std::stringstream output;
953 LOG(2, "From Contents of ListOfBonds, all atoms:");
954 for (molecule::const_iterator iter = begin();
955 iter != end();
956 ++iter) {
957 (*iter)->OutputBondOfAtom(output);
958 output << std::endl << "\t\t";
959 }
960 LOG(2, output.str());
961}
962
963/** Output of element before the actual coordination list.
964 * \param *out stream pointer
965 */
966bool molecule::Checkout(ofstream * const output) const
967{
968 return formula.checkOut(output);
969};
970
971/** Prints molecule with all its trajectories to *out as xyz file.
972 * \param *out output stream
973 */
974bool molecule::OutputTrajectoriesXYZ(ofstream * const output)
975{
976 time_t now;
977
978 if (output != NULL) {
979 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
980 for (int step=0;step<MDSteps;step++) {
981 *output << getAtomCount() << "\n\tCreated by molecuilder, step " << step << ", on " << ctime(&now);
982 for_each(atoms.begin(),atoms.end(),boost::bind(&atom::OutputTrajectoryXYZ,_1,output,step));
983 }
984 return true;
985 } else
986 return false;
987};
988
989/** Prints molecule to *out as xyz file.
990* \param *out output stream
991 */
992bool molecule::OutputXYZ(ofstream * const output) const
993{
994 time_t now;
995
996 if (output != NULL) {
997 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
998 *output << getAtomCount() << "\n\tCreated by molecuilder on " << ctime(&now);
999 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputXYZLine),output));
1000 return true;
1001 } else
1002 return false;
1003};
1004
1005/** Brings molecule::AtomCount and atom::*Name up-to-date.
1006 * \param *out output stream for debugging
1007 */
1008int molecule::doCountAtoms()
1009{
1010 int res = size();
1011 int i = 0;
1012 NoNonHydrogen = 0;
1013 for (molecule::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
1014 (*iter)->setNr(i); // update number in molecule (for easier referencing in FragmentMolecule lateron)
1015 if ((*iter)->getType()->getAtomicNumber() != 1) // count non-hydrogen atoms whilst at it
1016 NoNonHydrogen++;
1017 stringstream sstr;
1018 sstr << (*iter)->getType()->getSymbol() << (*iter)->getNr()+1;
1019 (*iter)->setName(sstr.str());
1020 DoLog(3) && (Log() << Verbose(3) << "Naming atom nr. " << (*iter)->getNr() << " " << (*iter)->getName() << "." << endl);
1021 i++;
1022 }
1023 return res;
1024};
1025
1026/** Counts the number of present bonds.
1027 * \return number of bonds
1028 */
1029int molecule::doCountBonds() const
1030{
1031 unsigned int counter = 0;
1032 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
1033 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
1034 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
1035 BondRunner != ListOfBonds.end();
1036 ++BondRunner)
1037 if ((*BondRunner)->leftatom == *AtomRunner)
1038 counter++;
1039 }
1040 return counter;
1041}
1042
1043
1044/** Returns an index map for two father-son-molecules.
1045 * The map tells which atom in this molecule corresponds to which one in the other molecul with their fathers.
1046 * \param *out output stream for debugging
1047 * \param *OtherMolecule corresponding molecule with fathers
1048 * \return allocated map of size molecule::AtomCount with map
1049 * \todo make this with a good sort O(n), not O(n^2)
1050 */
1051int * molecule::GetFatherSonAtomicMap(molecule *OtherMolecule)
1052{
1053 DoLog(3) && (Log() << Verbose(3) << "Begin of GetFatherAtomicMap." << endl);
1054 int *AtomicMap = new int[getAtomCount()];
1055 for (int i=getAtomCount();i--;)
1056 AtomicMap[i] = -1;
1057 if (OtherMolecule == this) { // same molecule
1058 for (int i=getAtomCount();i--;) // no need as -1 means already that there is trivial correspondence
1059 AtomicMap[i] = i;
1060 DoLog(4) && (Log() << Verbose(4) << "Map is trivial." << endl);
1061 } else {
1062 DoLog(4) && (Log() << Verbose(4) << "Map is ");
1063 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
1064 if ((*iter)->father == NULL) {
1065 AtomicMap[(*iter)->getNr()] = -2;
1066 } else {
1067 for (molecule::const_iterator runner = OtherMolecule->begin(); runner != OtherMolecule->end(); ++runner) {
1068 //for (int i=0;i<AtomCount;i++) { // search atom
1069 //for (int j=0;j<OtherMolecule->getAtomCount();j++) {
1070 //Log() << Verbose(4) << "Comparing father " << (*iter)->father << " with the other one " << (*runner)->father << "." << endl;
1071 if ((*iter)->father == (*runner))
1072 AtomicMap[(*iter)->getNr()] = (*runner)->getNr();
1073 }
1074 }
1075 DoLog(0) && (Log() << Verbose(0) << AtomicMap[(*iter)->getNr()] << "\t");
1076 }
1077 DoLog(0) && (Log() << Verbose(0) << endl);
1078 }
1079 DoLog(3) && (Log() << Verbose(3) << "End of GetFatherAtomicMap." << endl);
1080 return AtomicMap;
1081};
1082
1083/** Stores the temperature evaluated from velocities in molecule::Trajectories.
1084 * We simply use the formula equivaleting temperature and kinetic energy:
1085 * \f$k_B T = \sum_i m_i v_i^2\f$
1086 * \param *output output stream of temperature file
1087 * \param startstep first MD step in molecule::Trajectories
1088 * \param endstep last plus one MD step in molecule::Trajectories
1089 * \return file written (true), failure on writing file (false)
1090 */
1091bool molecule::OutputTemperatureFromTrajectories(ofstream * const output, int startstep, int endstep)
1092{
1093 double temperature;
1094 // test stream
1095 if (output == NULL)
1096 return false;
1097 else
1098 *output << "# Step Temperature [K] Temperature [a.u.]" << endl;
1099 for (int step=startstep;step < endstep; step++) { // loop over all time steps
1100 temperature = atoms.totalTemperatureAtStep(step);
1101 *output << step << "\t" << temperature*AtomicEnergyToKelvin << "\t" << temperature << endl;
1102 }
1103 return true;
1104};
1105
1106void molecule::flipActiveFlag(){
1107 ActiveFlag = !ActiveFlag;
1108}
Note: See TracBrowser for help on using the repository browser.