source: src/molecule.cpp@ 61b5f0

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 61b5f0 was 274d45, checked in by Frederik Heber <heber@…>, 15 years ago

FIX: Atoms were stored not in the sequence they were loaded.

  1. The main problem is molecule::atomSet which is a set<atom *>, i.e. atoms are sorted by their appearance in memory. As memory need not be allocated sequentially, this gives rise to extreme arbitririty which is not desired. Instead the atoms should be stored in the sequence they were loaded/created. The solution is as follows:
  • config::SaveAll()
  • molecule::atomSet is now a list<atom *>
  • molecule::atomIds is a new set<atomId_t> (atomIdSet) which controls that (global) ids remain unique in the no more Atomset's set (but list)
  • molecule::erase() erases also in atomIds
  • molecule::insert() checks whether id is present by atomIds
  • molecule::find() as std::list does not have a find, we just go through the list until the object is found (or not), this may be speeded up by another internal list.
  • molecule::InternalPointer made lots of confusion as virtual function GoToFirst() is const, hence begin() (needed therein) returns const_iterator, which then cannot be simply re-cast into an iterator: We make it a pointer, reinterpret_cast the pointer and reference it back. Although InternalPointer is mutable, the compiler cannot use the non-const function begin() (it cannot be made const, as overloading is not allowed). (this is noted in the code also extensively.)
  • molecule::containsAtom() does not use count but the new find, as it returns only boolean anyway.
  • rewrote MoleculeListClass::SimpleMerge() to get rid of the extra iterator, as we remove all atoms in the end anyway.
  • FIX: MoleculeListClass::SimpleMultiMerge() - the created mol was not inserted into the moleculelist in the end, although it is the only one to remain.
  1. All other databases had missing headers with respect to those stored in elements_db.cpp. Hence, valence of hydrogen was not parsed and this caused several failures in CalculateOrbitals() (Psi numbers and MaxMinSetp in pcp conf file).
  1. Subsequenytly, various test cases (12, 21, 30, 31, 36-38, 39) were broken. This had two reasons:
  • Seemingly, CalculateOrbitals() was broken before hence MaxMinStep (pcp config) and MaxPsiDouble/PsiMaxNn[Up|Down] were always 0. (10-21,30-31,39)
  • As the order is now correct, fixes from commits c9217161ec2a5d5db508557fe98a32068461f45b and 22a6da8380911571debebd69444d2615450bbbd8 were obselete and have been reverted (order of the Ion?_Type...): Molecules/6 (30), Molecules/7 (31), Filling/1 (39)
  • Due to different ordering, Tesselation/3 (38) had completely different .dat file (though same tesselation)
  • r3d had small differences, mostly order or epsilon (0 not being 0 but ..-e16), hence diffing was deactivated, as r3d is deprecated anyway (since vmd can render triangles as well and better).

Signed-off-by: Frederik Heber <heber@…>

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