source: src/molecules.cpp@ 3ccc3e

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 3ccc3e was 3ccc3e, checked in by Frederik Heber <heber@…>, 16 years ago

BUGFIXES: CyclicStructureAnalysis() now compatible to disconnected subgraphs, AssignKeySetsToFragment() and FillBondStructureFromReference() memory cleanup corrected

+ molecule::DepthFirstSearchAnalysis() now just returns BackEdgeStack, not MinimumRingSize. CyclicStructureAnalysis() is called during FragmentMolecule(), after subgraphs bonds list have been filled by FillBondStructureFromReference().
+ new function molecule::PickLocalBackEdges(), as the BackEdgeStack returned by DepthFirstSearchAnalysis() co
ntains only global bonds, not the local ones for the subgraph, we have to step through it and pick the right
ones out.
+ molecule::FragmentMolecule() now calls molecule::CyclicStructureAnalysis() separately for each subgraph, along with a BackEdgeStack filled by PickLocalBackEdges(), and allocates&initialises MinimumRingSize array. Als
o AssignKeySetsToFragment() frees the LocalListOfAtoms now (FreeList=true), now longer after the following wh
ile
+ molecule::CyclicStructureAnalysis() takes a local BackEdgeStack and analysis the subgraphs cycles, returnin
g minimum ring size
+ MoleculeLeafClass::AssignKeySetsToFragment() now frees memory for ListOfLocalAtoms when FreeList is set. BUGFIX: test of first key was testing against ..->nr != -1. However, LocalListOfAtoms was not even initialised correctly to NULL, hence ...->nr pointed in some cases to nowhere. Now it test atom* against NULL.
+ MoleculeLeafClass::FillBondStructureFromReference() now frees memory for ListOfLocalAtoms when FreeList is set correctly (only free initial pointer when FragmentCounter == 0, also it was decreased not before but after freeing, hence we free'd the wrong list). Also, father replaced by GetTrueFather() (makes the function moregenerally useable, was not a bug).
+ ParseCommandLineOptions() option 'D': adapted to changes in DepthFirstSearchAnalysis() in a similar manner
to FragmentMolecule()
+ molecule::CountCyclicBonds() adapted but does not perform CyclicStructureAnalysis()
+ molecule::CreateAdjacencyList() counts the bonds that could not be brought to covalently corrected degree (i.e. the remaining ionic atoms)
+ molecule::CreateListOfBondsPerAtom() prints atom names and number, which is helpful as name contains global

and number contains local number (helped in finding above bugs)

+ CreateFatherLookupTable(): BUGFIX: LookupTable was not initialised to NULL (see above)

  • Property mode set to 100644
File size: 210.5 KB
Line 
1/** \file molecules.cpp
2 *
3 * Functions for the class molecule.
4 *
5 */
6
7#include "molecules.hpp"
8
9/************************************* Other Functions *************************************/
10
11/** Determines sum of squared distances of \a X to all \a **vectors.
12 * \param *x reference vector
13 * \param *params
14 * \return sum of square distances
15 */
16double LSQ (const gsl_vector * x, void * params)
17{
18 double sum = 0.;
19 struct LSQ_params *par = (struct LSQ_params *)params;
20 Vector **vectors = par->vectors;
21 int num = par->num;
22
23 for (int i=num;i--;) {
24 for(int j=NDIM;j--;)
25 sum += (gsl_vector_get(x,j) - (vectors[i])->x[j])*(gsl_vector_get(x,j) - (vectors[i])->x[j]);
26 }
27
28 return sum;
29};
30
31/************************************* Functions for class molecule *********************************/
32
33/** Constructor of class molecule.
34 * Initialises molecule list with correctly referenced start and end, and sets molecule::last_atom to zero.
35 */
36molecule::molecule(periodentafel *teil)
37{
38 // init atom chain list
39 start = new atom;
40 end = new atom;
41 start->father = NULL;
42 end->father = NULL;
43 link(start,end);
44 // init bond chain list
45 first = new bond(start, end, 1, -1);
46 last = new bond(start, end, 1, -1);
47 link(first,last);
48 // other stuff
49 MDSteps = 0;
50 last_atom = 0;
51 elemente = teil;
52 AtomCount = 0;
53 BondCount = 0;
54 NoNonBonds = 0;
55 NoNonHydrogen = 0;
56 NoCyclicBonds = 0;
57 ListOfBondsPerAtom = NULL;
58 NumberOfBondsPerAtom = NULL;
59 ElementCount = 0;
60 for(int i=MAX_ELEMENTS;i--;)
61 ElementsInMolecule[i] = 0;
62 cell_size[0] = cell_size[2] = cell_size[5]= 20.;
63 cell_size[1] = cell_size[3] = cell_size[4]= 0.;
64};
65
66/** Destructor of class molecule.
67 * Initialises molecule list with correctly referenced start and end, and sets molecule::last_atom to zero.
68 */
69molecule::~molecule()
70{
71 if (ListOfBondsPerAtom != NULL)
72 for(int i=AtomCount;i--;)
73 Free((void **)&ListOfBondsPerAtom[i], "molecule::~molecule: ListOfBondsPerAtom[i]");
74 Free((void **)&ListOfBondsPerAtom, "molecule::~molecule: ListOfBondsPerAtom");
75 Free((void **)&NumberOfBondsPerAtom, "molecule::~molecule: NumberOfBondsPerAtom");
76 CleanupMolecule();
77 delete(first);
78 delete(last);
79 delete(end);
80 delete(start);
81};
82
83/** Adds given atom \a *pointer from molecule list.
84 * Increases molecule::last_atom and gives last number to added atom and names it according to its element::abbrev and molecule::AtomCount
85 * \param *pointer allocated and set atom
86 * \return true - succeeded, false - atom not found in list
87 */
88bool molecule::AddAtom(atom *pointer)
89{
90 if (pointer != NULL) {
91 pointer->sort = &pointer->nr;
92 pointer->nr = last_atom++; // increase number within molecule
93 AtomCount++;
94 if (pointer->type != NULL) {
95 if (ElementsInMolecule[pointer->type->Z] == 0)
96 ElementCount++;
97 ElementsInMolecule[pointer->type->Z]++; // increase number of elements
98 if (pointer->type->Z != 1)
99 NoNonHydrogen++;
100 if (pointer->Name == NULL) {
101 Free((void **)&pointer->Name, "molecule::AddAtom: *pointer->Name");
102 pointer->Name = (char *) Malloc(sizeof(char)*6, "molecule::AddAtom: *pointer->Name");
103 sprintf(pointer->Name, "%2s%02d", pointer->type->symbol, pointer->nr+1);
104 }
105 }
106 return add(pointer, end);
107 } else
108 return false;
109};
110
111/** Adds a copy of the given atom \a *pointer from molecule list.
112 * Increases molecule::last_atom and gives last number to added atom.
113 * \param *pointer allocated and set atom
114 * \return true - succeeded, false - atom not found in list
115 */
116atom * molecule::AddCopyAtom(atom *pointer)
117{
118 if (pointer != NULL) {
119 atom *walker = new atom();
120 walker->type = pointer->type; // copy element of atom
121 walker->x.CopyVector(&pointer->x); // copy coordination
122 walker->v.CopyVector(&pointer->v); // copy velocity
123 walker->FixedIon = pointer->FixedIon;
124 walker->sort = &walker->nr;
125 walker->nr = last_atom++; // increase number within molecule
126 walker->father = pointer; //->GetTrueFather();
127 walker->Name = (char *) Malloc(sizeof(char)*strlen(pointer->Name)+1, "molecule::AddCopyAtom: *Name");
128 strcpy (walker->Name, pointer->Name);
129 add(walker, end);
130 if ((pointer->type != NULL) && (pointer->type->Z != 1))
131 NoNonHydrogen++;
132 AtomCount++;
133 return walker;
134 } else
135 return NULL;
136};
137
138/** Adds a Hydrogen atom in replacement for the given atom \a *partner in bond with a *origin.
139 * Here, we have to distinguish between single, double or triple bonds as stated by \a BondDegree, that each demand
140 * a different scheme when adding \a *replacement atom for the given one.
141 * -# Single Bond: Simply add new atom with bond distance rescaled to typical hydrogen one
142 * -# Double Bond: Here, we need the **BondList of the \a *origin atom, by scanning for the other bonds instead of
143 * *Bond, we use the through these connected atoms to determine the plane they lie in, vector::MakeNormalvector().
144 * The orthonormal vector to this plane along with the vector in *Bond direction determines the plane the two
145 * replacing hydrogens shall lie in. Now, all remains to do is take the usual hydrogen double bond angle for the
146 * element of *origin and form the sin/cos admixture of both plane vectors for the new coordinates of the two
147 * hydrogens forming this angle with *origin.
148 * -# 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
149 * triangle formed by the to be added hydrogens are not equal to the typical bond distance \f$l\f$ but have to be
150 * determined from the typical angle \f$\alpha\f$ for a hydrogen triple connected to the element of *origin):
151 * We have the height \f$d\f$ as the vector in *Bond direction (from triangle C1-H1-H2).
152 * \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 )}}
153 * \f]
154 * vector::GetNormalvector() creates one orthonormal vector from this *Bond vector and vector::MakeNormalvector creates
155 * the third one from the former two vectors. The latter ones form the plane of the base triangle mentioned above.
156 * The lengths for these are \f$f\f$ and \f$g\f$ (from triangle H1-H2-(center of H1-H2-H3)) with knowledge that
157 * the median lines in an isosceles triangle meet in the center point with a ratio 2:1.
158 * \f[ f = \frac{b}{\sqrt{3}} \qquad g = \frac{b}{2}
159 * \f]
160 * as the coordination of all three atoms in the coordinate system of these three vectors:
161 * \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$.
162 *
163 * \param *out output stream for debugging
164 * \param *Bond pointer to bond between \a *origin and \a *replacement
165 * \param *TopOrigin son of \a *origin of upper level molecule (the atom added to this molecule as a copy of \a *origin)
166 * \param *origin pointer to atom which acts as the origin for scaling the added hydrogen to correct bond length
167 * \param *replacement pointer to the atom which shall be copied as a hydrogen atom in this molecule
168 * \param **BondList list of bonds \a *replacement has (necessary to determine plane for double and triple bonds)
169 * \param NumBond number of bonds in \a **BondList
170 * \param isAngstroem whether the coordination of the given atoms is in AtomicLength (false) or Angstrom(true)
171 * \return number of atoms added, if < bond::BondDegree then something went wrong
172 * \todo double and triple bonds splitting (always use the tetraeder angle!)
173 */
174bool molecule::AddHydrogenReplacementAtom(ofstream *out, bond *TopBond, atom *BottomOrigin, atom *TopOrigin, atom *TopReplacement, bond **BondList, int NumBond, bool IsAngstroem)
175{
176 double bondlength; // bond length of the bond to be replaced/cut
177 double bondangle; // bond angle of the bond to be replaced/cut
178 double BondRescale; // rescale value for the hydrogen bond length
179 bool AllWentWell = true; // flag gathering the boolean return value of molecule::AddAtom and other functions, as return value on exit
180 bond *FirstBond = NULL, *SecondBond = NULL; // Other bonds in double bond case to determine "other" plane
181 atom *FirstOtherAtom = NULL, *SecondOtherAtom = NULL, *ThirdOtherAtom = NULL; // pointer to hydrogen atoms to be added
182 double b,l,d,f,g, alpha, factors[NDIM]; // hold temporary values in triple bond case for coordination determination
183 Vector Orthovector1, Orthovector2; // temporary vectors in coordination construction
184 Vector InBondvector; // vector in direction of *Bond
185 bond *Binder = NULL;
186 double *matrix;
187
188// *out << Verbose(3) << "Begin of AddHydrogenReplacementAtom." << endl;
189 // create vector in direction of bond
190 InBondvector.CopyVector(&TopReplacement->x);
191 InBondvector.SubtractVector(&TopOrigin->x);
192 bondlength = InBondvector.Norm();
193
194 // is greater than typical bond distance? Then we have to correct periodically
195 // the problem is not the H being out of the box, but InBondvector have the wrong direction
196 // due to TopReplacement or Origin being on the wrong side!
197 if (bondlength > BondDistance) {
198// *out << Verbose(4) << "InBondvector is: ";
199// InBondvector.Output(out);
200// *out << endl;
201 Orthovector1.Zero();
202 for (int i=NDIM;i--;) {
203 l = TopReplacement->x.x[i] - TopOrigin->x.x[i];
204 if (fabs(l) > BondDistance) { // is component greater than bond distance
205 Orthovector1.x[i] = (l < 0) ? -1. : +1.;
206 } // (signs are correct, was tested!)
207 }
208 matrix = ReturnFullMatrixforSymmetric(cell_size);
209 Orthovector1.MatrixMultiplication(matrix);
210 InBondvector.SubtractVector(&Orthovector1); // subtract just the additional translation
211 Free((void **)&matrix, "molecule::AddHydrogenReplacementAtom: *matrix");
212 bondlength = InBondvector.Norm();
213// *out << Verbose(4) << "Corrected InBondvector is now: ";
214// InBondvector.Output(out);
215// *out << endl;
216 } // periodic correction finished
217
218 InBondvector.Normalize();
219 // get typical bond length and store as scale factor for later
220 BondRescale = TopOrigin->type->HBondDistance[TopBond->BondDegree-1];
221 if (BondRescale == -1) {
222 cerr << Verbose(3) << "WARNING: There is no typical bond distance for bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") of degree " << TopBond->BondDegree << "!" << endl;
223 BondRescale = bondlength;
224 } else {
225 if (!IsAngstroem)
226 BondRescale /= (1.*AtomicLengthToAngstroem);
227 }
228
229 // discern single, double and triple bonds
230 switch(TopBond->BondDegree) {
231 case 1:
232 FirstOtherAtom = new atom(); // new atom
233 FirstOtherAtom->type = elemente->FindElement(1); // element is Hydrogen
234 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
235 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
236 if (TopReplacement->type->Z == 1) { // neither rescale nor replace if it's already hydrogen
237 FirstOtherAtom->father = TopReplacement;
238 BondRescale = bondlength;
239 } else {
240 FirstOtherAtom->father = NULL; // if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father
241 }
242 InBondvector.Scale(&BondRescale); // rescale the distance vector to Hydrogen bond length
243 FirstOtherAtom->x.CopyVector(&TopOrigin->x); // set coordination to origin ...
244 FirstOtherAtom->x.AddVector(&InBondvector); // ... and add distance vector to replacement atom
245 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
246// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
247// FirstOtherAtom->x.Output(out);
248// *out << endl;
249 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
250 Binder->Cyclic = false;
251 Binder->Type = TreeEdge;
252 break;
253 case 2:
254 // determine two other bonds (warning if there are more than two other) plus valence sanity check
255 for (int i=0;i<NumBond;i++) {
256 if (BondList[i] != TopBond) {
257 if (FirstBond == NULL) {
258 FirstBond = BondList[i];
259 FirstOtherAtom = BondList[i]->GetOtherAtom(TopOrigin);
260 } else if (SecondBond == NULL) {
261 SecondBond = BondList[i];
262 SecondOtherAtom = BondList[i]->GetOtherAtom(TopOrigin);
263 } else {
264 *out << Verbose(3) << "WARNING: Detected more than four bonds for atom " << TopOrigin->Name;
265 }
266 }
267 }
268 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)
269 SecondBond = TopBond;
270 SecondOtherAtom = TopReplacement;
271 }
272 if (FirstOtherAtom != NULL) { // then we just have this double bond and the plane does not matter at all
273// *out << 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;
274
275 // determine the plane of these two with the *origin
276 AllWentWell = AllWentWell && Orthovector1.MakeNormalVector(&TopOrigin->x, &FirstOtherAtom->x, &SecondOtherAtom->x);
277 } else {
278 Orthovector1.GetOneNormalVector(&InBondvector);
279 }
280 //*out << Verbose(3)<< "Orthovector1: ";
281 //Orthovector1.Output(out);
282 //*out << endl;
283 // orthogonal vector and bond vector between origin and replacement form the new plane
284 Orthovector1.MakeNormalVector(&InBondvector);
285 Orthovector1.Normalize();
286 //*out << Verbose(3) << "ReScaleCheck: " << Orthovector1.Norm() << " and " << InBondvector.Norm() << "." << endl;
287
288 // create the two Hydrogens ...
289 FirstOtherAtom = new atom();
290 SecondOtherAtom = new atom();
291 FirstOtherAtom->type = elemente->FindElement(1);
292 SecondOtherAtom->type = elemente->FindElement(1);
293 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
294 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
295 SecondOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
296 SecondOtherAtom->FixedIon = TopReplacement->FixedIon;
297 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father
298 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father
299 bondangle = TopOrigin->type->HBondAngle[1];
300 if (bondangle == -1) {
301 *out << Verbose(3) << "WARNING: There is no typical bond angle for bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") of degree " << TopBond->BondDegree << "!" << endl;
302 bondangle = 0;
303 }
304 bondangle *= M_PI/180./2.;
305// *out << Verbose(3) << "ReScaleCheck: InBondvector ";
306// InBondvector.Output(out);
307// *out << endl;
308// *out << Verbose(3) << "ReScaleCheck: Orthovector ";
309// Orthovector1.Output(out);
310// *out << endl;
311// *out << Verbose(3) << "Half the bond angle is " << bondangle << ", sin and cos of it: " << sin(bondangle) << ", " << cos(bondangle) << endl;
312 FirstOtherAtom->x.Zero();
313 SecondOtherAtom->x.Zero();
314 for(int i=NDIM;i--;) { // rotate by half the bond angle in both directions (InBondvector is bondangle = 0 direction)
315 FirstOtherAtom->x.x[i] = InBondvector.x[i] * cos(bondangle) + Orthovector1.x[i] * (sin(bondangle));
316 SecondOtherAtom->x.x[i] = InBondvector.x[i] * cos(bondangle) + Orthovector1.x[i] * (-sin(bondangle));
317 }
318 FirstOtherAtom->x.Scale(&BondRescale); // rescale by correct BondDistance
319 SecondOtherAtom->x.Scale(&BondRescale);
320 //*out << Verbose(3) << "ReScaleCheck: " << FirstOtherAtom->x.Norm() << " and " << SecondOtherAtom->x.Norm() << "." << endl;
321 for(int i=NDIM;i--;) { // and make relative to origin atom
322 FirstOtherAtom->x.x[i] += TopOrigin->x.x[i];
323 SecondOtherAtom->x.x[i] += TopOrigin->x.x[i];
324 }
325 // ... and add to molecule
326 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
327 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom);
328// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
329// FirstOtherAtom->x.Output(out);
330// *out << endl;
331// *out << Verbose(4) << "Added " << *SecondOtherAtom << " at: ";
332// SecondOtherAtom->x.Output(out);
333// *out << endl;
334 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
335 Binder->Cyclic = false;
336 Binder->Type = TreeEdge;
337 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1);
338 Binder->Cyclic = false;
339 Binder->Type = TreeEdge;
340 break;
341 case 3:
342 // take the "usual" tetraoidal angle and add the three Hydrogen in direction of the bond (height of the tetraoid)
343 FirstOtherAtom = new atom();
344 SecondOtherAtom = new atom();
345 ThirdOtherAtom = new atom();
346 FirstOtherAtom->type = elemente->FindElement(1);
347 SecondOtherAtom->type = elemente->FindElement(1);
348 ThirdOtherAtom->type = elemente->FindElement(1);
349 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
350 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
351 SecondOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
352 SecondOtherAtom->FixedIon = TopReplacement->FixedIon;
353 ThirdOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
354 ThirdOtherAtom->FixedIon = TopReplacement->FixedIon;
355 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father
356 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father
357 ThirdOtherAtom->father = NULL; // we are just an added hydrogen with no father
358
359 // we need to vectors orthonormal the InBondvector
360 AllWentWell = AllWentWell && Orthovector1.GetOneNormalVector(&InBondvector);
361// *out << Verbose(3) << "Orthovector1: ";
362// Orthovector1.Output(out);
363// *out << endl;
364 AllWentWell = AllWentWell && Orthovector2.MakeNormalVector(&InBondvector, &Orthovector1);
365// *out << Verbose(3) << "Orthovector2: ";
366// Orthovector2.Output(out);
367// *out << endl;
368
369 // create correct coordination for the three atoms
370 alpha = (TopOrigin->type->HBondAngle[2])/180.*M_PI/2.; // retrieve triple bond angle from database
371 l = BondRescale; // desired bond length
372 b = 2.*l*sin(alpha); // base length of isosceles triangle
373 d = l*sqrt(cos(alpha)*cos(alpha) - sin(alpha)*sin(alpha)/3.); // length for InBondvector
374 f = b/sqrt(3.); // length for Orthvector1
375 g = b/2.; // length for Orthvector2
376// *out << Verbose(3) << "Bond length and half-angle: " << l << ", " << alpha << "\t (b,d,f,g) = " << b << ", " << d << ", " << f << ", " << g << ", " << endl;
377// *out << 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;
378 factors[0] = d;
379 factors[1] = f;
380 factors[2] = 0.;
381 FirstOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
382 factors[1] = -0.5*f;
383 factors[2] = g;
384 SecondOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
385 factors[2] = -g;
386 ThirdOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
387
388 // rescale each to correct BondDistance
389// FirstOtherAtom->x.Scale(&BondRescale);
390// SecondOtherAtom->x.Scale(&BondRescale);
391// ThirdOtherAtom->x.Scale(&BondRescale);
392
393 // and relative to *origin atom
394 FirstOtherAtom->x.AddVector(&TopOrigin->x);
395 SecondOtherAtom->x.AddVector(&TopOrigin->x);
396 ThirdOtherAtom->x.AddVector(&TopOrigin->x);
397
398 // ... and add to molecule
399 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
400 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom);
401 AllWentWell = AllWentWell && AddAtom(ThirdOtherAtom);
402// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
403// FirstOtherAtom->x.Output(out);
404// *out << endl;
405// *out << Verbose(4) << "Added " << *SecondOtherAtom << " at: ";
406// SecondOtherAtom->x.Output(out);
407// *out << endl;
408// *out << Verbose(4) << "Added " << *ThirdOtherAtom << " at: ";
409// ThirdOtherAtom->x.Output(out);
410// *out << endl;
411 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
412 Binder->Cyclic = false;
413 Binder->Type = TreeEdge;
414 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1);
415 Binder->Cyclic = false;
416 Binder->Type = TreeEdge;
417 Binder = AddBond(BottomOrigin, ThirdOtherAtom, 1);
418 Binder->Cyclic = false;
419 Binder->Type = TreeEdge;
420 break;
421 default:
422 cerr << "ERROR: BondDegree does not state single, double or triple bond!" << endl;
423 AllWentWell = false;
424 break;
425 }
426
427// *out << Verbose(3) << "End of AddHydrogenReplacementAtom." << endl;
428 return AllWentWell;
429};
430
431/** Adds given atom \a *pointer from molecule list.
432 * Increases molecule::last_atom and gives last number to added atom.
433 * \param filename name and path of xyz file
434 * \return true - succeeded, false - file not found
435 */
436bool molecule::AddXYZFile(string filename)
437{
438 istringstream *input = NULL;
439 int NumberOfAtoms = 0; // atom number in xyz read
440 int i, j; // loop variables
441 atom *Walker = NULL; // pointer to added atom
442 char shorthand[3]; // shorthand for atom name
443 ifstream xyzfile; // xyz file
444 string line; // currently parsed line
445 double x[3]; // atom coordinates
446
447 xyzfile.open(filename.c_str());
448 if (!xyzfile)
449 return false;
450
451 getline(xyzfile,line,'\n'); // Read numer of atoms in file
452 input = new istringstream(line);
453 *input >> NumberOfAtoms;
454 cout << Verbose(0) << "Parsing " << NumberOfAtoms << " atoms in file." << endl;
455 getline(xyzfile,line,'\n'); // Read comment
456 cout << Verbose(1) << "Comment: " << line << endl;
457
458 if (MDSteps == 0) // no atoms yet present
459 MDSteps++;
460 for(i=0;i<NumberOfAtoms;i++){
461 Walker = new atom;
462 getline(xyzfile,line,'\n');
463 istringstream *item = new istringstream(line);
464 //istringstream input(line);
465 //cout << Verbose(1) << "Reading: " << line << endl;
466 *item >> shorthand;
467 *item >> x[0];
468 *item >> x[1];
469 *item >> x[2];
470 Walker->type = elemente->FindElement(shorthand);
471 if (Walker->type == NULL) {
472 cerr << "Could not parse the element at line: '" << line << "', setting to H.";
473 Walker->type = elemente->FindElement(1);
474 }
475 if (Trajectories[Walker].R.size() <= (unsigned int)MDSteps) {
476 Trajectories[Walker].R.resize(MDSteps+10);
477 Trajectories[Walker].U.resize(MDSteps+10);
478 Trajectories[Walker].F.resize(MDSteps+10);
479 }
480 for(j=NDIM;j--;) {
481 Walker->x.x[j] = x[j];
482 Trajectories[Walker].R.at(MDSteps-1).x[j] = x[j];
483 Trajectories[Walker].U.at(MDSteps-1).x[j] = 0;
484 Trajectories[Walker].F.at(MDSteps-1).x[j] = 0;
485 }
486 AddAtom(Walker); // add to molecule
487 delete(item);
488 }
489 xyzfile.close();
490 delete(input);
491 return true;
492};
493
494/** Creates a copy of this molecule.
495 * \return copy of molecule
496 */
497molecule *molecule::CopyMolecule()
498{
499 molecule *copy = new molecule(elemente);
500 atom *CurrentAtom = NULL;
501 atom *LeftAtom = NULL, *RightAtom = NULL;
502 atom *Walker = NULL;
503
504 // copy all atoms
505 Walker = start;
506 while(Walker->next != end) {
507 Walker = Walker->next;
508 CurrentAtom = copy->AddCopyAtom(Walker);
509 }
510
511 // copy all bonds
512 bond *Binder = first;
513 bond *NewBond = NULL;
514 while(Binder->next != last) {
515 Binder = Binder->next;
516 // get the pendant atoms of current bond in the copy molecule
517 LeftAtom = copy->start;
518 while (LeftAtom->next != copy->end) {
519 LeftAtom = LeftAtom->next;
520 if (LeftAtom->father == Binder->leftatom)
521 break;
522 }
523 RightAtom = copy->start;
524 while (RightAtom->next != copy->end) {
525 RightAtom = RightAtom->next;
526 if (RightAtom->father == Binder->rightatom)
527 break;
528 }
529 NewBond = copy->AddBond(LeftAtom, RightAtom, Binder->BondDegree);
530 NewBond->Cyclic = Binder->Cyclic;
531 if (Binder->Cyclic)
532 copy->NoCyclicBonds++;
533 NewBond->Type = Binder->Type;
534 }
535 // correct fathers
536 Walker = copy->start;
537 while(Walker->next != copy->end) {
538 Walker = Walker->next;
539 if (Walker->father->father == Walker->father) // same atom in copy's father points to itself
540 Walker->father = Walker; // set father to itself (copy of a whole molecule)
541 else
542 Walker->father = Walker->father->father; // set father to original's father
543 }
544 // copy values
545 copy->CountAtoms((ofstream *)&cout);
546 copy->CountElements();
547 if (first->next != last) { // if adjaceny list is present
548 copy->BondDistance = BondDistance;
549 copy->CreateListOfBondsPerAtom((ofstream *)&cout);
550 }
551
552 return copy;
553};
554
555/** Adds a bond to a the molecule specified by two atoms, \a *first and \a *second.
556 * Also updates molecule::BondCount and molecule::NoNonBonds.
557 * \param *first first atom in bond
558 * \param *second atom in bond
559 * \return pointer to bond or NULL on failure
560 */
561bond * molecule::AddBond(atom *atom1, atom *atom2, int degree=1)
562{
563 bond *Binder = NULL;
564 if ((atom1 != NULL) && (FindAtom(atom1->nr) != NULL) && (atom2 != NULL) && (FindAtom(atom2->nr) != NULL)) {
565 Binder = new bond(atom1, atom2, degree, BondCount++);
566 if ((atom1->type != NULL) && (atom1->type->Z != 1) && (atom2->type != NULL) && (atom2->type->Z != 1))
567 NoNonBonds++;
568 add(Binder, last);
569 } else {
570 cerr << Verbose(1) << "ERROR: Could not add bond between " << atom1->Name << " and " << atom2->Name << " as one or both are not present in the molecule." << endl;
571 }
572 return Binder;
573};
574
575/** Remove bond from bond chain list.
576 * \todo Function not implemented yet
577 * \param *pointer bond pointer
578 * \return true - bound found and removed, false - bond not found/removed
579 */
580bool molecule::RemoveBond(bond *pointer)
581{
582 //cerr << Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl;
583 removewithoutcheck(pointer);
584 return true;
585};
586
587/** Remove every bond from bond chain list that atom \a *BondPartner is a constituent of.
588 * \todo Function not implemented yet
589 * \param *BondPartner atom to be removed
590 * \return true - bounds found and removed, false - bonds not found/removed
591 */
592bool molecule::RemoveBonds(atom *BondPartner)
593{
594 cerr << Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl;
595 return false;
596};
597
598/** Sets the molecule::cell_size to the components of \a *dim (rectangular box)
599 * \param *dim vector class
600 */
601void molecule::SetBoxDimension(Vector *dim)
602{
603 cell_size[0] = dim->x[0];
604 cell_size[1] = 0.;
605 cell_size[2] = dim->x[1];
606 cell_size[3] = 0.;
607 cell_size[4] = 0.;
608 cell_size[5] = dim->x[2];
609};
610
611/** Centers the molecule in the box whose lengths are defined by vector \a *BoxLengths.
612 * \param *out output stream for debugging
613 * \param *BoxLengths box lengths
614 */
615bool molecule::CenterInBox(ofstream *out, Vector *BoxLengths)
616{
617 bool status = true;
618 atom *ptr = NULL;
619 Vector *min = new Vector;
620 Vector *max = new Vector;
621
622 // gather min and max for each axis
623 ptr = start->next; // start at first in list
624 if (ptr != end) { //list not empty?
625 for (int i=NDIM;i--;) {
626 max->x[i] = ptr->x.x[i];
627 min->x[i] = ptr->x.x[i];
628 }
629 while (ptr->next != end) { // continue with second if present
630 ptr = ptr->next;
631 //ptr->Output(1,1,out);
632 for (int i=NDIM;i--;) {
633 max->x[i] = (max->x[i] < ptr->x.x[i]) ? ptr->x.x[i] : max->x[i];
634 min->x[i] = (min->x[i] > ptr->x.x[i]) ? ptr->x.x[i] : min->x[i];
635 }
636 }
637 }
638 // sanity check
639 for(int i=NDIM;i--;) {
640 if (max->x[i] - min->x[i] > BoxLengths->x[i])
641 status = false;
642 }
643 // warn if check failed
644 if (!status)
645 *out << "WARNING: molecule is bigger than defined box!" << endl;
646 else { // else center in box
647 max->AddVector(min);
648 max->Scale(-1.);
649 max->AddVector(BoxLengths);
650 max->Scale(0.5);
651 Translate(max);
652 }
653
654 // free and exit
655 delete(min);
656 delete(max);
657 return status;
658};
659
660/** Centers the edge of the atoms at (0,0,0).
661 * \param *out output stream for debugging
662 * \param *max coordinates of other edge, specifying box dimensions.
663 */
664void molecule::CenterEdge(ofstream *out, Vector *max)
665{
666 Vector *min = new Vector;
667
668// *out << Verbose(3) << "Begin of CenterEdge." << endl;
669 atom *ptr = start->next; // start at first in list
670 if (ptr != end) { //list not empty?
671 for (int i=NDIM;i--;) {
672 max->x[i] = ptr->x.x[i];
673 min->x[i] = ptr->x.x[i];
674 }
675 while (ptr->next != end) { // continue with second if present
676 ptr = ptr->next;
677 //ptr->Output(1,1,out);
678 for (int i=NDIM;i--;) {
679 max->x[i] = (max->x[i] < ptr->x.x[i]) ? ptr->x.x[i] : max->x[i];
680 min->x[i] = (min->x[i] > ptr->x.x[i]) ? ptr->x.x[i] : min->x[i];
681 }
682 }
683// *out << Verbose(4) << "Maximum is ";
684// max->Output(out);
685// *out << ", Minimum is ";
686// min->Output(out);
687// *out << endl;
688 min->Scale(-1.);
689 max->AddVector(min);
690 Translate(min);
691 }
692 delete(min);
693// *out << Verbose(3) << "End of CenterEdge." << endl;
694};
695
696/** Centers the center of the atoms at (0,0,0).
697 * \param *out output stream for debugging
698 * \param *center return vector for translation vector
699 */
700void molecule::CenterOrigin(ofstream *out, Vector *center)
701{
702 int Num = 0;
703 atom *ptr = start->next; // start at first in list
704
705 for(int i=NDIM;i--;) // zero center vector
706 center->x[i] = 0.;
707
708 if (ptr != end) { //list not empty?
709 while (ptr->next != end) { // continue with second if present
710 ptr = ptr->next;
711 Num++;
712 center->AddVector(&ptr->x);
713 }
714 center->Scale(-1./Num); // divide through total number (and sign for direction)
715 Translate(center);
716 }
717};
718
719/** Returns vector pointing to center of gravity.
720 * \param *out output stream for debugging
721 * \return pointer to center of gravity vector
722 */
723Vector * molecule::DetermineCenterOfAll(ofstream *out)
724{
725 atom *ptr = start->next; // start at first in list
726 Vector *a = new Vector();
727 Vector tmp;
728 double Num = 0;
729
730 a->Zero();
731
732 if (ptr != end) { //list not empty?
733 while (ptr->next != end) { // continue with second if present
734 ptr = ptr->next;
735 Num += 1.;
736 tmp.CopyVector(&ptr->x);
737 a->AddVector(&tmp);
738 }
739 a->Scale(-1./Num); // divide through total mass (and sign for direction)
740 }
741 //cout << Verbose(1) << "Resulting center of gravity: ";
742 //a->Output(out);
743 //cout << endl;
744 return a;
745};
746
747/** Returns vector pointing to center of gravity.
748 * \param *out output stream for debugging
749 * \return pointer to center of gravity vector
750 */
751Vector * molecule::DetermineCenterOfGravity(ofstream *out)
752{
753 atom *ptr = start->next; // start at first in list
754 Vector *a = new Vector();
755 Vector tmp;
756 double Num = 0;
757
758 a->Zero();
759
760 if (ptr != end) { //list not empty?
761 while (ptr->next != end) { // continue with second if present
762 ptr = ptr->next;
763 Num += ptr->type->mass;
764 tmp.CopyVector(&ptr->x);
765 tmp.Scale(ptr->type->mass); // scale by mass
766 a->AddVector(&tmp);
767 }
768 a->Scale(-1./Num); // divide through total mass (and sign for direction)
769 }
770// *out << Verbose(1) << "Resulting center of gravity: ";
771// a->Output(out);
772// *out << endl;
773 return a;
774};
775
776/** Centers the center of gravity of the atoms at (0,0,0).
777 * \param *out output stream for debugging
778 * \param *center return vector for translation vector
779 */
780void molecule::CenterGravity(ofstream *out, Vector *center)
781{
782 if (center == NULL) {
783 DetermineCenter(*center);
784 Translate(center);
785 delete(center);
786 } else {
787 Translate(center);
788 }
789};
790
791/** Scales all atoms by \a *factor.
792 * \param *factor pointer to scaling factor
793 */
794void molecule::Scale(double **factor)
795{
796 atom *ptr = start;
797
798 while (ptr->next != end) {
799 ptr = ptr->next;
800 for (int j=0;j<MDSteps;j++)
801 Trajectories[ptr].R.at(j).Scale(factor);
802 ptr->x.Scale(factor);
803 }
804};
805
806/** Translate all atoms by given vector.
807 * \param trans[] translation vector.
808 */
809void molecule::Translate(const Vector *trans)
810{
811 atom *ptr = start;
812
813 while (ptr->next != end) {
814 ptr = ptr->next;
815 for (int j=0;j<MDSteps;j++)
816 Trajectories[ptr].R.at(j).Translate(trans);
817 ptr->x.Translate(trans);
818 }
819};
820
821/** Mirrors all atoms against a given plane.
822 * \param n[] normal vector of mirror plane.
823 */
824void molecule::Mirror(const Vector *n)
825{
826 atom *ptr = start;
827
828 while (ptr->next != end) {
829 ptr = ptr->next;
830 for (int j=0;j<MDSteps;j++)
831 Trajectories[ptr].R.at(j).Mirror(n);
832 ptr->x.Mirror(n);
833 }
834};
835
836/** Determines center of molecule (yet not considering atom masses).
837 * \param Center reference to return vector
838 */
839void molecule::DetermineCenter(Vector &Center)
840{
841 atom *Walker = start;
842 bond *Binder = NULL;
843 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
844 double tmp;
845 bool flag;
846 Vector Testvector, Translationvector;
847
848 do {
849 Center.Zero();
850 flag = true;
851 while (Walker->next != end) {
852 Walker = Walker->next;
853#ifdef ADDHYDROGEN
854 if (Walker->type->Z != 1) {
855#endif
856 Testvector.CopyVector(&Walker->x);
857 Testvector.InverseMatrixMultiplication(matrix);
858 Translationvector.Zero();
859 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
860 Binder = ListOfBondsPerAtom[Walker->nr][i];
861 if (Walker->nr < Binder->GetOtherAtom(Walker)->nr) // otherwise we shift one to, the other fro and gain nothing
862 for (int j=0;j<NDIM;j++) {
863 tmp = Walker->x.x[j] - Binder->GetOtherAtom(Walker)->x.x[j];
864 if ((fabs(tmp)) > BondDistance) {
865 flag = false;
866 cout << Verbose(0) << "Hit: atom " << Walker->Name << " in bond " << *Binder << " has to be shifted due to " << tmp << "." << endl;
867 if (tmp > 0)
868 Translationvector.x[j] -= 1.;
869 else
870 Translationvector.x[j] += 1.;
871 }
872 }
873 }
874 Testvector.AddVector(&Translationvector);
875 Testvector.MatrixMultiplication(matrix);
876 Center.AddVector(&Testvector);
877 cout << Verbose(1) << "vector is: ";
878 Testvector.Output((ofstream *)&cout);
879 cout << endl;
880#ifdef ADDHYDROGEN
881 // now also change all hydrogens
882 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
883 Binder = ListOfBondsPerAtom[Walker->nr][i];
884 if (Binder->GetOtherAtom(Walker)->type->Z == 1) {
885 Testvector.CopyVector(&Binder->GetOtherAtom(Walker)->x);
886 Testvector.InverseMatrixMultiplication(matrix);
887 Testvector.AddVector(&Translationvector);
888 Testvector.MatrixMultiplication(matrix);
889 Center.AddVector(&Testvector);
890 cout << Verbose(1) << "Hydrogen vector is: ";
891 Testvector.Output((ofstream *)&cout);
892 cout << endl;
893 }
894 }
895 }
896#endif
897 }
898 } while (!flag);
899 Free((void **)&matrix, "molecule::DetermineCenter: *matrix");
900 Center.Scale(1./(double)AtomCount);
901};
902
903/** Transforms/Rotates the given molecule into its principal axis system.
904 * \param *out output stream for debugging
905 * \param DoRotate whether to rotate (true) or only to determine the PAS.
906 */
907void molecule::PrincipalAxisSystem(ofstream *out, bool DoRotate)
908{
909 atom *ptr = start; // start at first in list
910 double InertiaTensor[NDIM*NDIM];
911 Vector *CenterOfGravity = DetermineCenterOfGravity(out);
912
913 CenterGravity(out, CenterOfGravity);
914
915 // reset inertia tensor
916 for(int i=0;i<NDIM*NDIM;i++)
917 InertiaTensor[i] = 0.;
918
919 // sum up inertia tensor
920 while (ptr->next != end) {
921 ptr = ptr->next;
922 Vector x;
923 x.CopyVector(&ptr->x);
924 //x.SubtractVector(CenterOfGravity);
925 InertiaTensor[0] += ptr->type->mass*(x.x[1]*x.x[1] + x.x[2]*x.x[2]);
926 InertiaTensor[1] += ptr->type->mass*(-x.x[0]*x.x[1]);
927 InertiaTensor[2] += ptr->type->mass*(-x.x[0]*x.x[2]);
928 InertiaTensor[3] += ptr->type->mass*(-x.x[1]*x.x[0]);
929 InertiaTensor[4] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[2]*x.x[2]);
930 InertiaTensor[5] += ptr->type->mass*(-x.x[1]*x.x[2]);
931 InertiaTensor[6] += ptr->type->mass*(-x.x[2]*x.x[0]);
932 InertiaTensor[7] += ptr->type->mass*(-x.x[2]*x.x[1]);
933 InertiaTensor[8] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[1]*x.x[1]);
934 }
935 // print InertiaTensor for debugging
936 *out << "The inertia tensor is:" << endl;
937 for(int i=0;i<NDIM;i++) {
938 for(int j=0;j<NDIM;j++)
939 *out << InertiaTensor[i*NDIM+j] << " ";
940 *out << endl;
941 }
942 *out << endl;
943
944 // diagonalize to determine principal axis system
945 gsl_eigen_symmv_workspace *T = gsl_eigen_symmv_alloc(NDIM);
946 gsl_matrix_view m = gsl_matrix_view_array(InertiaTensor, NDIM, NDIM);
947 gsl_vector *eval = gsl_vector_alloc(NDIM);
948 gsl_matrix *evec = gsl_matrix_alloc(NDIM, NDIM);
949 gsl_eigen_symmv(&m.matrix, eval, evec, T);
950 gsl_eigen_symmv_free(T);
951 gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_DESC);
952
953 for(int i=0;i<NDIM;i++) {
954 *out << Verbose(1) << "eigenvalue = " << gsl_vector_get(eval, i);
955 *out << ", eigenvector = (" << evec->data[i * evec->tda + 0] << "," << evec->data[i * evec->tda + 1] << "," << evec->data[i * evec->tda + 2] << ")" << endl;
956 }
957
958 // check whether we rotate or not
959 if (DoRotate) {
960 *out << Verbose(1) << "Transforming molecule into PAS ... ";
961 // the eigenvectors specify the transformation matrix
962 ptr = start;
963 while (ptr->next != end) {
964 ptr = ptr->next;
965 for (int j=0;j<MDSteps;j++)
966 Trajectories[ptr].R.at(j).MatrixMultiplication(evec->data);
967 ptr->x.MatrixMultiplication(evec->data);
968 }
969 *out << "done." << endl;
970
971 // summing anew for debugging (resulting matrix has to be diagonal!)
972 // reset inertia tensor
973 for(int i=0;i<NDIM*NDIM;i++)
974 InertiaTensor[i] = 0.;
975
976 // sum up inertia tensor
977 ptr = start;
978 while (ptr->next != end) {
979 ptr = ptr->next;
980 Vector x;
981 x.CopyVector(&ptr->x);
982 //x.SubtractVector(CenterOfGravity);
983 InertiaTensor[0] += ptr->type->mass*(x.x[1]*x.x[1] + x.x[2]*x.x[2]);
984 InertiaTensor[1] += ptr->type->mass*(-x.x[0]*x.x[1]);
985 InertiaTensor[2] += ptr->type->mass*(-x.x[0]*x.x[2]);
986 InertiaTensor[3] += ptr->type->mass*(-x.x[1]*x.x[0]);
987 InertiaTensor[4] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[2]*x.x[2]);
988 InertiaTensor[5] += ptr->type->mass*(-x.x[1]*x.x[2]);
989 InertiaTensor[6] += ptr->type->mass*(-x.x[2]*x.x[0]);
990 InertiaTensor[7] += ptr->type->mass*(-x.x[2]*x.x[1]);
991 InertiaTensor[8] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[1]*x.x[1]);
992 }
993 // print InertiaTensor for debugging
994 *out << "The inertia tensor is:" << endl;
995 for(int i=0;i<NDIM;i++) {
996 for(int j=0;j<NDIM;j++)
997 *out << InertiaTensor[i*NDIM+j] << " ";
998 *out << endl;
999 }
1000 *out << endl;
1001 }
1002
1003 // free everything
1004 delete(CenterOfGravity);
1005 gsl_vector_free(eval);
1006 gsl_matrix_free(evec);
1007};
1008
1009/** Parses nuclear forces from file and performs Verlet integration.
1010 * Note that we assume the parsed forces to be in atomic units (hence, if coordinates are in angstroem, we
1011 * have to transform them).
1012 * This adds a new MD step to the config file.
1013 * \param *file filename
1014 * \param delta_t time step width in atomic units
1015 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false)
1016 * \return true - file found and parsed, false - file not found or imparsable
1017 */
1018bool molecule::VerletForceIntegration(char *file, double delta_t, bool IsAngstroem)
1019{
1020 element *runner = elemente->start;
1021 atom *walker = NULL;
1022 int AtomNo;
1023 ifstream input(file);
1024 string token;
1025 stringstream item;
1026 double a, IonMass, Vector[NDIM];
1027 ForceMatrix Force;
1028
1029 CountElements(); // make sure ElementsInMolecule is up to date
1030
1031 // check file
1032 if (input == NULL) {
1033 return false;
1034 } else {
1035 // parse file into ForceMatrix
1036 if (!Force.ParseMatrix(file, 0,0,0)) {
1037 cerr << "Could not parse Force Matrix file " << file << "." << endl;
1038 return false;
1039 }
1040 if (Force.RowCounter[0] != AtomCount) {
1041 cerr << "Mismatch between number of atoms in file " << Force.RowCounter[0] << " and in molecule " << AtomCount << "." << endl;
1042 return false;
1043 }
1044 // correct Forces
1045 for(int d=0;d<NDIM;d++)
1046 Vector[d] = 0.;
1047 for(int i=0;i<AtomCount;i++)
1048 for(int d=0;d<NDIM;d++) {
1049 Vector[d] += Force.Matrix[0][i][d+5];
1050 }
1051 for(int i=0;i<AtomCount;i++)
1052 for(int d=0;d<NDIM;d++) {
1053 Force.Matrix[0][i][d+5] -= Vector[d]/(double)AtomCount;
1054 }
1055 // and perform Verlet integration for each atom with position, velocity and force vector
1056 runner = elemente->start;
1057 while (runner->next != elemente->end) { // go through every element
1058 runner = runner->next;
1059 IonMass = runner->mass;
1060 a = delta_t*0.5/IonMass; // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a
1061 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1062 AtomNo = 0;
1063 walker = start;
1064 while (walker->next != end) { // go through every atom of this element
1065 walker = walker->next;
1066 if (walker->type == runner) { // if this atom fits to element
1067 // check size of vectors
1068 if (Trajectories[walker].R.size() <= (unsigned int)(MDSteps)) {
1069 //cout << "Increasing size for trajectory array of " << *walker << " to " << (size+10) << "." << endl;
1070 Trajectories[walker].R.resize(MDSteps+10);
1071 Trajectories[walker].U.resize(MDSteps+10);
1072 Trajectories[walker].F.resize(MDSteps+10);
1073 }
1074
1075 // Update R (and F)
1076 for (int d=0; d<NDIM; d++) {
1077 Trajectories[walker].F.at(MDSteps).x[d] = -Force.Matrix[0][AtomNo][d+5]*(IsAngstroem ? AtomicLengthToAngstroem : 1.);
1078 Trajectories[walker].R.at(MDSteps).x[d] = Trajectories[walker].R.at(MDSteps-1).x[d];
1079 Trajectories[walker].R.at(MDSteps).x[d] += delta_t*(Trajectories[walker].U.at(MDSteps-1).x[d]);
1080 Trajectories[walker].R.at(MDSteps).x[d] += delta_t*a*(Trajectories[walker].F.at(MDSteps).x[d]); // F = m * a and s = 0.5 * F/m * t^2 = F * a * t
1081 }
1082 // Update U
1083 for (int d=0; d<NDIM; d++) {
1084 Trajectories[walker].U.at(MDSteps).x[d] = Trajectories[walker].U.at(MDSteps-1).x[d];
1085 Trajectories[walker].U.at(MDSteps).x[d] += a * (Trajectories[walker].F.at(MDSteps).x[d]+Trajectories[walker].F.at(MDSteps-1).x[d]);
1086 }
1087// cout << "Integrated position&velocity of step " << (MDSteps) << ": (";
1088// for (int d=0;d<NDIM;d++)
1089// cout << Trajectories[walker].R.at(MDSteps).x[d] << " "; // next step
1090// cout << ")\t(";
1091// for (int d=0;d<NDIM;d++)
1092// cout << Trajectories[walker].U.at(MDSteps).x[d] << " "; // next step
1093// cout << ")" << endl;
1094 // next atom
1095 AtomNo++;
1096 }
1097 }
1098 }
1099 }
1100 }
1101// // correct velocities (rather momenta) so that center of mass remains motionless
1102// for(int d=0;d<NDIM;d++)
1103// Vector[d] = 0.;
1104// IonMass = 0.;
1105// walker = start;
1106// while (walker->next != end) { // go through every atom
1107// walker = walker->next;
1108// IonMass += walker->type->mass; // sum up total mass
1109// for(int d=0;d<NDIM;d++) {
1110// Vector[d] += Trajectories[walker].U.at(MDSteps).x[d]*walker->type->mass;
1111// }
1112// }
1113// walker = start;
1114// while (walker->next != end) { // go through every atom of this element
1115// walker = walker->next;
1116// for(int d=0;d<NDIM;d++) {
1117// Trajectories[walker].U.at(MDSteps).x[d] -= Vector[d]*walker->type->mass/IonMass;
1118// }
1119// }
1120 MDSteps++;
1121
1122
1123 // exit
1124 return true;
1125};
1126
1127/** Align all atoms in such a manner that given vector \a *n is along z axis.
1128 * \param n[] alignment vector.
1129 */
1130void molecule::Align(Vector *n)
1131{
1132 atom *ptr = start;
1133 double alpha, tmp;
1134 Vector z_axis;
1135 z_axis.x[0] = 0.;
1136 z_axis.x[1] = 0.;
1137 z_axis.x[2] = 1.;
1138
1139 // rotate on z-x plane
1140 cout << Verbose(0) << "Begin of Aligning all atoms." << endl;
1141 alpha = atan(-n->x[0]/n->x[2]);
1142 cout << Verbose(1) << "Z-X-angle: " << alpha << " ... ";
1143 while (ptr->next != end) {
1144 ptr = ptr->next;
1145 tmp = ptr->x.x[0];
1146 ptr->x.x[0] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];
1147 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2];
1148 for (int j=0;j<MDSteps;j++) {
1149 tmp = Trajectories[ptr].R.at(j).x[0];
1150 Trajectories[ptr].R.at(j).x[0] = cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2];
1151 Trajectories[ptr].R.at(j).x[2] = -sin(alpha) * tmp + cos(alpha) * Trajectories[ptr].R.at(j).x[2];
1152 }
1153 }
1154 // rotate n vector
1155 tmp = n->x[0];
1156 n->x[0] = cos(alpha) * tmp + sin(alpha) * n->x[2];
1157 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2];
1158 cout << Verbose(1) << "alignment vector after first rotation: ";
1159 n->Output((ofstream *)&cout);
1160 cout << endl;
1161
1162 // rotate on z-y plane
1163 ptr = start;
1164 alpha = atan(-n->x[1]/n->x[2]);
1165 cout << Verbose(1) << "Z-Y-angle: " << alpha << " ... ";
1166 while (ptr->next != end) {
1167 ptr = ptr->next;
1168 tmp = ptr->x.x[1];
1169 ptr->x.x[1] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];
1170 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2];
1171 for (int j=0;j<MDSteps;j++) {
1172 tmp = Trajectories[ptr].R.at(j).x[1];
1173 Trajectories[ptr].R.at(j).x[1] = cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2];
1174 Trajectories[ptr].R.at(j).x[2] = -sin(alpha) * tmp + cos(alpha) * Trajectories[ptr].R.at(j).x[2];
1175 }
1176 }
1177 // rotate n vector (for consistency check)
1178 tmp = n->x[1];
1179 n->x[1] = cos(alpha) * tmp + sin(alpha) * n->x[2];
1180 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2];
1181
1182 cout << Verbose(1) << "alignment vector after second rotation: ";
1183 n->Output((ofstream *)&cout);
1184 cout << Verbose(1) << endl;
1185 cout << Verbose(0) << "End of Aligning all atoms." << endl;
1186};
1187
1188/** Removes atom from molecule list.
1189 * \param *pointer atom to be removed
1190 * \return true - succeeded, false - atom not found in list
1191 */
1192bool molecule::RemoveAtom(atom *pointer)
1193{
1194 if (ElementsInMolecule[pointer->type->Z] != 0) // this would indicate an error
1195 ElementsInMolecule[pointer->type->Z]--; // decrease number of atom of this element
1196 else
1197 cerr << "ERROR: Atom " << pointer->Name << " is of element " << pointer->type->Z << " but the entry in the table of the molecule is 0!" << endl;
1198 if (ElementsInMolecule[pointer->type->Z] == 0) // was last atom of this element?
1199 ElementCount--;
1200 Trajectories.erase(pointer);
1201 return remove(pointer, start, end);
1202};
1203
1204/** Removes every atom from molecule list.
1205 * \return true - succeeded, false - atom not found in list
1206 */
1207bool molecule::CleanupMolecule()
1208{
1209 return (cleanup(start,end) && cleanup(first,last));
1210};
1211
1212/** Finds an atom specified by its continuous number.
1213 * \param Nr number of atom withim molecule
1214 * \return pointer to atom or NULL
1215 */
1216atom * molecule::FindAtom(int Nr) const{
1217 atom * walker = find(&Nr, start,end);
1218 if (walker != NULL) {
1219 //cout << Verbose(0) << "Found Atom Nr. " << walker->nr << endl;
1220 return walker;
1221 } else {
1222 cout << Verbose(0) << "Atom not found in list." << endl;
1223 return NULL;
1224 }
1225};
1226
1227/** Asks for atom number, and checks whether in list.
1228 * \param *text question before entering
1229 */
1230atom * molecule::AskAtom(string text)
1231{
1232 int No;
1233 atom *ion = NULL;
1234 do {
1235 //cout << Verbose(0) << "============Atom list==========================" << endl;
1236 //mol->Output((ofstream *)&cout);
1237 //cout << Verbose(0) << "===============================================" << endl;
1238 cout << Verbose(0) << text;
1239 cin >> No;
1240 ion = this->FindAtom(No);
1241 } while (ion == NULL);
1242 return ion;
1243};
1244
1245/** Checks if given coordinates are within cell volume.
1246 * \param *x array of coordinates
1247 * \return true - is within, false - out of cell
1248 */
1249bool molecule::CheckBounds(const Vector *x) const
1250{
1251 bool result = true;
1252 int j =-1;
1253 for (int i=0;i<NDIM;i++) {
1254 j += i+1;
1255 result = result && ((x->x[i] >= 0) && (x->x[i] < cell_size[j]));
1256 }
1257 //return result;
1258 return true; /// probably not gonna use the check no more
1259};
1260
1261/** Calculates sum over least square distance to line hidden in \a *x.
1262 * \param *x offset and direction vector
1263 * \param *params pointer to lsq_params structure
1264 * \return \f$ sum_i^N | y_i - (a + t_i b)|^2\f$
1265 */
1266double LeastSquareDistance (const gsl_vector * x, void * params)
1267{
1268 double res = 0, t;
1269 Vector a,b,c,d;
1270 struct lsq_params *par = (struct lsq_params *)params;
1271 atom *ptr = par->mol->start;
1272
1273 // initialize vectors
1274 a.x[0] = gsl_vector_get(x,0);
1275 a.x[1] = gsl_vector_get(x,1);
1276 a.x[2] = gsl_vector_get(x,2);
1277 b.x[0] = gsl_vector_get(x,3);
1278 b.x[1] = gsl_vector_get(x,4);
1279 b.x[2] = gsl_vector_get(x,5);
1280 // go through all atoms
1281 while (ptr != par->mol->end) {
1282 ptr = ptr->next;
1283 if (ptr->type == ((struct lsq_params *)params)->type) { // for specific type
1284 c.CopyVector(&ptr->x); // copy vector to temporary one
1285 c.SubtractVector(&a); // subtract offset vector
1286 t = c.ScalarProduct(&b); // get direction parameter
1287 d.CopyVector(&b); // and create vector
1288 d.Scale(&t);
1289 c.SubtractVector(&d); // ... yielding distance vector
1290 res += d.ScalarProduct((const Vector *)&d); // add squared distance
1291 }
1292 }
1293 return res;
1294};
1295
1296/** By minimizing the least square distance gains alignment vector.
1297 * \bug this is not yet working properly it seems
1298 */
1299void molecule::GetAlignvector(struct lsq_params * par) const
1300{
1301 int np = 6;
1302
1303 const gsl_multimin_fminimizer_type *T =
1304 gsl_multimin_fminimizer_nmsimplex;
1305 gsl_multimin_fminimizer *s = NULL;
1306 gsl_vector *ss;
1307 gsl_multimin_function minex_func;
1308
1309 size_t iter = 0, i;
1310 int status;
1311 double size;
1312
1313 /* Initial vertex size vector */
1314 ss = gsl_vector_alloc (np);
1315
1316 /* Set all step sizes to 1 */
1317 gsl_vector_set_all (ss, 1.0);
1318
1319 /* Starting point */
1320 par->x = gsl_vector_alloc (np);
1321 par->mol = this;
1322
1323 gsl_vector_set (par->x, 0, 0.0); // offset
1324 gsl_vector_set (par->x, 1, 0.0);
1325 gsl_vector_set (par->x, 2, 0.0);
1326 gsl_vector_set (par->x, 3, 0.0); // direction
1327 gsl_vector_set (par->x, 4, 0.0);
1328 gsl_vector_set (par->x, 5, 1.0);
1329
1330 /* Initialize method and iterate */
1331 minex_func.f = &LeastSquareDistance;
1332 minex_func.n = np;
1333 minex_func.params = (void *)par;
1334
1335 s = gsl_multimin_fminimizer_alloc (T, np);
1336 gsl_multimin_fminimizer_set (s, &minex_func, par->x, ss);
1337
1338 do
1339 {
1340 iter++;
1341 status = gsl_multimin_fminimizer_iterate(s);
1342
1343 if (status)
1344 break;
1345
1346 size = gsl_multimin_fminimizer_size (s);
1347 status = gsl_multimin_test_size (size, 1e-2);
1348
1349 if (status == GSL_SUCCESS)
1350 {
1351 printf ("converged to minimum at\n");
1352 }
1353
1354 printf ("%5d ", (int)iter);
1355 for (i = 0; i < (size_t)np; i++)
1356 {
1357 printf ("%10.3e ", gsl_vector_get (s->x, i));
1358 }
1359 printf ("f() = %7.3f size = %.3f\n", s->fval, size);
1360 }
1361 while (status == GSL_CONTINUE && iter < 100);
1362
1363 for (i=0;i<(size_t)np;i++)
1364 gsl_vector_set(par->x, i, gsl_vector_get(s->x, i));
1365 //gsl_vector_free(par->x);
1366 gsl_vector_free(ss);
1367 gsl_multimin_fminimizer_free (s);
1368};
1369
1370/** Prints molecule to *out.
1371 * \param *out output stream
1372 */
1373bool molecule::Output(ofstream *out)
1374{
1375 element *runner;
1376 atom *walker = NULL;
1377 int ElementNo, AtomNo;
1378 CountElements();
1379
1380 if (out == NULL) {
1381 return false;
1382 } else {
1383 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
1384 ElementNo = 0;
1385 runner = elemente->start;
1386 while (runner->next != elemente->end) { // go through every element
1387 runner = runner->next;
1388 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1389 ElementNo++;
1390 AtomNo = 0;
1391 walker = start;
1392 while (walker->next != end) { // go through every atom of this element
1393 walker = walker->next;
1394 if (walker->type == runner) { // if this atom fits to element
1395 AtomNo++;
1396 walker->Output(ElementNo, AtomNo, out); // removed due to trajectories
1397 }
1398 }
1399 }
1400 }
1401 return true;
1402 }
1403};
1404
1405/** Prints molecule with all atomic trajectory positions to *out.
1406 * \param *out output stream
1407 */
1408bool molecule::OutputTrajectories(ofstream *out)
1409{
1410 element *runner = NULL;
1411 atom *walker = NULL;
1412 int ElementNo, AtomNo;
1413 CountElements();
1414
1415 if (out == NULL) {
1416 return false;
1417 } else {
1418 for (int step = 0; step < MDSteps; step++) {
1419 if (step == 0) {
1420 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
1421 } else {
1422 *out << "# ====== MD step " << step << " =========" << endl;
1423 }
1424 ElementNo = 0;
1425 runner = elemente->start;
1426 while (runner->next != elemente->end) { // go through every element
1427 runner = runner->next;
1428 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1429 ElementNo++;
1430 AtomNo = 0;
1431 walker = start;
1432 while (walker->next != end) { // go through every atom of this element
1433 walker = walker->next;
1434 if (walker->type == runner) { // if this atom fits to element
1435 AtomNo++;
1436 *out << "Ion_Type" << ElementNo << "_" << AtomNo << "\t" << fixed << setprecision(9) << showpoint;
1437 *out << Trajectories[walker].R.at(step).x[0] << "\t" << Trajectories[walker].R.at(step).x[1] << "\t" << Trajectories[walker].R.at(step).x[2];
1438 *out << "\t" << walker->FixedIon;
1439 if (Trajectories[walker].U.at(step).Norm() > MYEPSILON)
1440 *out << "\t" << scientific << setprecision(6) << Trajectories[walker].U.at(step).x[0] << "\t" << Trajectories[walker].U.at(step).x[1] << "\t" << Trajectories[walker].U.at(step).x[2] << "\t";
1441 if (Trajectories[walker].F.at(step).Norm() > MYEPSILON)
1442 *out << "\t" << scientific << setprecision(6) << Trajectories[walker].F.at(step).x[0] << "\t" << Trajectories[walker].F.at(step).x[1] << "\t" << Trajectories[walker].F.at(step).x[2] << "\t";
1443 *out << "\t# Number in molecule " << walker->nr << endl;
1444 }
1445 }
1446 }
1447 }
1448 }
1449 return true;
1450 }
1451};
1452
1453/** Outputs contents of molecule::ListOfBondsPerAtom.
1454 * \param *out output stream
1455 */
1456void molecule::OutputListOfBonds(ofstream *out) const
1457{
1458 *out << Verbose(2) << endl << "From Contents of ListOfBondsPerAtom, all non-hydrogen atoms:" << endl;
1459 atom *Walker = start;
1460 while (Walker->next != end) {
1461 Walker = Walker->next;
1462#ifdef ADDHYDROGEN
1463 if (Walker->type->Z != 1) { // regard only non-hydrogen
1464#endif
1465 *out << Verbose(2) << "Atom " << Walker->Name << " has Bonds: "<<endl;
1466 for(int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
1467 *out << Verbose(3) << *(ListOfBondsPerAtom)[Walker->nr][j] << endl;
1468 }
1469#ifdef ADDHYDROGEN
1470 }
1471#endif
1472 }
1473 *out << endl;
1474};
1475
1476/** Output of element before the actual coordination list.
1477 * \param *out stream pointer
1478 */
1479bool molecule::Checkout(ofstream *out) const
1480{
1481 return elemente->Checkout(out, ElementsInMolecule);
1482};
1483
1484/** Prints molecule with all its trajectories to *out as xyz file.
1485 * \param *out output stream
1486 */
1487bool molecule::OutputTrajectoriesXYZ(ofstream *out)
1488{
1489 atom *walker = NULL;
1490 int No = 0;
1491 time_t now;
1492
1493 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
1494 walker = start;
1495 while (walker->next != end) { // go through every atom and count
1496 walker = walker->next;
1497 No++;
1498 }
1499 if (out != NULL) {
1500 for (int step=0;step<MDSteps;step++) {
1501 *out << No << "\n\tCreated by molecuilder, step " << step << ", on " << ctime(&now);
1502 walker = start;
1503 while (walker->next != end) { // go through every atom of this element
1504 walker = walker->next;
1505 *out << walker->type->symbol << "\t" << Trajectories[walker].R.at(step).x[0] << "\t" << Trajectories[walker].R.at(step).x[1] << "\t" << Trajectories[walker].R.at(step).x[2] << endl;
1506 }
1507 }
1508 return true;
1509 } else
1510 return false;
1511};
1512
1513/** Prints molecule to *out as xyz file.
1514* \param *out output stream
1515 */
1516bool molecule::OutputXYZ(ofstream *out) const
1517{
1518 atom *walker = NULL;
1519 int No = 0;
1520 time_t now;
1521
1522 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
1523 walker = start;
1524 while (walker->next != end) { // go through every atom and count
1525 walker = walker->next;
1526 No++;
1527 }
1528 if (out != NULL) {
1529 *out << No << "\n\tCreated by molecuilder on " << ctime(&now);
1530 walker = start;
1531 while (walker->next != end) { // go through every atom of this element
1532 walker = walker->next;
1533 walker->OutputXYZLine(out);
1534 }
1535 return true;
1536 } else
1537 return false;
1538};
1539
1540/** Brings molecule::AtomCount and atom::*Name up-to-date.
1541 * \param *out output stream for debugging
1542 */
1543void molecule::CountAtoms(ofstream *out)
1544{
1545 int i = 0;
1546 atom *Walker = start;
1547 while (Walker->next != end) {
1548 Walker = Walker->next;
1549 i++;
1550 }
1551 if ((AtomCount == 0) || (i != AtomCount)) {
1552 *out << Verbose(3) << "Mismatch in AtomCount " << AtomCount << " and recounted number " << i << ", renaming all." << endl;
1553 AtomCount = i;
1554
1555 // count NonHydrogen atoms and give each atom a unique name
1556 if (AtomCount != 0) {
1557 i=0;
1558 NoNonHydrogen = 0;
1559 Walker = start;
1560 while (Walker->next != end) {
1561 Walker = Walker->next;
1562 Walker->nr = i; // update number in molecule (for easier referencing in FragmentMolecule lateron)
1563 if (Walker->type->Z != 1) // count non-hydrogen atoms whilst at it
1564 NoNonHydrogen++;
1565 Free((void **)&Walker->Name, "molecule::CountAtoms: *walker->Name");
1566 Walker->Name = (char *) Malloc(sizeof(char)*6, "molecule::CountAtoms: *walker->Name");
1567 sprintf(Walker->Name, "%2s%02d", Walker->type->symbol, Walker->nr+1);
1568 *out << "Naming atom nr. " << Walker->nr << " " << Walker->Name << "." << endl;
1569 i++;
1570 }
1571 } else
1572 *out << Verbose(3) << "AtomCount is still " << AtomCount << ", thus counting nothing." << endl;
1573 }
1574};
1575
1576/** Brings molecule::ElementCount and molecule::ElementsInMolecule up-to-date.
1577 */
1578void molecule::CountElements()
1579{
1580 int i = 0;
1581 for(i=MAX_ELEMENTS;i--;)
1582 ElementsInMolecule[i] = 0;
1583 ElementCount = 0;
1584
1585 atom *walker = start;
1586 while (walker->next != end) {
1587 walker = walker->next;
1588 ElementsInMolecule[walker->type->Z]++;
1589 i++;
1590 }
1591 for(i=MAX_ELEMENTS;i--;)
1592 ElementCount += (ElementsInMolecule[i] != 0 ? 1 : 0);
1593};
1594
1595/** Counts all cyclic bonds and returns their number.
1596 * \note Hydrogen bonds can never by cyclic, thus no check for that
1597 * \param *out output stream for debugging
1598 * \return number opf cyclic bonds
1599 */
1600int molecule::CountCyclicBonds(ofstream *out)
1601{
1602 int No = 0;
1603 int *MinimumRingSize = NULL;
1604 MoleculeLeafClass *Subgraphs = NULL;
1605 class StackClass<bond *> *BackEdgeStack = NULL;
1606 bond *Binder = first;
1607 if ((Binder->next != last) && (Binder->next->Type == Undetermined)) {
1608 *out << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl;
1609 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack);
1610 while (Subgraphs->next != NULL) {
1611 Subgraphs = Subgraphs->next;
1612 delete(Subgraphs->previous);
1613 }
1614 delete(Subgraphs);
1615 delete[](MinimumRingSize);
1616 }
1617 while(Binder->next != last) {
1618 Binder = Binder->next;
1619 if (Binder->Cyclic)
1620 No++;
1621 }
1622 delete(BackEdgeStack);
1623 return No;
1624};
1625/** Returns Shading as a char string.
1626 * \param color the Shading
1627 * \return string of the flag
1628 */
1629string molecule::GetColor(enum Shading color)
1630{
1631 switch(color) {
1632 case white:
1633 return "white";
1634 break;
1635 case lightgray:
1636 return "lightgray";
1637 break;
1638 case darkgray:
1639 return "darkgray";
1640 break;
1641 case black:
1642 return "black";
1643 break;
1644 default:
1645 return "uncolored";
1646 break;
1647 };
1648};
1649
1650
1651/** Counts necessary number of valence electrons and returns number and SpinType.
1652 * \param configuration containing everything
1653 */
1654void molecule::CalculateOrbitals(class config &configuration)
1655{
1656 configuration.MaxPsiDouble = configuration.PsiMaxNoDown = configuration.PsiMaxNoUp = configuration.PsiType = 0;
1657 for(int i=MAX_ELEMENTS;i--;) {
1658 if (ElementsInMolecule[i] != 0) {
1659 //cout << "CalculateOrbitals: " << elemente->FindElement(i)->name << " has a valence of " << (int)elemente->FindElement(i)->Valence << " and there are " << ElementsInMolecule[i] << " of it." << endl;
1660 configuration.MaxPsiDouble += ElementsInMolecule[i]*((int)elemente->FindElement(i)->Valence);
1661 }
1662 }
1663 configuration.PsiMaxNoDown = configuration.MaxPsiDouble/2 + (configuration.MaxPsiDouble % 2);
1664 configuration.PsiMaxNoUp = configuration.MaxPsiDouble/2;
1665 configuration.MaxPsiDouble /= 2;
1666 configuration.PsiType = (configuration.PsiMaxNoDown == configuration.PsiMaxNoUp) ? 0 : 1;
1667 if ((configuration.PsiType == 1) && (configuration.ProcPEPsi < 2)) {
1668 configuration.ProcPEGamma /= 2;
1669 configuration.ProcPEPsi *= 2;
1670 } else {
1671 configuration.ProcPEGamma *= configuration.ProcPEPsi;
1672 configuration.ProcPEPsi = 1;
1673 }
1674 configuration.InitMaxMinStopStep = configuration.MaxMinStopStep = configuration.MaxPsiDouble;
1675};
1676
1677/** Creates an adjacency list of the molecule.
1678 * Generally, we use the CSD approach to bond recognition, that is the the distance
1679 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
1680 * a threshold t = 0.4 Angstroem.
1681 * To make it O(N log N) the function uses the linked-cell technique as follows:
1682 * The procedure is step-wise:
1683 * -# Remove every bond in list
1684 * -# Count the atoms in the molecule with CountAtoms()
1685 * -# partition cell into smaller linked cells of size \a bonddistance
1686 * -# put each atom into its corresponding cell
1687 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true
1688 * -# create the list of bonds via CreateListOfBondsPerAtom()
1689 * -# correct the bond degree iteratively (single->double->triple bond)
1690 * -# finally print the bond list to \a *out if desired
1691 * \param *out out stream for printing the matrix, NULL if no output
1692 * \param bonddistance length of linked cells (i.e. maximum minimal length checked)
1693 * \param IsAngstroem whether coordinate system is gauged to Angstroem or Bohr radii
1694 */
1695void molecule::CreateAdjacencyList(ofstream *out, double bonddistance, bool IsAngstroem)
1696{
1697 atom *Walker = NULL, *OtherWalker = NULL, *Candidate = NULL;
1698 int No, NoBonds, CandidateBondNo;
1699 int NumberCells, divisor[NDIM], n[NDIM], N[NDIM], index, Index, j;
1700 molecule **CellList;
1701 double distance, MinDistance, MaxDistance;
1702 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
1703 Vector x;
1704 int FalseBondDegree = 0;
1705
1706 BondDistance = bonddistance; // * ((IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem);
1707 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl;
1708 // remove every bond from the list
1709 if ((first->next != last) && (last->previous != first)) { // there are bonds present
1710 cleanup(first,last);
1711 }
1712
1713 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering)
1714 CountAtoms(out);
1715 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl;
1716
1717 if (AtomCount != 0) {
1718 // 1. find divisor for each axis, such that a sphere with radius of at least bonddistance can be placed into each cell
1719 j=-1;
1720 for (int i=0;i<NDIM;i++) {
1721 j += i+1;
1722 divisor[i] = (int)floor(cell_size[j]/bonddistance); // take smaller value such that size of linked cell is at least bonddistance
1723 //*out << Verbose(1) << "divisor[" << i << "] = " << divisor[i] << "." << endl;
1724 }
1725 // 2a. allocate memory for the cell list
1726 NumberCells = divisor[0]*divisor[1]*divisor[2];
1727 *out << Verbose(1) << "Allocating " << NumberCells << " cells." << endl;
1728 CellList = (molecule **) Malloc(sizeof(molecule *)*NumberCells, "molecule::CreateAdjacencyList - ** CellList");
1729 for (int i=NumberCells;i--;)
1730 CellList[i] = NULL;
1731
1732 // 2b. put all atoms into its corresponding list
1733 Walker = start;
1734 while(Walker->next != end) {
1735 Walker = Walker->next;
1736 //*out << Verbose(1) << "Current atom is " << *Walker << " with coordinates ";
1737 //Walker->x.Output(out);
1738 //*out << "." << endl;
1739 // compute the cell by the atom's coordinates
1740 j=-1;
1741 for (int i=0;i<NDIM;i++) {
1742 j += i+1;
1743 x.CopyVector(&(Walker->x));
1744 x.KeepPeriodic(out, matrix);
1745 n[i] = (int)floor(x.x[i]/cell_size[j]*(double)divisor[i]);
1746 }
1747 index = n[2] + (n[1] + n[0] * divisor[1]) * divisor[2];
1748 //*out << Verbose(1) << "Atom " << *Walker << " goes into cell number [" << n[0] << "," << n[1] << "," << n[2] << "] = " << index << "." << endl;
1749 // add copy atom to this cell
1750 if (CellList[index] == NULL) // allocate molecule if not done
1751 CellList[index] = new molecule(elemente);
1752 OtherWalker = CellList[index]->AddCopyAtom(Walker); // add a copy of walker to this atom, father will be walker for later reference
1753 //*out << Verbose(1) << "Copy Atom is " << *OtherWalker << "." << endl;
1754 }
1755 //for (int i=0;i<NumberCells;i++)
1756 //*out << Verbose(1) << "Cell number " << i << ": " << CellList[i] << "." << endl;
1757
1758 // 3a. go through every cell
1759 for (N[0]=divisor[0];N[0]--;)
1760 for (N[1]=divisor[1];N[1]--;)
1761 for (N[2]=divisor[2];N[2]--;) {
1762 Index = N[2] + (N[1] + N[0] * divisor[1]) * divisor[2];
1763 if (CellList[Index] != NULL) { // if there atoms in this cell
1764 //*out << Verbose(1) << "Current cell is " << Index << "." << endl;
1765 // 3b. for every atom therein
1766 Walker = CellList[Index]->start;
1767 while (Walker->next != CellList[Index]->end) { // go through every atom
1768 Walker = Walker->next;
1769 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl;
1770 // 3c. check for possible bond between each atom in this and every one in the 27 cells
1771 for (n[0]=-1;n[0]<=1;n[0]++)
1772 for (n[1]=-1;n[1]<=1;n[1]++)
1773 for (n[2]=-1;n[2]<=1;n[2]++) {
1774 // compute the index of this comparison cell and make it periodic
1775 index = ((N[2]+n[2]+divisor[2])%divisor[2]) + (((N[1]+n[1]+divisor[1])%divisor[1]) + ((N[0]+n[0]+divisor[0])%divisor[0]) * divisor[1]) * divisor[2];
1776 //*out << Verbose(1) << "Number of comparison cell is " << index << "." << endl;
1777 if (CellList[index] != NULL) { // if there are any atoms in this cell
1778 OtherWalker = CellList[index]->start;
1779 while(OtherWalker->next != CellList[index]->end) { // go through every atom in this cell
1780 OtherWalker = OtherWalker->next;
1781 //*out << Verbose(0) << "Current comparison atom is " << *OtherWalker << "." << endl;
1782 /// \todo periodic check is missing here!
1783 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl;
1784 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius;
1785 MinDistance *= (IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem;
1786 MaxDistance = MinDistance + BONDTHRESHOLD;
1787 MinDistance -= BONDTHRESHOLD;
1788 distance = OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size);
1789 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance*MaxDistance) && (distance >= MinDistance*MinDistance)) { // create bond if distance is smaller
1790 //*out << Verbose(0) << "Adding Bond between " << *Walker << " and " << *OtherWalker << "." << endl;
1791 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount
1792 BondCount++;
1793 } else {
1794 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl;
1795 }
1796 }
1797 }
1798 }
1799 }
1800 }
1801 }
1802 // 4. free the cell again
1803 for (int i=NumberCells;i--;)
1804 if (CellList[i] != NULL) {
1805 delete(CellList[i]);
1806 }
1807 Free((void **)&CellList, "molecule::CreateAdjacencyList - ** CellList");
1808
1809 // create the adjacency list per atom
1810 CreateListOfBondsPerAtom(out);
1811
1812 // correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees,
1813 // iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene
1814 // preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of
1815 // double bonds as was expected.
1816 if (BondCount != 0) {
1817 NoCyclicBonds = 0;
1818 *out << Verbose(1) << "Correcting Bond degree of each bond ... ";
1819 do {
1820 No = 0; // No acts as breakup flag (if 1 we still continue)
1821 Walker = start;
1822 while (Walker->next != end) { // go through every atom
1823 Walker = Walker->next;
1824 // count valence of first partner
1825 NoBonds = 0;
1826 for(j=0;j<NumberOfBondsPerAtom[Walker->nr];j++)
1827 NoBonds += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
1828 *out << Verbose(3) << "Walker " << *Walker << ": " << (int)Walker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
1829 if ((int)(Walker->type->NoValenceOrbitals) > NoBonds) { // we have a mismatch, check all bonding partners for mismatch
1830 Candidate = NULL;
1831 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through each of its bond partners
1832 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
1833 // count valence of second partner
1834 NoBonds = 0;
1835 for(j=0;j<NumberOfBondsPerAtom[OtherWalker->nr];j++)
1836 NoBonds += ListOfBondsPerAtom[OtherWalker->nr][j]->BondDegree;
1837 *out << Verbose(3) << "OtherWalker " << *OtherWalker << ": " << (int)OtherWalker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
1838 if ((int)(OtherWalker->type->NoValenceOrbitals) > NoBonds) { // check if possible candidate
1839 if ((Candidate == NULL) || (NumberOfBondsPerAtom[Candidate->nr] > NumberOfBondsPerAtom[OtherWalker->nr])) { // pick the one with fewer number of bonds first
1840 Candidate = OtherWalker;
1841 CandidateBondNo = i;
1842 *out << Verbose(3) << "New candidate is " << *Candidate << "." << endl;
1843 }
1844 }
1845 }
1846 if (Candidate != NULL) {
1847 ListOfBondsPerAtom[Walker->nr][CandidateBondNo]->BondDegree++;
1848 *out << Verbose(2) << "Increased bond degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl;
1849 } else
1850 *out << Verbose(2) << "Could not find correct degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl;
1851 FalseBondDegree++;
1852 }
1853 }
1854 } while (No);
1855 *out << " done." << endl;
1856 } else
1857 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl;
1858 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << bonddistance << ", " << FalseBondDegree << " bonds could not be corrected." << endl;
1859
1860 // output bonds for debugging (if bond chain list was correctly installed)
1861 *out << Verbose(1) << endl << "From contents of bond chain list:";
1862 bond *Binder = first;
1863 while(Binder->next != last) {
1864 Binder = Binder->next;
1865 *out << *Binder << "\t" << endl;
1866 }
1867 *out << endl;
1868 } else
1869 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl;
1870 *out << Verbose(0) << "End of CreateAdjacencyList." << endl;
1871 Free((void **)&matrix, "molecule::CreateAdjacencyList: *matrix");
1872};
1873
1874/** Performs a Depth-First search on this molecule.
1875 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
1876 * articulations points, ...
1877 * We use the algorithm from [Even, Graph Algorithms, p.62].
1878 * \param *out output stream for debugging
1879 * \param *&BackEdgeStack NULL pointer to StackClass with all the found back edges, allocated and filled on return
1880 * \return list of each disconnected subgraph as an individual molecule class structure
1881 */
1882MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, class StackClass<bond *> *&BackEdgeStack)
1883{
1884 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
1885 BackEdgeStack = new StackClass<bond *> (BondCount);
1886 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
1887 MoleculeLeafClass *LeafWalker = SubGraphs;
1888 int CurrentGraphNr = 0, OldGraphNr;
1889 int ComponentNumber = 0;
1890 atom *Walker = NULL, *OtherAtom = NULL, *Root = start->next;
1891 bond *Binder = NULL;
1892 bool BackStepping = false;
1893
1894 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl;
1895
1896 ResetAllBondsToUnused();
1897 ResetAllAtomNumbers();
1898 InitComponentNumbers();
1899 BackEdgeStack->ClearStack();
1900 while (Root != end) { // if there any atoms at all
1901 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all
1902 AtomStack->ClearStack();
1903
1904 // put into new subgraph molecule and add this to list of subgraphs
1905 LeafWalker = new MoleculeLeafClass(LeafWalker);
1906 LeafWalker->Leaf = new molecule(elemente);
1907 LeafWalker->Leaf->AddCopyAtom(Root);
1908
1909 OldGraphNr = CurrentGraphNr;
1910 Walker = Root;
1911 do { // (10)
1912 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
1913 if (!BackStepping) { // if we don't just return from (8)
1914 Walker->GraphNr = CurrentGraphNr;
1915 Walker->LowpointNr = CurrentGraphNr;
1916 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl;
1917 AtomStack->Push(Walker);
1918 CurrentGraphNr++;
1919 }
1920 do { // (3) if Walker has no unused egdes, go to (5)
1921 BackStepping = false; // reset backstepping flag for (8)
1922 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
1923 Binder = FindNextUnused(Walker);
1924 if (Binder == NULL)
1925 break;
1926 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl;
1927 // (4) Mark Binder used, ...
1928 Binder->MarkUsed(black);
1929 OtherAtom = Binder->GetOtherAtom(Walker);
1930 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl;
1931 if (OtherAtom->GraphNr != -1) {
1932 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
1933 Binder->Type = BackEdge;
1934 BackEdgeStack->Push(Binder);
1935 Walker->LowpointNr = ( Walker->LowpointNr < OtherAtom->GraphNr ) ? Walker->LowpointNr : OtherAtom->GraphNr;
1936 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl;
1937 } else {
1938 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
1939 Binder->Type = TreeEdge;
1940 OtherAtom->Ancestor = Walker;
1941 Walker = OtherAtom;
1942 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl;
1943 break;
1944 }
1945 Binder = NULL;
1946 } while (1); // (3)
1947 if (Binder == NULL) {
1948 *out << Verbose(2) << "No more Unused Bonds." << endl;
1949 break;
1950 } else
1951 Binder = NULL;
1952 } while (1); // (2)
1953
1954 // if we came from backstepping, yet there were no more unused bonds, we end up here with no Ancestor, because Walker is Root! Then we are finished!
1955 if ((Walker == Root) && (Binder == NULL))
1956 break;
1957
1958 // (5) if Ancestor of Walker is ...
1959 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl;
1960 if (Walker->Ancestor->GraphNr != Root->GraphNr) {
1961 // (6) (Ancestor of Walker is not Root)
1962 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
1963 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
1964 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
1965 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl;
1966 } else {
1967 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
1968 Walker->Ancestor->SeparationVertex = true;
1969 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl;
1970 SetNextComponentNumber(Walker->Ancestor, ComponentNumber);
1971 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << ComponentNumber << "." << endl;
1972 SetNextComponentNumber(Walker, ComponentNumber);
1973 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1974 do {
1975 OtherAtom = AtomStack->PopLast();
1976 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
1977 SetNextComponentNumber(OtherAtom, ComponentNumber);
1978 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1979 } while (OtherAtom != Walker);
1980 ComponentNumber++;
1981 }
1982 // (8) Walker becomes its Ancestor, go to (3)
1983 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl;
1984 Walker = Walker->Ancestor;
1985 BackStepping = true;
1986 }
1987 if (!BackStepping) { // coming from (8) want to go to (3)
1988 // (9) remove all from stack till Walker (including), these and Root form a component
1989 AtomStack->Output(out);
1990 SetNextComponentNumber(Root, ComponentNumber);
1991 *out << Verbose(3) << "(9) Root[" << Root->Name << "]'s Component is " << ComponentNumber << "." << endl;
1992 SetNextComponentNumber(Walker, ComponentNumber);
1993 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << ComponentNumber << "." << endl;
1994 do {
1995 OtherAtom = AtomStack->PopLast();
1996 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
1997 SetNextComponentNumber(OtherAtom, ComponentNumber);
1998 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1999 } while (OtherAtom != Walker);
2000 ComponentNumber++;
2001
2002 // (11) Root is separation vertex, set Walker to Root and go to (4)
2003 Walker = Root;
2004 Binder = FindNextUnused(Walker);
2005 *out << Verbose(1) << "(10) Walker is Root[" << Root->Name << "], next Unused Bond is " << Binder << "." << endl;
2006 if (Binder != NULL) { // Root is separation vertex
2007 *out << Verbose(1) << "(11) Root is a separation vertex." << endl;
2008 Walker->SeparationVertex = true;
2009 }
2010 }
2011 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
2012
2013 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
2014 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << CurrentGraphNr << "." << endl;
2015 LeafWalker->Leaf->Output(out);
2016 *out << endl;
2017
2018 // step on to next root
2019 while ((Root != end) && (Root->GraphNr != -1)) {
2020 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl;
2021 if (Root->GraphNr != -1) // if already discovered, step on
2022 Root = Root->next;
2023 }
2024 }
2025 // set cyclic bond criterium on "same LP" basis
2026 Binder = first;
2027 while(Binder->next != last) {
2028 Binder = Binder->next;
2029 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ??
2030 Binder->Cyclic = true;
2031 NoCyclicBonds++;
2032 }
2033 }
2034
2035
2036 *out << Verbose(1) << "Final graph info for each atom is:" << endl;
2037 Walker = start;
2038 while (Walker->next != end) {
2039 Walker = Walker->next;
2040 *out << Verbose(2) << "Atom " << Walker->Name << " is " << ((Walker->SeparationVertex) ? "a" : "not a") << " separation vertex, components are ";
2041 OutputComponentNumber(out, Walker);
2042 *out << " with Lowpoint " << Walker->LowpointNr << " and Graph Nr. " << Walker->GraphNr << "." << endl;
2043 }
2044
2045 *out << Verbose(1) << "Final graph info for each bond is:" << endl;
2046 Binder = first;
2047 while(Binder->next != last) {
2048 Binder = Binder->next;
2049 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
2050 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
2051 OutputComponentNumber(out, Binder->leftatom);
2052 *out << " === ";
2053 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
2054 OutputComponentNumber(out, Binder->rightatom);
2055 *out << ">." << endl;
2056 if (Binder->Cyclic) // cyclic ??
2057 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl;
2058 }
2059
2060 // free all and exit
2061 delete(AtomStack);
2062 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl;
2063 return SubGraphs;
2064};
2065
2066/** Analyses the cycles found and returns minimum of all cycle lengths.
2067 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
2068 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
2069 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
2070 * as cyclic and print out the cycles.
2071 * \param *out output stream for debugging
2072 * \param *BackEdgeStack stack with all back edges found during DFS scan. Beware: This stack contains the bonds from the total molecule, not from the subgraph!
2073 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
2074 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
2075 */
2076void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize)
2077{
2078 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList");
2079 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList");
2080 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CyclicStructureAnalysis: *ColorList");
2081 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring
2082 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop)
2083 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL;
2084 bond *Binder = NULL, *BackEdge = NULL;
2085 int RingSize, NumCycles, MinRingSize = -1;
2086
2087 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
2088 for (int i=AtomCount;i--;) {
2089 PredecessorList[i] = NULL;
2090 ShortestPathList[i] = -1;
2091 ColorList[i] = white;
2092 }
2093
2094 *out << Verbose(1) << "Back edge list - ";
2095 BackEdgeStack->Output(out);
2096
2097 *out << Verbose(1) << "Analysing cycles ... " << endl;
2098 NumCycles = 0;
2099 while (!BackEdgeStack->IsEmpty()) {
2100 BackEdge = BackEdgeStack->PopFirst();
2101 // this is the target
2102 Root = BackEdge->leftatom;
2103 // this is the source point
2104 Walker = BackEdge->rightatom;
2105 ShortestPathList[Walker->nr] = 0;
2106 BFSStack->ClearStack(); // start with empty BFS stack
2107 BFSStack->Push(Walker);
2108 TouchedStack->Push(Walker);
2109 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
2110 OtherAtom = NULL;
2111 do { // look for Root
2112 Walker = BFSStack->PopFirst();
2113 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
2114 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2115 Binder = ListOfBondsPerAtom[Walker->nr][i];
2116 if (Binder != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
2117 OtherAtom = Binder->GetOtherAtom(Walker);
2118#ifdef ADDHYDROGEN
2119 if (OtherAtom->type->Z != 1) {
2120#endif
2121 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2122 if (ColorList[OtherAtom->nr] == white) {
2123 TouchedStack->Push(OtherAtom);
2124 ColorList[OtherAtom->nr] = lightgray;
2125 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2126 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2127 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
2128 //if (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
2129 *out << Verbose(3) << "Putting OtherAtom into queue." << endl;
2130 BFSStack->Push(OtherAtom);
2131 //}
2132 } else {
2133 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
2134 }
2135 if (OtherAtom == Root)
2136 break;
2137#ifdef ADDHYDROGEN
2138 } else {
2139 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl;
2140 ColorList[OtherAtom->nr] = black;
2141 }
2142#endif
2143 } else {
2144 *out << Verbose(2) << "Bond " << *Binder << " not Visiting, is the back edge." << endl;
2145 }
2146 }
2147 ColorList[Walker->nr] = black;
2148 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2149 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
2150 // step through predecessor list
2151 while (OtherAtom != BackEdge->rightatom) {
2152 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
2153 break;
2154 else
2155 OtherAtom = PredecessorList[OtherAtom->nr];
2156 }
2157 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
2158 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;\
2159 do {
2160 OtherAtom = TouchedStack->PopLast();
2161 if (PredecessorList[OtherAtom->nr] == Walker) {
2162 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl;
2163 PredecessorList[OtherAtom->nr] = NULL;
2164 ShortestPathList[OtherAtom->nr] = -1;
2165 ColorList[OtherAtom->nr] = white;
2166 BFSStack->RemoveItem(OtherAtom);
2167 }
2168 } while ((!TouchedStack->IsEmpty()) && (PredecessorList[OtherAtom->nr] == NULL));
2169 TouchedStack->Push(OtherAtom); // last was wrongly popped
2170 OtherAtom = BackEdge->rightatom; // set to not Root
2171 } else
2172 OtherAtom = Root;
2173 }
2174 } while ((!BFSStack->IsEmpty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr])));
2175
2176 if (OtherAtom == Root) {
2177 // now climb back the predecessor list and thus find the cycle members
2178 NumCycles++;
2179 RingSize = 1;
2180 Root->GetTrueFather()->IsCyclic = true;
2181 *out << Verbose(1) << "Found ring contains: ";
2182 Walker = Root;
2183 while (Walker != BackEdge->rightatom) {
2184 *out << Walker->Name << " <-> ";
2185 Walker = PredecessorList[Walker->nr];
2186 Walker->GetTrueFather()->IsCyclic = true;
2187 RingSize++;
2188 }
2189 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl;
2190 // walk through all and set MinimumRingSize
2191 Walker = Root;
2192 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
2193 while (Walker != BackEdge->rightatom) {
2194 Walker = PredecessorList[Walker->nr];
2195 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr])
2196 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
2197 }
2198 if ((RingSize < MinRingSize) || (MinRingSize == -1))
2199 MinRingSize = RingSize;
2200 } else {
2201 *out << Verbose(1) << "No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl;
2202 }
2203
2204 // now clean the lists
2205 while (!TouchedStack->IsEmpty()){
2206 Walker = TouchedStack->PopFirst();
2207 PredecessorList[Walker->nr] = NULL;
2208 ShortestPathList[Walker->nr] = -1;
2209 ColorList[Walker->nr] = white;
2210 }
2211 }
2212 if (MinRingSize != -1) {
2213 // go over all atoms
2214 Root = start;
2215 while(Root->next != end) {
2216 Root = Root->next;
2217
2218 if (MinimumRingSize[Root->GetTrueFather()->nr] == AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is
2219 Walker = Root;
2220 ShortestPathList[Walker->nr] = 0;
2221 BFSStack->ClearStack(); // start with empty BFS stack
2222 BFSStack->Push(Walker);
2223 TouchedStack->Push(Walker);
2224 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
2225 OtherAtom = Walker;
2226 while (OtherAtom != NULL) { // look for Root
2227 Walker = BFSStack->PopFirst();
2228 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
2229 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2230 Binder = ListOfBondsPerAtom[Walker->nr][i];
2231 if ((Binder != BackEdge) || (NumberOfBondsPerAtom[Walker->nr] == 1)) { // only walk along DFS spanning tree (otherwise we always find SP of 1 being backedge Binder), but terminal hydrogens may be connected via backedge, hence extra check
2232 OtherAtom = Binder->GetOtherAtom(Walker);
2233 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2234 if (ColorList[OtherAtom->nr] == white) {
2235 TouchedStack->Push(OtherAtom);
2236 ColorList[OtherAtom->nr] = lightgray;
2237 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2238 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2239 //*out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
2240 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
2241 MinimumRingSize[Root->GetTrueFather()->nr] = ShortestPathList[OtherAtom->nr]+MinimumRingSize[OtherAtom->GetTrueFather()->nr];
2242 OtherAtom = NULL; //break;
2243 break;
2244 } else
2245 BFSStack->Push(OtherAtom);
2246 } else {
2247 //*out << Verbose(3) << "Not Adding, has already been visited." << endl;
2248 }
2249 } else {
2250 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl;
2251 }
2252 }
2253 ColorList[Walker->nr] = black;
2254 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2255 }
2256
2257 // now clean the lists
2258 while (!TouchedStack->IsEmpty()){
2259 Walker = TouchedStack->PopFirst();
2260 PredecessorList[Walker->nr] = NULL;
2261 ShortestPathList[Walker->nr] = -1;
2262 ColorList[Walker->nr] = white;
2263 }
2264 }
2265 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl;
2266 }
2267 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl;
2268 } else
2269 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
2270
2271 Free((void **)&PredecessorList, "molecule::CyclicStructureAnalysis: **PredecessorList");
2272 Free((void **)&ShortestPathList, "molecule::CyclicStructureAnalysis: **ShortestPathList");
2273 Free((void **)&ColorList, "molecule::CyclicStructureAnalysis: **ColorList");
2274 delete(BFSStack);
2275};
2276
2277/** Sets the next component number.
2278 * This is O(N) as the number of bonds per atom is bound.
2279 * \param *vertex atom whose next atom::*ComponentNr is to be set
2280 * \param nr number to use
2281 */
2282void molecule::SetNextComponentNumber(atom *vertex, int nr)
2283{
2284 int i=0;
2285 if (vertex != NULL) {
2286 for(;i<NumberOfBondsPerAtom[vertex->nr];i++) {
2287 if (vertex->ComponentNr[i] == -1) { // check if not yet used
2288 vertex->ComponentNr[i] = nr;
2289 break;
2290 }
2291 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
2292 break; // breaking here will not cause error!
2293 }
2294 if (i == NumberOfBondsPerAtom[vertex->nr])
2295 cerr << "Error: All Component entries are already occupied!" << endl;
2296 } else
2297 cerr << "Error: Given vertex is NULL!" << endl;
2298};
2299
2300/** Output a list of flags, stating whether the bond was visited or not.
2301 * \param *out output stream for debugging
2302 */
2303void molecule::OutputComponentNumber(ofstream *out, atom *vertex)
2304{
2305 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
2306 *out << vertex->ComponentNr[i] << " ";
2307};
2308
2309/** Allocates memory for all atom::*ComponentNr in this molecule and sets each entry to -1.
2310 */
2311void molecule::InitComponentNumbers()
2312{
2313 atom *Walker = start;
2314 while(Walker->next != end) {
2315 Walker = Walker->next;
2316 if (Walker->ComponentNr != NULL)
2317 Free((void **)&Walker->ComponentNr, "molecule::InitComponentNumbers: **Walker->ComponentNr");
2318 Walker->ComponentNr = (int *) Malloc(sizeof(int)*NumberOfBondsPerAtom[Walker->nr], "molecule::InitComponentNumbers: *Walker->ComponentNr");
2319 for (int i=NumberOfBondsPerAtom[Walker->nr];i--;)
2320 Walker->ComponentNr[i] = -1;
2321 }
2322};
2323
2324/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
2325 * \param *vertex atom to regard
2326 * \return bond class or NULL
2327 */
2328bond * molecule::FindNextUnused(atom *vertex)
2329{
2330 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
2331 if (ListOfBondsPerAtom[vertex->nr][i]->IsUsed() == white)
2332 return(ListOfBondsPerAtom[vertex->nr][i]);
2333 return NULL;
2334};
2335
2336/** Resets bond::Used flag of all bonds in this molecule.
2337 * \return true - success, false - -failure
2338 */
2339void molecule::ResetAllBondsToUnused()
2340{
2341 bond *Binder = first;
2342 while (Binder->next != last) {
2343 Binder = Binder->next;
2344 Binder->ResetUsed();
2345 }
2346};
2347
2348/** Resets atom::nr to -1 of all atoms in this molecule.
2349 */
2350void molecule::ResetAllAtomNumbers()
2351{
2352 atom *Walker = start;
2353 while (Walker->next != end) {
2354 Walker = Walker->next;
2355 Walker->GraphNr = -1;
2356 }
2357};
2358
2359/** Output a list of flags, stating whether the bond was visited or not.
2360 * \param *out output stream for debugging
2361 * \param *list
2362 */
2363void OutputAlreadyVisited(ofstream *out, int *list)
2364{
2365 *out << Verbose(4) << "Already Visited Bonds:\t";
2366 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " ";
2367 *out << endl;
2368};
2369
2370/** Estimates by educated guessing (using upper limit) the expected number of fragments.
2371 * The upper limit is
2372 * \f[
2373 * n = N \cdot C^k
2374 * \f]
2375 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
2376 * \param *out output stream for debugging
2377 * \param order bond order k
2378 * \return number n of fragments
2379 */
2380int molecule::GuesstimateFragmentCount(ofstream *out, int order)
2381{
2382 int c = 0;
2383 int FragmentCount;
2384 // get maximum bond degree
2385 atom *Walker = start;
2386 while (Walker->next != end) {
2387 Walker = Walker->next;
2388 c = (NumberOfBondsPerAtom[Walker->nr] > c) ? NumberOfBondsPerAtom[Walker->nr] : c;
2389 }
2390 FragmentCount = NoNonHydrogen*(1 << (c*order));
2391 *out << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl;
2392 return FragmentCount;
2393};
2394
2395/** Scans a single line for number and puts them into \a KeySet.
2396 * \param *out output stream for debugging
2397 * \param *buffer buffer to scan
2398 * \param &CurrentSet filled KeySet on return
2399 * \return true - at least one valid atom id parsed, false - CurrentSet is empty
2400 */
2401bool molecule::ScanBufferIntoKeySet(ofstream *out, char *buffer, KeySet &CurrentSet)
2402{
2403 stringstream line;
2404 int AtomNr;
2405 int status = 0;
2406
2407 line.str(buffer);
2408 while (!line.eof()) {
2409 line >> AtomNr;
2410 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
2411 CurrentSet.insert(AtomNr); // insert at end, hence in same order as in file!
2412 status++;
2413 } // else it's "-1" or else and thus must not be added
2414 }
2415 *out << Verbose(1) << "The scanned KeySet is ";
2416 for(KeySet::iterator runner = CurrentSet.begin(); runner != CurrentSet.end(); runner++) {
2417 *out << (*runner) << "\t";
2418 }
2419 *out << endl;
2420 return (status != 0);
2421};
2422
2423/** Parses the KeySet file and fills \a *FragmentList from the known molecule structure.
2424 * Does two-pass scanning:
2425 * -# Scans the keyset file and initialises a temporary graph
2426 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
2427 * Finally, the temporary graph is inserted into the given \a FragmentList for return.
2428 * \param *out output stream for debugging
2429 * \param *path path to file
2430 * \param *FragmentList empty, filled on return
2431 * \return true - parsing successfully, false - failure on parsing (FragmentList will be NULL)
2432 */
2433bool molecule::ParseKeySetFile(ofstream *out, char *path, Graph *&FragmentList)
2434{
2435 bool status = true;
2436 ifstream InputFile;
2437 stringstream line;
2438 GraphTestPair testGraphInsert;
2439 int NumberOfFragments = 0;
2440 double TEFactor;
2441 char *filename = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - filename");
2442
2443 if (FragmentList == NULL) { // check list pointer
2444 FragmentList = new Graph;
2445 }
2446
2447 // 1st pass: open file and read
2448 *out << Verbose(1) << "Parsing the KeySet file ... " << endl;
2449 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, KEYSETFILE);
2450 InputFile.open(filename);
2451 if (InputFile != NULL) {
2452 // each line represents a new fragment
2453 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - *buffer");
2454 // 1. parse keysets and insert into temp. graph
2455 while (!InputFile.eof()) {
2456 InputFile.getline(buffer, MAXSTRINGSIZE);
2457 KeySet CurrentSet;
2458 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(out, buffer, CurrentSet))) { // if at least one valid atom was added, write config
2459 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1))); // store fragment number and current factor
2460 if (!testGraphInsert.second) {
2461 cerr << "KeySet file must be corrupt as there are two equal key sets therein!" << endl;
2462 }
2463 //FragmentList->ListOfMolecules[NumberOfFragments++] = StoreFragmentFromKeySet(out, CurrentSet, IsAngstroem);
2464 }
2465 }
2466 // 2. Free and done
2467 InputFile.close();
2468 InputFile.clear();
2469 Free((void **)&buffer, "molecule::ParseKeySetFile - *buffer");
2470 *out << Verbose(1) << "done." << endl;
2471 } else {
2472 *out << Verbose(1) << "File " << filename << " not found." << endl;
2473 status = false;
2474 }
2475
2476 // 2nd pass: open TEFactors file and read
2477 *out << Verbose(1) << "Parsing the TEFactors file ... " << endl;
2478 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, TEFACTORSFILE);
2479 InputFile.open(filename);
2480 if (InputFile != NULL) {
2481 // 3. add found TEFactors to each keyset
2482 NumberOfFragments = 0;
2483 for(Graph::iterator runner = FragmentList->begin();runner != FragmentList->end(); runner++) {
2484 if (!InputFile.eof()) {
2485 InputFile >> TEFactor;
2486 (*runner).second.second = TEFactor;
2487 *out << Verbose(2) << "Setting " << ++NumberOfFragments << " fragment's TEFactor to " << (*runner).second.second << "." << endl;
2488 } else {
2489 status = false;
2490 break;
2491 }
2492 }
2493 // 4. Free and done
2494 InputFile.close();
2495 *out << Verbose(1) << "done." << endl;
2496 } else {
2497 *out << Verbose(1) << "File " << filename << " not found." << endl;
2498 status = false;
2499 }
2500
2501 // free memory
2502 Free((void **)&filename, "molecule::ParseKeySetFile - filename");
2503
2504 return status;
2505};
2506
2507/** Stores keysets and TEFactors to file.
2508 * \param *out output stream for debugging
2509 * \param KeySetList Graph with Keysets and factors
2510 * \param *path path to file
2511 * \return true - file written successfully, false - writing failed
2512 */
2513bool molecule::StoreKeySetFile(ofstream *out, Graph &KeySetList, char *path)
2514{
2515 ofstream output;
2516 bool status = true;
2517 string line;
2518
2519 // open KeySet file
2520 line = path;
2521 line.append("/");
2522 line += FRAGMENTPREFIX;
2523 line += KEYSETFILE;
2524 output.open(line.c_str(), ios::out);
2525 *out << Verbose(1) << "Saving key sets of the total graph ... ";
2526 if(output != NULL) {
2527 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) {
2528 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
2529 if (sprinter != (*runner).first.begin())
2530 output << "\t";
2531 output << *sprinter;
2532 }
2533 output << endl;
2534 }
2535 *out << "done." << endl;
2536 } else {
2537 cerr << "Unable to open " << line << " for writing keysets!" << endl;
2538 status = false;
2539 }
2540 output.close();
2541 output.clear();
2542
2543 // open TEFactors file
2544 line = path;
2545 line.append("/");
2546 line += FRAGMENTPREFIX;
2547 line += TEFACTORSFILE;
2548 output.open(line.c_str(), ios::out);
2549 *out << Verbose(1) << "Saving TEFactors of the total graph ... ";
2550 if(output != NULL) {
2551 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++)
2552 output << (*runner).second.second << endl;
2553 *out << Verbose(1) << "done." << endl;
2554 } else {
2555 *out << Verbose(1) << "failed to open " << line << "." << endl;
2556 status = false;
2557 }
2558 output.close();
2559
2560 return status;
2561};
2562
2563/** Storing the bond structure of a molecule to file.
2564 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
2565 * \param *out output stream for debugging
2566 * \param *path path to file
2567 * \return true - file written successfully, false - writing failed
2568 */
2569bool molecule::StoreAdjacencyToFile(ofstream *out, char *path)
2570{
2571 ofstream AdjacencyFile;
2572 atom *Walker = NULL;
2573 stringstream line;
2574 bool status = true;
2575
2576 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
2577 AdjacencyFile.open(line.str().c_str(), ios::out);
2578 *out << Verbose(1) << "Saving adjacency list ... ";
2579 if (AdjacencyFile != NULL) {
2580 Walker = start;
2581 while(Walker->next != end) {
2582 Walker = Walker->next;
2583 AdjacencyFile << Walker->nr << "\t";
2584 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
2585 AdjacencyFile << ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker)->nr << "\t";
2586 AdjacencyFile << endl;
2587 }
2588 AdjacencyFile.close();
2589 *out << Verbose(1) << "done." << endl;
2590 } else {
2591 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
2592 status = false;
2593 }
2594
2595 return status;
2596};
2597
2598/** Checks contents of adjacency file against bond structure in structure molecule.
2599 * \param *out output stream for debugging
2600 * \param *path path to file
2601 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
2602 * \return true - structure is equal, false - not equivalence
2603 */
2604bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms)
2605{
2606 ifstream File;
2607 stringstream filename;
2608 bool status = true;
2609 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
2610
2611 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
2612 File.open(filename.str().c_str(), ios::out);
2613 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... ";
2614 if (File != NULL) {
2615 // allocate storage structure
2616 int NonMatchNumber = 0; // will number of atoms with differing bond structure
2617 int *CurrentBonds = (int *) Malloc(sizeof(int)*8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
2618 int CurrentBondsOfAtom;
2619
2620 // Parse the file line by line and count the bonds
2621 while (!File.eof()) {
2622 File.getline(buffer, MAXSTRINGSIZE);
2623 stringstream line;
2624 line.str(buffer);
2625 int AtomNr = -1;
2626 line >> AtomNr;
2627 CurrentBondsOfAtom = -1; // we count one too far due to line end
2628 // parse into structure
2629 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
2630 while (!line.eof())
2631 line >> CurrentBonds[ ++CurrentBondsOfAtom ];
2632 // compare against present bonds
2633 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
2634 if (CurrentBondsOfAtom == NumberOfBondsPerAtom[AtomNr]) {
2635 for(int i=0;i<NumberOfBondsPerAtom[AtomNr];i++) {
2636 int id = ListOfBondsPerAtom[AtomNr][i]->GetOtherAtom(ListOfAtoms[AtomNr])->nr;
2637 int j = 0;
2638 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds
2639 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms
2640 ListOfAtoms[AtomNr] = NULL;
2641 NonMatchNumber++;
2642 status = false;
2643 //out << "[" << id << "]\t";
2644 } else {
2645 //out << id << "\t";
2646 }
2647 }
2648 //out << endl;
2649 } else {
2650 *out << "Number of bonds for Atom " << *ListOfAtoms[AtomNr] << " does not match, parsed " << CurrentBondsOfAtom << " against " << NumberOfBondsPerAtom[AtomNr] << "." << endl;
2651 status = false;
2652 }
2653 }
2654 }
2655 File.close();
2656 File.clear();
2657 if (status) { // if equal we parse the KeySetFile
2658 *out << Verbose(1) << "done: Equal." << endl;
2659 status = true;
2660 } else
2661 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
2662 Free((void **)&CurrentBonds, "molecule::CheckAdjacencyFileAgainstMolecule - **CurrentBonds");
2663 } else {
2664 *out << Verbose(1) << "Adjacency file not found." << endl;
2665 status = false;
2666 }
2667 *out << endl;
2668 Free((void **)&buffer, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
2669
2670 return status;
2671};
2672
2673/** Checks whether the OrderAtSite is still below \a Order at some site.
2674 * \param *out output stream for debugging
2675 * \param *AtomMask defines true/false per global Atom::nr to mask in/out each nuclear site, used to activate given number of site to increment order adaptively
2676 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
2677 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
2678 * \param *MinimumRingSize array of max. possible order to avoid loops
2679 * \param *path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
2680 * \return true - needs further fragmentation, false - does not need fragmentation
2681 */
2682bool molecule::CheckOrderAtSite(ofstream *out, bool *AtomMask, Graph *GlobalKeySetList, int Order, int *MinimumRingSize, char *path)
2683{
2684 atom *Walker = start;
2685 bool status = false;
2686 ifstream InputFile;
2687
2688 // initialize mask list
2689 for(int i=AtomCount;i--;)
2690 AtomMask[i] = false;
2691
2692 if (Order < 0) { // adaptive increase of BondOrder per site
2693 if (AtomMask[AtomCount] == true) // break after one step
2694 return false;
2695 // parse the EnergyPerFragment file
2696 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckOrderAtSite: *buffer");
2697 sprintf(buffer, "%s/%s%s.dat", path, FRAGMENTPREFIX, ENERGYPERFRAGMENT);
2698 InputFile.open(buffer, ios::in);
2699 if ((InputFile != NULL) && (GlobalKeySetList != NULL)) {
2700 // transmorph graph keyset list into indexed KeySetList
2701 map<int,KeySet> IndexKeySetList;
2702 for(Graph::iterator runner = GlobalKeySetList->begin(); runner != GlobalKeySetList->end(); runner++) {
2703 IndexKeySetList.insert( pair<int,KeySet>(runner->second.first,runner->first) );
2704 }
2705 int lines = 0;
2706 // count the number of lines, i.e. the number of fragments
2707 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
2708 InputFile.getline(buffer, MAXSTRINGSIZE);
2709 while(!InputFile.eof()) {
2710 InputFile.getline(buffer, MAXSTRINGSIZE);
2711 lines++;
2712 }
2713 //*out << Verbose(2) << "Scanned " << lines-1 << " lines." << endl; // one endline too much
2714 InputFile.clear();
2715 InputFile.seekg(ios::beg);
2716 map<int, pair<double,int> > AdaptiveCriteriaList; // (Root No., (Value, Order)) !
2717 int No, FragOrder;
2718 double Value;
2719 // each line represents a fragment root (Atom::nr) id and its energy contribution
2720 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
2721 InputFile.getline(buffer, MAXSTRINGSIZE);
2722 while(!InputFile.eof()) {
2723 InputFile.getline(buffer, MAXSTRINGSIZE);
2724 if (strlen(buffer) > 2) {
2725 //*out << Verbose(2) << "Scanning: " << buffer << endl;
2726 stringstream line(buffer);
2727 line >> FragOrder;
2728 line >> ws >> No;
2729 line >> ws >> Value; // skip time entry
2730 line >> ws >> Value;
2731 No -= 1; // indices start at 1 in file, not 0
2732 //*out << Verbose(2) << " - yields (" << No << "," << Value << ", " << FragOrder << ")" << endl;
2733
2734 // clean the list of those entries that have been superceded by higher order terms already
2735 map<int,KeySet>::iterator marker = IndexKeySetList.find(No); // find keyset to Frag No.
2736 if (marker != IndexKeySetList.end()) { // if found
2737 Value *= 1 + MYEPSILON*(*((*marker).second.begin())); // in case of equal energies this makes em not equal without changing anything actually
2738 // as the smallest number in each set has always been the root (we use global id to keep the doubles away), seek smallest and insert into AtomMask
2739 pair <map<int, pair<double,int> >::iterator, bool> InsertedElement = AdaptiveCriteriaList.insert( make_pair(*((*marker).second.begin()), pair<double,int>( fabs(Value), FragOrder) ));
2740 map<int, pair<double,int> >::iterator PresentItem = InsertedElement.first;
2741 if (!InsertedElement.second) { // this root is already present
2742 if ((*PresentItem).second.second < FragOrder) // if order there is lower, update entry with higher-order term
2743 //if ((*PresentItem).second.first < (*runner).first) // as higher-order terms are not always better, we skip this part (which would always include this site into adaptive increase)
2744 { // if value is smaller, update value and order
2745 (*PresentItem).second.first = fabs(Value);
2746 (*PresentItem).second.second = FragOrder;
2747 *out << Verbose(2) << "Updated element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;
2748 } else {
2749 *out << Verbose(2) << "Did not update element " << (*PresentItem).first << " as " << FragOrder << " is less than or equal to " << (*PresentItem).second.second << "." << endl;
2750 }
2751 } else {
2752 *out << Verbose(2) << "Inserted element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;
2753 }
2754 } else {
2755 *out << Verbose(1) << "No Fragment under No. " << No << "found." << endl;
2756 }
2757 }
2758 }
2759 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
2760 map<double, pair<int,int> > FinalRootCandidates;
2761 *out << Verbose(1) << "Root candidate list is: " << endl;
2762 for(map<int, pair<double,int> >::iterator runner = AdaptiveCriteriaList.begin(); runner != AdaptiveCriteriaList.end(); runner++) {
2763 Walker = FindAtom((*runner).first);
2764 if (Walker != NULL) {
2765 //if ((*runner).second.second >= Walker->AdaptiveOrder) { // only insert if this is an "active" root site for the current order
2766 if (!Walker->MaxOrder) {
2767 *out << Verbose(2) << "(" << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "])" << endl;
2768 FinalRootCandidates.insert( make_pair( (*runner).second.first, pair<int,int>((*runner).first, (*runner).second.second) ) );
2769 } else {
2770 *out << Verbose(2) << "Excluding (" << *Walker << ", " << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "]), as it has reached its maximum order." << endl;
2771 }
2772 } else {
2773 cerr << "Atom No. " << (*runner).second.first << " was not found in this molecule." << endl;
2774 }
2775 }
2776 // pick the ones still below threshold and mark as to be adaptively updated
2777 for(map<double, pair<int,int> >::iterator runner = FinalRootCandidates.upper_bound(pow(10.,Order)); runner != FinalRootCandidates.end(); runner++) {
2778 No = (*runner).second.first;
2779 Walker = FindAtom(No);
2780 //if (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]) {
2781 *out << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", setting entry " << No << " of Atom mask to true." << endl;
2782 AtomMask[No] = true;
2783 status = true;
2784 //} else
2785 //*out << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", however MinimumRingSize of " << MinimumRingSize[Walker->nr] << " does not allow further adaptive increase." << endl;
2786 }
2787 // close and done
2788 InputFile.close();
2789 InputFile.clear();
2790 } else {
2791 cerr << "Unable to parse " << buffer << " file, incrementing all." << endl;
2792 while (Walker->next != end) {
2793 Walker = Walker->next;
2794 #ifdef ADDHYDROGEN
2795 if (Walker->type->Z != 1) // skip hydrogen
2796 #endif
2797 {
2798 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms
2799 status = true;
2800 }
2801 }
2802 }
2803 Free((void **)&buffer, "molecule::CheckOrderAtSite: *buffer");
2804 // pick a given number of highest values and set AtomMask
2805 } else { // global increase of Bond Order
2806 while (Walker->next != end) {
2807 Walker = Walker->next;
2808 #ifdef ADDHYDROGEN
2809 if (Walker->type->Z != 1) // skip hydrogen
2810 #endif
2811 {
2812 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms
2813 if ((Order != 0) && (Walker->AdaptiveOrder < Order)) // && (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]))
2814 status = true;
2815 }
2816 }
2817 if ((Order == 0) && (AtomMask[AtomCount] == false)) // single stepping, just check
2818 status = true;
2819
2820 if (!status) {
2821 if (Order == 0)
2822 *out << Verbose(1) << "Single stepping done." << endl;
2823 else
2824 *out << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl;
2825 }
2826 }
2827
2828 // print atom mask for debugging
2829 *out << " ";
2830 for(int i=0;i<AtomCount;i++)
2831 *out << (i % 10);
2832 *out << endl << "Atom mask is: ";
2833 for(int i=0;i<AtomCount;i++)
2834 *out << (AtomMask[i] ? "t" : "f");
2835 *out << endl;
2836
2837 return status;
2838};
2839
2840/** Create a SortIndex to map from atomic labels to the sequence in which the atoms are given in the config file.
2841 * \param *out output stream for debugging
2842 * \param *&SortIndex Mapping array of size molecule::AtomCount
2843 * \return true - success, false - failure of SortIndex alloc
2844 */
2845bool molecule::CreateMappingLabelsToConfigSequence(ofstream *out, int *&SortIndex)
2846{
2847 element *runner = elemente->start;
2848 int AtomNo = 0;
2849 atom *Walker = NULL;
2850
2851 if (SortIndex != NULL) {
2852 *out << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl;
2853 return false;
2854 }
2855 SortIndex = (int *) Malloc(sizeof(int)*AtomCount, "molecule::FragmentMolecule: *SortIndex");
2856 for(int i=AtomCount;i--;)
2857 SortIndex[i] = -1;
2858 while (runner->next != elemente->end) { // go through every element
2859 runner = runner->next;
2860 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
2861 Walker = start;
2862 while (Walker->next != end) { // go through every atom of this element
2863 Walker = Walker->next;
2864 if (Walker->type->Z == runner->Z) // if this atom fits to element
2865 SortIndex[Walker->nr] = AtomNo++;
2866 }
2867 }
2868 }
2869 return true;
2870};
2871
2872/** Performs a many-body bond order analysis for a given bond order.
2873 * -# parses adjacency, keysets and orderatsite files
2874 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
2875 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
2876y contribution", and that's why this consciously not done in the following loop)
2877 * -# in a loop over all subgraphs
2878 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
2879 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
2880 * -# combines the generated molecule lists from all subgraphs
2881 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
2882 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
2883 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
2884 * subgraph in the MoleculeListClass.
2885 * \param *out output stream for debugging
2886 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
2887 * \param *configuration configuration for writing config files for each fragment
2888 * \return 1 - continue, 2 - stop (no fragmentation occured)
2889 */
2890int molecule::FragmentMolecule(ofstream *out, int Order, config *configuration)
2891{
2892 MoleculeListClass *BondFragments = NULL;
2893 int *SortIndex = NULL;
2894 int *MinimumRingSize = new int[AtomCount];
2895 int FragmentCounter;
2896 MoleculeLeafClass *MolecularWalker = NULL;
2897 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
2898 fstream File;
2899 bool FragmentationToDo = true;
2900 class StackClass<bond *> *BackEdgeStack = NULL, *LocalBackEdgeStack = NULL;
2901 bool CheckOrder = false;
2902 Graph **FragmentList = NULL;
2903 Graph *ParsedFragmentList = NULL;
2904 Graph TotalGraph; // graph with all keysets however local numbers
2905 int TotalNumberOfKeySets = 0;
2906 atom **ListOfAtoms = NULL;
2907 atom ***ListOfLocalAtoms = NULL;
2908 bool *AtomMask = NULL;
2909
2910 *out << endl;
2911#ifdef ADDHYDROGEN
2912 *out << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl;
2913#else
2914 *out << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl;
2915#endif
2916
2917 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
2918
2919 // ===== 1. Check whether bond structure is same as stored in files ====
2920
2921 // fill the adjacency list
2922 CreateListOfBondsPerAtom(out);
2923
2924 // create lookup table for Atom::nr
2925 FragmentationToDo = FragmentationToDo && CreateFatherLookupTable(out, start, end, ListOfAtoms, AtomCount);
2926
2927 // === compare it with adjacency file ===
2928 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(out, configuration->configpath, ListOfAtoms);
2929 Free((void **)&ListOfAtoms, "molecule::FragmentMolecule - **ListOfAtoms");
2930
2931 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
2932 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack);
2933 // fill the bond structure of the individually stored subgraphs
2934 Subgraphs->next->FillBondStructureFromReference(out, this, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms
2935 // analysis of the cycles (print rings, get minimum cycle length) for each subgraph
2936 for(int i=AtomCount;i--;)
2937 MinimumRingSize[i] = AtomCount;
2938 MolecularWalker = Subgraphs;
2939 FragmentCounter = 0;
2940 while (MolecularWalker->next != NULL) {
2941 MolecularWalker = MolecularWalker->next;
2942 *out << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl;
2943 LocalBackEdgeStack = new StackClass<bond *> (MolecularWalker->Leaf->BondCount);
2944// // check the list of local atoms for debugging
2945// *out << Verbose(0) << "ListOfLocalAtoms for this subgraph is:" << endl;
2946// for (int i=0;i<AtomCount;i++)
2947// if (ListOfLocalAtoms[FragmentCounter][i] == NULL)
2948// *out << "\tNULL";
2949// else
2950// *out << "\t" << ListOfLocalAtoms[FragmentCounter][i]->Name;
2951 MolecularWalker->Leaf->PickLocalBackEdges(out, ListOfLocalAtoms[FragmentCounter++], BackEdgeStack, LocalBackEdgeStack);
2952 MolecularWalker->Leaf->CyclicStructureAnalysis(out, LocalBackEdgeStack, MinimumRingSize);
2953 delete(LocalBackEdgeStack);
2954 }
2955
2956 // ===== 3. if structure still valid, parse key set file and others =====
2957 FragmentationToDo = FragmentationToDo && ParseKeySetFile(out, configuration->configpath, ParsedFragmentList);
2958
2959 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
2960 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(out, configuration->configpath);
2961
2962 // =================================== Begin of FRAGMENTATION ===============================
2963 // ===== 6a. assign each keyset to its respective subgraph =====
2964 Subgraphs->next->AssignKeySetsToFragment(out, this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, (FragmentCounter = 0), true);
2965
2966 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
2967 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
2968 AtomMask = new bool[AtomCount+1];
2969 AtomMask[AtomCount] = false;
2970 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
2971 while ((CheckOrder = CheckOrderAtSite(out, AtomMask, ParsedFragmentList, Order, MinimumRingSize, configuration->configpath))) {
2972 FragmentationToDo = FragmentationToDo || CheckOrder;
2973 AtomMask[AtomCount] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
2974 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
2975 Subgraphs->next->FillRootStackForSubgraphs(out, RootStack, AtomMask, (FragmentCounter = 0));
2976
2977 // ===== 7. fill the bond fragment list =====
2978 FragmentCounter = 0;
2979 MolecularWalker = Subgraphs;
2980 while (MolecularWalker->next != NULL) {
2981 MolecularWalker = MolecularWalker->next;
2982 *out << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl;
2983 // output ListOfBondsPerAtom for debugging
2984 MolecularWalker->Leaf->OutputListOfBonds(out);
2985 if (MolecularWalker->Leaf->first->next != MolecularWalker->Leaf->last) {
2986
2987 // call BOSSANOVA method
2988 *out << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl;
2989 MolecularWalker->Leaf->FragmentBOSSANOVA(out, FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize);
2990 } else {
2991 cerr << "Subgraph " << MolecularWalker << " has no atoms!" << endl;
2992 }
2993 FragmentCounter++; // next fragment list
2994 }
2995 }
2996 delete[](RootStack);
2997 delete[](AtomMask);
2998 delete(ParsedFragmentList);
2999 delete[](MinimumRingSize);
3000
3001
3002 // ==================================== End of FRAGMENTATION ============================================
3003
3004 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
3005 Subgraphs->next->TranslateIndicesToGlobalIDs(out, FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
3006
3007 // free subgraph memory again
3008 FragmentCounter = 0;
3009 if (Subgraphs != NULL) {
3010 while (Subgraphs->next != NULL) {
3011 Subgraphs = Subgraphs->next;
3012 delete(FragmentList[FragmentCounter++]);
3013 delete(Subgraphs->previous);
3014 }
3015 delete(Subgraphs);
3016 }
3017 Free((void **)&FragmentList, "molecule::FragmentMolecule - **FragmentList");
3018
3019 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
3020 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
3021 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
3022 BondFragments = new MoleculeListClass(TotalGraph.size(), AtomCount);
3023 int k=0;
3024 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
3025 KeySet test = (*runner).first;
3026 *out << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl;
3027 BondFragments->ListOfMolecules[k] = StoreFragmentFromKeySet(out, test, configuration);
3028 k++;
3029 }
3030 *out << k << "/" << BondFragments->NumberOfMolecules << " fragments generated from the keysets." << endl;
3031
3032 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
3033 if (BondFragments->NumberOfMolecules != 0) {
3034 // create the SortIndex from BFS labels to order in the config file
3035 CreateMappingLabelsToConfigSequence(out, SortIndex);
3036
3037 *out << Verbose(1) << "Writing " << BondFragments->NumberOfMolecules << " possible bond fragmentation configs" << endl;
3038 if (BondFragments->OutputConfigForListOfFragments(out, configuration, SortIndex))
3039 *out << Verbose(1) << "All configs written." << endl;
3040 else
3041 *out << Verbose(1) << "Some config writing failed." << endl;
3042
3043 // store force index reference file
3044 BondFragments->StoreForcesFile(out, configuration->configpath, SortIndex);
3045
3046 // store keysets file
3047 StoreKeySetFile(out, TotalGraph, configuration->configpath);
3048
3049 // store Adjacency file
3050 StoreAdjacencyToFile(out, configuration->configpath);
3051
3052 // store Hydrogen saturation correction file
3053 BondFragments->AddHydrogenCorrection(out, configuration->configpath);
3054
3055 // store adaptive orders into file
3056 StoreOrderAtSiteFile(out, configuration->configpath);
3057
3058 // restore orbital and Stop values
3059 CalculateOrbitals(*configuration);
3060
3061 // free memory for bond part
3062 *out << Verbose(1) << "Freeing bond memory" << endl;
3063 delete(FragmentList); // remove bond molecule from memory
3064 Free((void **)&SortIndex, "molecule::FragmentMolecule: *SortIndex");
3065 } else
3066 *out << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl;
3067 //} else
3068 // *out << Verbose(1) << "No fragments to store." << endl;
3069 *out << Verbose(0) << "End of bond fragmentation." << endl;
3070
3071 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
3072};
3073
3074
3075/** Picks from a global stack with all back edges the ones in the fragment.
3076 * \param *out output stream for debugging
3077 * \param **ListOfLocalAtoms array of father atom::nr to local atom::nr (reverse of atom::father)
3078 * \param *ReferenceStack stack with all the back egdes
3079 * \param *LocalStack stack to be filled
3080 * \return true - everything ok, false - ReferenceStack was empty
3081 */
3082bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack)
3083{
3084 bool status = true;
3085 if (ReferenceStack->IsEmpty()) {
3086 cerr << "ReferenceStack is empty!" << endl;
3087 return false;
3088 }
3089 bond *Binder = ReferenceStack->PopFirst();
3090 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
3091 atom *Walker = NULL, *OtherAtom = NULL;
3092 ReferenceStack->Push(Binder);
3093
3094 do { // go through all bonds and push local ones
3095 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule
3096 if (Walker == NULL) // if this Walker exists in the subgraph ...
3097 continue;
3098 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through the local list of bonds
3099 OtherAtom = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
3100 if (OtherAtom == ListOfLocalAtoms[Binder->rightatom->nr]) { // found the bond
3101 LocalStack->Push(ListOfBondsPerAtom[Walker->nr][i]);
3102 break;
3103 }
3104 }
3105 Binder = ReferenceStack->PopFirst(); // loop the stack for next item
3106 ReferenceStack->Push(Binder);
3107 } while (FirstBond != Binder);
3108
3109 return status;
3110};
3111
3112/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
3113 * Atoms not present in the file get "-1".
3114 * \param *out output stream for debugging
3115 * \param *path path to file ORDERATSITEFILE
3116 * \return true - file writable, false - not writable
3117 */
3118bool molecule::StoreOrderAtSiteFile(ofstream *out, char *path)
3119{
3120 stringstream line;
3121 ofstream file;
3122
3123 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
3124 file.open(line.str().c_str());
3125 *out << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl;
3126 if (file != NULL) {
3127 atom *Walker = start;
3128 while (Walker->next != end) {
3129 Walker = Walker->next;
3130 file << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << endl;
3131 *out << Verbose(2) << "Storing: " << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << "." << endl;
3132 }
3133 file.close();
3134 *out << Verbose(1) << "done." << endl;
3135 return true;
3136 } else {
3137 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
3138 return false;
3139 }
3140};
3141
3142/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
3143 * Atoms not present in the file get "0".
3144 * \param *out output stream for debugging
3145 * \param *path path to file ORDERATSITEFILEe
3146 * \return true - file found and scanned, false - file not found
3147 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
3148 */
3149bool molecule::ParseOrderAtSiteFromFile(ofstream *out, char *path)
3150{
3151 unsigned char *OrderArray = (unsigned char *) Malloc(sizeof(unsigned char)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
3152 bool *MaxArray = (bool *) Malloc(sizeof(bool)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
3153 bool status;
3154 int AtomNr, value;
3155 stringstream line;
3156 ifstream file;
3157
3158 *out << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl;
3159 for(int i=AtomCount;i--;)
3160 OrderArray[i] = 0;
3161 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
3162 file.open(line.str().c_str());
3163 if (file != NULL) {
3164 for (int i=AtomCount;i--;) { // initialise with 0
3165 OrderArray[i] = 0;
3166 MaxArray[i] = 0;
3167 }
3168 while (!file.eof()) { // parse from file
3169 AtomNr = -1;
3170 file >> AtomNr;
3171 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
3172 file >> value;
3173 OrderArray[AtomNr] = value;
3174 file >> value;
3175 MaxArray[AtomNr] = value;
3176 //*out << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
3177 }
3178 }
3179 atom *Walker = start;
3180 while (Walker->next != end) { // fill into atom classes
3181 Walker = Walker->next;
3182 Walker->AdaptiveOrder = OrderArray[Walker->nr];
3183 Walker->MaxOrder = MaxArray[Walker->nr];
3184 *out << Verbose(2) << *Walker << " gets order " << (int)Walker->AdaptiveOrder << " and is " << (!Walker->MaxOrder ? "not " : " ") << "maxed." << endl;
3185 }
3186 file.close();
3187 *out << Verbose(1) << "done." << endl;
3188 status = true;
3189 } else {
3190 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
3191 status = false;
3192 }
3193 Free((void **)&OrderArray, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
3194 Free((void **)&MaxArray, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
3195
3196 *out << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl;
3197 return status;
3198};
3199
3200/** Creates an 2d array of pointer with an entry for each atom and each bond it has.
3201 * Updates molecule::ListOfBondsPerAtom, molecule::NumberOfBondsPerAtom by parsing through
3202 * bond chain list, using molecule::AtomCount and molecule::BondCount.
3203 * Allocates memory, fills the array and exits
3204 * \param *out output stream for debugging
3205 */
3206void molecule::CreateListOfBondsPerAtom(ofstream *out)
3207{
3208 bond *Binder = NULL;
3209 atom *Walker = NULL;
3210 int TotalDegree;
3211 *out << Verbose(1) << "Begin of Creating ListOfBondsPerAtom: AtomCount = " << AtomCount << "\tBondCount = " << BondCount << "\tNoNonBonds = " << NoNonBonds << "." << endl;
3212
3213 // re-allocate memory
3214 *out << Verbose(2) << "(Re-)Allocating memory." << endl;
3215 if (ListOfBondsPerAtom != NULL) {
3216 for(int i=AtomCount;i--;)
3217 Free((void **)&ListOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom[i]");
3218 Free((void **)&ListOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom");
3219 }
3220 if (NumberOfBondsPerAtom != NULL)
3221 Free((void **)&NumberOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: NumberOfBondsPerAtom");
3222 ListOfBondsPerAtom = (bond ***) Malloc(sizeof(bond **)*AtomCount, "molecule::CreateListOfBondsPerAtom: ***ListOfBondsPerAtom");
3223 NumberOfBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfBondsPerAtom: *NumberOfBondsPerAtom");
3224
3225 // reset bond counts per atom
3226 for(int i=AtomCount;i--;)
3227 NumberOfBondsPerAtom[i] = 0;
3228 // count bonds per atom
3229 Binder = first;
3230 while (Binder->next != last) {
3231 Binder = Binder->next;
3232 NumberOfBondsPerAtom[Binder->leftatom->nr]++;
3233 NumberOfBondsPerAtom[Binder->rightatom->nr]++;
3234 }
3235 for(int i=AtomCount;i--;) {
3236 // allocate list of bonds per atom
3237 ListOfBondsPerAtom[i] = (bond **) Malloc(sizeof(bond *)*NumberOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: **ListOfBondsPerAtom[]");
3238 // clear the list again, now each NumberOfBondsPerAtom marks current free field
3239 NumberOfBondsPerAtom[i] = 0;
3240 }
3241 // fill the list
3242 Binder = first;
3243 while (Binder->next != last) {
3244 Binder = Binder->next;
3245 ListOfBondsPerAtom[Binder->leftatom->nr][NumberOfBondsPerAtom[Binder->leftatom->nr]++] = Binder;
3246 ListOfBondsPerAtom[Binder->rightatom->nr][NumberOfBondsPerAtom[Binder->rightatom->nr]++] = Binder;
3247 }
3248
3249 // output list for debugging
3250 *out << Verbose(3) << "ListOfBondsPerAtom for each atom:" << endl;
3251 Walker = start;
3252 while (Walker->next != end) {
3253 Walker = Walker->next;
3254 *out << Verbose(4) << "Atom " << Walker->Name << "/" << Walker->nr << " with " << NumberOfBondsPerAtom[Walker->nr] << " bonds: ";
3255 TotalDegree = 0;
3256 for (int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
3257 *out << *ListOfBondsPerAtom[Walker->nr][j] << "\t";
3258 TotalDegree += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
3259 }
3260 *out << " -- TotalDegree: " << TotalDegree << endl;
3261 }
3262 *out << Verbose(1) << "End of Creating ListOfBondsPerAtom." << endl << endl;
3263};
3264
3265/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
3266 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
3267 * white and putting into queue.
3268 * \param *out output stream for debugging
3269 * \param *Mol Molecule class to add atoms to
3270 * \param **AddedAtomList list with added atom pointers, index is atom father's number
3271 * \param **AddedBondList list with added bond pointers, index is bond father's number
3272 * \param *Root root vertex for BFS
3273 * \param *Bond bond not to look beyond
3274 * \param BondOrder maximum distance for vertices to add
3275 * \param IsAngstroem lengths are in angstroem or bohrradii
3276 */
3277void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
3278{
3279 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList");
3280 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList");
3281 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList");
3282 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
3283 atom *Walker = NULL, *OtherAtom = NULL;
3284 bond *Binder = NULL;
3285
3286 // add Root if not done yet
3287 AtomStack->ClearStack();
3288 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
3289 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
3290 AtomStack->Push(Root);
3291
3292 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
3293 for (int i=AtomCount;i--;) {
3294 PredecessorList[i] = NULL;
3295 ShortestPathList[i] = -1;
3296 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited
3297 ColorList[i] = lightgray;
3298 else
3299 ColorList[i] = white;
3300 }
3301 ShortestPathList[Root->nr] = 0;
3302
3303 // and go on ... Queue always contains all lightgray vertices
3304 while (!AtomStack->IsEmpty()) {
3305 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
3306 // e.g. if current atom is 2, push to end of stack are of length 3, but first all of length 2 would be popped. They again
3307 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
3308 // followed by n+1 till top of stack.
3309 Walker = AtomStack->PopFirst(); // pop oldest added
3310 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl;
3311 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
3312 Binder = ListOfBondsPerAtom[Walker->nr][i];
3313 if (Binder != NULL) { // don't look at bond equal NULL
3314 OtherAtom = Binder->GetOtherAtom(Walker);
3315 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
3316 if (ColorList[OtherAtom->nr] == white) {
3317 if (Binder != Bond) // let other atom white if it's via Root bond. In case it's cyclic it has to be reached again (yet Root is from OtherAtom already black, thus no problem)
3318 ColorList[OtherAtom->nr] = lightgray;
3319 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
3320 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
3321 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " " << ((ColorList[OtherAtom->nr] == white) ? "white" : "lightgray") << ", its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
3322 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance
3323 *out << Verbose(3);
3324 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
3325 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
3326 *out << "Added OtherAtom " << OtherAtom->Name;
3327 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3328 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3329 AddedBondList[Binder->nr]->Type = Binder->Type;
3330 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
3331 } else { // this code should actually never come into play (all white atoms are not yet present in BondMolecule, that's why they are white in the first place)
3332 *out << "Not adding OtherAtom " << OtherAtom->Name;
3333 if (AddedBondList[Binder->nr] == NULL) {
3334 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3335 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3336 AddedBondList[Binder->nr]->Type = Binder->Type;
3337 *out << ", added Bond " << *(AddedBondList[Binder->nr]);
3338 } else
3339 *out << ", not added Bond ";
3340 }
3341 *out << ", putting OtherAtom into queue." << endl;
3342 AtomStack->Push(OtherAtom);
3343 } else { // out of bond order, then replace
3344 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
3345 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
3346 if (Binder == Bond)
3347 *out << Verbose(3) << "Not Queueing, is the Root bond";
3348 else if (ShortestPathList[OtherAtom->nr] >= BondOrder)
3349 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder;
3350 if (!Binder->Cyclic)
3351 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
3352 if (AddedBondList[Binder->nr] == NULL) {
3353 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
3354 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3355 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3356 AddedBondList[Binder->nr]->Type = Binder->Type;
3357 } else {
3358#ifdef ADDHYDROGEN
3359 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
3360#endif
3361 }
3362 }
3363 }
3364 } else {
3365 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
3366 // This has to be a cyclic bond, check whether it's present ...
3367 if (AddedBondList[Binder->nr] == NULL) {
3368 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) {
3369 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3370 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3371 AddedBondList[Binder->nr]->Type = Binder->Type;
3372 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
3373#ifdef ADDHYDROGEN
3374 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
3375#endif
3376 }
3377 }
3378 }
3379 }
3380 }
3381 ColorList[Walker->nr] = black;
3382 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
3383 }
3384 Free((void **)&PredecessorList, "molecule::BreadthFirstSearchAdd: **PredecessorList");
3385 Free((void **)&ShortestPathList, "molecule::BreadthFirstSearchAdd: **ShortestPathList");
3386 Free((void **)&ColorList, "molecule::BreadthFirstSearchAdd: **ColorList");
3387 delete(AtomStack);
3388};
3389
3390/** Adds bond structure to this molecule from \a Father molecule.
3391 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
3392 * with end points present in this molecule, bond is created in this molecule.
3393 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
3394 * \param *out output stream for debugging
3395 * \param *Father father molecule
3396 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
3397 * \todo not checked, not fully working probably
3398 */
3399bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
3400{
3401 atom *Walker = NULL, *OtherAtom = NULL;
3402 bool status = true;
3403 atom **ParentList = (atom **) Malloc(sizeof(atom *)*Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList");
3404
3405 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
3406
3407 // reset parent list
3408 *out << Verbose(3) << "Resetting ParentList." << endl;
3409 for (int i=Father->AtomCount;i--;)
3410 ParentList[i] = NULL;
3411
3412 // fill parent list with sons
3413 *out << Verbose(3) << "Filling Parent List." << endl;
3414 Walker = start;
3415 while (Walker->next != end) {
3416 Walker = Walker->next;
3417 ParentList[Walker->father->nr] = Walker;
3418 // Outputting List for debugging
3419 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
3420 }
3421
3422 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
3423 *out << Verbose(3) << "Creating bonds." << endl;
3424 Walker = Father->start;
3425 while (Walker->next != Father->end) {
3426 Walker = Walker->next;
3427 if (ParentList[Walker->nr] != NULL) {
3428 if (ParentList[Walker->nr]->father != Walker) {
3429 status = false;
3430 } else {
3431 for (int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) {
3432 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
3433 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
3434 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i] << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
3435 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree);
3436 }
3437 }
3438 }
3439 }
3440 }
3441
3442 Free((void **)&ParentList, "molecule::BuildInducedSubgraph: **ParentList");
3443 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
3444 return status;
3445};
3446
3447
3448/** Looks through a StackClass<atom *> and returns the likeliest removal candiate.
3449 * \param *out output stream for debugging messages
3450 * \param *&Leaf KeySet to look through
3451 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
3452 * \param index of the atom suggested for removal
3453 */
3454int molecule::LookForRemovalCandidate(ofstream *&out, KeySet *&Leaf, int *&ShortestPathList)
3455{
3456 atom *Runner = NULL;
3457 int SP, Removal;
3458
3459 *out << Verbose(2) << "Looking for removal candidate." << endl;
3460 SP = -1; //0; // not -1, so that Root is never removed
3461 Removal = -1;
3462 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
3463 Runner = FindAtom((*runner));
3464 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack
3465 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
3466 SP = ShortestPathList[(*runner)];
3467 Removal = (*runner);
3468 }
3469 }
3470 }
3471 return Removal;
3472};
3473
3474/** Stores a fragment from \a KeySet into \a molecule.
3475 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
3476 * molecule and adds missing hydrogen where bonds were cut.
3477 * \param *out output stream for debugging messages
3478 * \param &Leaflet pointer to KeySet structure
3479 * \param IsAngstroem whether we have Ansgtroem or bohrradius
3480 * \return pointer to constructed molecule
3481 */
3482molecule * molecule::StoreFragmentFromKeySet(ofstream *out, KeySet &Leaflet, bool IsAngstroem)
3483{
3484 atom *Runner = NULL, *FatherOfRunner = NULL, *OtherFather = NULL;
3485 atom **SonList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::StoreFragmentFromStack: **SonList");
3486 molecule *Leaf = new molecule(elemente);
3487 bool LonelyFlag = false;
3488 int size;
3489
3490// *out << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
3491
3492 Leaf->BondDistance = BondDistance;
3493 for(int i=NDIM*2;i--;)
3494 Leaf->cell_size[i] = cell_size[i];
3495
3496 // initialise SonList (indicates when we need to replace a bond with hydrogen instead)
3497 for(int i=AtomCount;i--;)
3498 SonList[i] = NULL;
3499
3500 // first create the minimal set of atoms from the KeySet
3501 size = 0;
3502 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
3503 FatherOfRunner = FindAtom((*runner)); // find the id
3504 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner);
3505 size++;
3506 }
3507
3508 // create the bonds between all: Make it an induced subgraph and add hydrogen
3509// *out << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
3510 Runner = Leaf->start;
3511 while (Runner->next != Leaf->end) {
3512 Runner = Runner->next;
3513 LonelyFlag = true;
3514 FatherOfRunner = Runner->father;
3515 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list
3516 // create all bonds
3517 for (int i=0;i<NumberOfBondsPerAtom[FatherOfRunner->nr];i++) { // go through every bond of father
3518 OtherFather = ListOfBondsPerAtom[FatherOfRunner->nr][i]->GetOtherAtom(FatherOfRunner);
3519// *out << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
3520 if (SonList[OtherFather->nr] != NULL) {
3521// *out << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
3522 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
3523// *out << Verbose(3) << "Adding Bond: ";
3524// *out <<
3525 Leaf->AddBond(Runner, SonList[OtherFather->nr], ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree);
3526// *out << "." << endl;
3527 //NumBonds[Runner->nr]++;
3528 } else {
3529// *out << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
3530 }
3531 LonelyFlag = false;
3532 } else {
3533// *out << ", who has no son in this fragment molecule." << endl;
3534#ifdef ADDHYDROGEN
3535 //*out << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl;
3536 Leaf->AddHydrogenReplacementAtom(out, ListOfBondsPerAtom[FatherOfRunner->nr][i], Runner, FatherOfRunner, OtherFather, ListOfBondsPerAtom[FatherOfRunner->nr],NumberOfBondsPerAtom[FatherOfRunner->nr], IsAngstroem);
3537#endif
3538 //NumBonds[Runner->nr] += ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree;
3539 }
3540 }
3541 } else {
3542 *out << Verbose(0) << "ERROR: Son " << Runner->Name << " has father " << FatherOfRunner->Name << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl;
3543 }
3544 if ((LonelyFlag) && (size > 1)) {
3545 *out << Verbose(0) << *Runner << "has got bonds only to hydrogens!" << endl;
3546 }
3547#ifdef ADDHYDROGEN
3548 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen
3549 Runner = Runner->next;
3550#endif
3551 }
3552 Leaf->CreateListOfBondsPerAtom(out);
3553 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
3554 Free((void **)&SonList, "molecule::StoreFragmentFromStack: **SonList");
3555// *out << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
3556 return Leaf;
3557};
3558
3559/** Creates \a MoleculeListClass of all unique fragments of the \a molecule containing \a Order atoms or vertices.
3560 * The picture to have in mind is that of a DFS "snake" of a certain length \a Order, i.e. as in the infamous
3561 * computer game, that winds through the connected graph representing the molecule. Color (white,
3562 * lightgray, darkgray, black) indicates whether a vertex has been discovered so far or not. Labels will help in
3563 * creating only unique fragments and not additional ones with vertices simply in different sequence.
3564 * The Predecessor is always the one that came before in discovering, needed on backstepping. And
3565 * finally, the ShortestPath is needed for removing vertices from the snake stack during the back-
3566 * stepping.
3567 * \param *out output stream for debugging
3568 * \param Order number of atoms in each fragment
3569 * \param *configuration configuration for writing config files for each fragment
3570 * \return List of all unique fragments with \a Order atoms
3571 */
3572/*
3573MoleculeListClass * molecule::CreateListOfUniqueFragmentsOfOrder(ofstream *out, int Order, config *configuration)
3574{
3575 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
3576 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
3577 int *Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
3578 enum Shading *ColorVertexList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
3579 enum Shading *ColorEdgeList = (enum Shading *) Malloc(sizeof(enum Shading)*BondCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorBondList");
3580 StackClass<atom *> *RootStack = new StackClass<atom *>(AtomCount);
3581 StackClass<atom *> *TouchedStack = new StackClass<atom *>((int)pow(4,Order)+2); // number of atoms reached from one with maximal 4 bonds plus Root itself
3582 StackClass<atom *> *SnakeStack = new StackClass<atom *>(Order+1); // equal to Order is not possible, as then the StackClass<atom *> cannot discern between full and empty stack!
3583 MoleculeLeafClass *Leaflet = NULL, *TempLeaf = NULL;
3584 MoleculeListClass *FragmentList = NULL;
3585 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Removal = NULL;
3586 bond *Binder = NULL;
3587 int RunningIndex = 0, FragmentCounter = 0;
3588
3589 *out << Verbose(1) << "Begin of CreateListOfUniqueFragmentsOfOrder." << endl;
3590
3591 // reset parent list
3592 *out << Verbose(3) << "Resetting labels, parent, predecessor, color and shortest path lists." << endl;
3593 for (int i=0;i<AtomCount;i++) { // reset all atom labels
3594 // initialise each vertex as white with no predecessor, empty queue, color lightgray, not labelled, no sons
3595 Labels[i] = -1;
3596 SonList[i] = NULL;
3597 PredecessorList[i] = NULL;
3598 ColorVertexList[i] = white;
3599 ShortestPathList[i] = -1;
3600 }
3601 for (int i=0;i<BondCount;i++)
3602 ColorEdgeList[i] = white;
3603 RootStack->ClearStack(); // clearstack and push first atom if exists
3604 TouchedStack->ClearStack();
3605 Walker = start->next;
3606 while ((Walker != end)
3607#ifdef ADDHYDROGEN
3608 && (Walker->type->Z == 1)
3609#endif
3610 ) { // search for first non-hydrogen atom
3611 *out << Verbose(4) << "Current Root candidate is " << Walker->Name << "." << endl;
3612 Walker = Walker->next;
3613 }
3614 if (Walker != end)
3615 RootStack->Push(Walker);
3616 else
3617 *out << Verbose(0) << "ERROR: Could not find an appropriate Root atom!" << endl;
3618 *out << Verbose(3) << "Root " << Walker->Name << " is on AtomStack, beginning loop through all vertices ..." << endl;
3619
3620 ///// OUTER LOOP ////////////
3621 while (!RootStack->IsEmpty()) {
3622 // get new root vertex from atom stack
3623 Root = RootStack->PopFirst();
3624 ShortestPathList[Root->nr] = 0;
3625 if (Labels[Root->nr] == -1)
3626 Labels[Root->nr] = RunningIndex++; // prevent it from getting again on AtomStack
3627 PredecessorList[Root->nr] = Root;
3628 TouchedStack->Push(Root);
3629 *out << Verbose(0) << "Root for this loop is: " << Root->Name << ".\n";
3630
3631 // clear snake stack
3632 SnakeStack->ClearStack();
3633 //SnakeStack->TestImplementation(out, start->next);
3634
3635 ///// INNER LOOP ////////////
3636 // Problems:
3637 // - what about cyclic bonds?
3638 Walker = Root;
3639 do {
3640 *out << Verbose(1) << "Current Walker is: " << Walker->Name;
3641 // initial setting of the new Walker: label, color, shortest path and put on stacks
3642 if (Labels[Walker->nr] == -1) { // give atom a unique, monotonely increasing number
3643 Labels[Walker->nr] = RunningIndex++;
3644 RootStack->Push(Walker);
3645 }
3646 *out << ", has label " << Labels[Walker->nr];
3647 if ((ColorVertexList[Walker->nr] == white) || ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white))) { // color it if newly discovered and push on stacks (and if within reach!)
3648 if ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white)) {
3649 // Binder ought to be set still from last neighbour search
3650 *out << ", coloring bond " << *Binder << " black";
3651 ColorEdgeList[Binder->nr] = black; // mark this bond as used
3652 }
3653 if (ShortestPathList[Walker->nr] == -1) {
3654 ShortestPathList[Walker->nr] = ShortestPathList[PredecessorList[Walker->nr]->nr]+1;
3655 TouchedStack->Push(Walker); // mark every atom for lists cleanup later, whose shortest path has been changed
3656 }
3657 if ((ShortestPathList[Walker->nr] < Order) && (ColorVertexList[Walker->nr] != darkgray)) { // if not already on snake stack
3658 SnakeStack->Push(Walker);
3659 ColorVertexList[Walker->nr] = darkgray; // mark as dark gray of on snake stack
3660 }
3661 }
3662 *out << ", SP of " << ShortestPathList[Walker->nr] << " and its color is " << GetColor(ColorVertexList[Walker->nr]) << "." << endl;
3663
3664 // then check the stack for a newly stumbled upon fragment
3665 if (SnakeStack->ItemCount() == Order) { // is stack full?
3666 // store the fragment if it is one and get a removal candidate
3667 Removal = StoreFragmentFromStack(out, Root, Walker, Leaflet, SnakeStack, ShortestPathList, SonList, Labels, &FragmentCounter, configuration);
3668 // remove the candidate if one was found
3669 if (Removal != NULL) {
3670 *out << Verbose(2) << "Removing item " << Removal->Name << " with SP of " << ShortestPathList[Removal->nr] << " from snake stack." << endl;
3671 SnakeStack->RemoveItem(Removal);
3672 ColorVertexList[Removal->nr] = lightgray; // return back to not on snake stack but explored marking
3673 if (Walker == Removal) { // if the current atom is to be removed, we also have to take a step back
3674 Walker = PredecessorList[Removal->nr];
3675 *out << Verbose(2) << "Stepping back to " << Walker->Name << "." << endl;
3676 }
3677 }
3678 } else
3679 Removal = NULL;
3680
3681 // finally, look for a white neighbour as the next Walker
3682 Binder = NULL;
3683 if ((Removal == NULL) || (Walker != PredecessorList[Removal->nr])) { // don't look, if a new walker has been set above
3684 *out << Verbose(2) << "Snake has currently " << SnakeStack->ItemCount() << " item(s)." << endl;
3685 OtherAtom = NULL; // this is actually not needed, every atom has at least one neighbour
3686 if (ShortestPathList[Walker->nr] < Order) {
3687 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
3688 Binder = ListOfBondsPerAtom[Walker->nr][i];
3689 *out << Verbose(2) << "Current bond is " << *Binder << ": ";
3690 OtherAtom = Binder->GetOtherAtom(Walker);
3691 if ((Labels[OtherAtom->nr] != -1) && (Labels[OtherAtom->nr] < Labels[Root->nr])) { // we don't step up to labels bigger than us
3692 *out << "Label " << Labels[OtherAtom->nr] << " is smaller than Root's " << Labels[Root->nr] << "." << endl;
3693 //ColorVertexList[OtherAtom->nr] = lightgray; // mark as explored
3694 } else { // otherwise check its colour and element
3695 if (
3696#ifdef ADDHYDROGEN
3697 (OtherAtom->type->Z != 1) &&
3698#endif
3699 (ColorEdgeList[Binder->nr] == white)) { // skip hydrogen, look for unexplored vertices
3700 *out << "Moving along " << GetColor(ColorEdgeList[Binder->nr]) << " bond " << Binder << " to " << ((ColorVertexList[OtherAtom->nr] == white) ? "unexplored" : "explored") << " item: " << OtherAtom->Name << "." << endl;
3701 // i find it currently rather sensible to always set the predecessor in order to find one's way back
3702 //if (PredecessorList[OtherAtom->nr] == NULL) {
3703 PredecessorList[OtherAtom->nr] = Walker;
3704 *out << Verbose(3) << "Setting Predecessor of " << OtherAtom->Name << " to " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
3705 //} else {
3706 // *out << Verbose(3) << "Predecessor of " << OtherAtom->Name << " is " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
3707 //}
3708 Walker = OtherAtom;
3709 break;
3710 } else {
3711 if (OtherAtom->type->Z == 1)
3712 *out << "Links to a hydrogen atom." << endl;
3713 else
3714 *out << "Bond has not white but " << GetColor(ColorEdgeList[Binder->nr]) << " color." << endl;
3715 }
3716 }
3717 }
3718 } else { // means we have stepped beyond the horizon: Return!
3719 Walker = PredecessorList[Walker->nr];
3720 OtherAtom = Walker;
3721 *out << Verbose(3) << "We have gone too far, stepping back to " << Walker->Name << "." << endl;
3722 }
3723 if (Walker != OtherAtom) { // if no white neighbours anymore, color it black
3724 *out << Verbose(2) << "Coloring " << Walker->Name << " black." << endl;
3725 ColorVertexList[Walker->nr] = black;
3726 Walker = PredecessorList[Walker->nr];
3727 }
3728 }
3729 } while ((Walker != Root) || (ColorVertexList[Root->nr] != black));
3730 *out << Verbose(2) << "Inner Looping is finished." << endl;
3731
3732 // if we reset all AtomCount atoms, we have again technically O(N^2) ...
3733 *out << Verbose(2) << "Resetting lists." << endl;
3734 Walker = NULL;
3735 Binder = NULL;
3736 while (!TouchedStack->IsEmpty()) {
3737 Walker = TouchedStack->PopLast();
3738 *out << Verbose(3) << "Re-initialising entries of " << *Walker << "." << endl;
3739 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
3740 ColorEdgeList[ListOfBondsPerAtom[Walker->nr][i]->nr] = white;
3741 PredecessorList[Walker->nr] = NULL;
3742 ColorVertexList[Walker->nr] = white;
3743 ShortestPathList[Walker->nr] = -1;
3744 }
3745 }
3746 *out << Verbose(1) << "Outer Looping over all vertices is done." << endl;
3747
3748 // copy together
3749 *out << Verbose(1) << "Copying all fragments into MoleculeList structure." << endl;
3750 FragmentList = new MoleculeListClass(FragmentCounter, AtomCount);
3751 RunningIndex = 0;
3752 while ((Leaflet != NULL) && (RunningIndex < FragmentCounter)) {
3753 FragmentList->ListOfMolecules[RunningIndex++] = Leaflet->Leaf;
3754 Leaflet->Leaf = NULL; // prevent molecule from being removed
3755 TempLeaf = Leaflet;
3756 Leaflet = Leaflet->previous;
3757 delete(TempLeaf);
3758 };
3759
3760 // free memory and exit
3761 Free((void **)&PredecessorList, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
3762 Free((void **)&ShortestPathList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
3763 Free((void **)&Labels, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
3764 Free((void **)&ColorVertexList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
3765 delete(RootStack);
3766 delete(TouchedStack);
3767 delete(SnakeStack);
3768
3769 *out << Verbose(1) << "End of CreateListOfUniqueFragmentsOfOrder." << endl;
3770 return FragmentList;
3771};
3772*/
3773
3774/** Structure containing all values in power set combination generation.
3775 */
3776struct UniqueFragments {
3777 config *configuration;
3778 atom *Root;
3779 Graph *Leaflet;
3780 KeySet *FragmentSet;
3781 int ANOVAOrder;
3782 int FragmentCounter;
3783 int CurrentIndex;
3784 double TEFactor;
3785 int *ShortestPathList;
3786 bool **UsedList;
3787 bond **BondsPerSPList;
3788 int *BondsPerSPCount;
3789};
3790
3791/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
3792 * -# loops over every possible combination (2^dimension of edge set)
3793 * -# inserts current set, if there's still space left
3794 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
3795ance+1
3796 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
3797 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
3798distance) and current set
3799 * \param *out output stream for debugging
3800 * \param FragmentSearch UniqueFragments structure with all values needed
3801 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
3802 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
3803 * \param SubOrder remaining number of allowed vertices to add
3804 */
3805void molecule::SPFragmentGenerator(ofstream *out, struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
3806{
3807 atom *OtherWalker = NULL;
3808 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
3809 int NumCombinations;
3810 bool bit;
3811 int bits, TouchedIndex, SubSetDimension, SP, Added;
3812 int Removal;
3813 int SpaceLeft;
3814 int *TouchedList = (int *) Malloc(sizeof(int)*(SubOrder+1), "molecule::SPFragmentGenerator: *TouchedList");
3815 bond *Binder = NULL;
3816 bond **BondsList = NULL;
3817 KeySetTestPair TestKeySetInsert;
3818
3819 NumCombinations = 1 << SetDimension;
3820
3821 // Hier muessen von 1 bis NumberOfBondsPerAtom[Walker->nr] alle Kombinationen
3822 // von Endstuecken (aus den Bonds) hinzugefᅵᅵgt werden und fᅵᅵr verbleibende ANOVAOrder
3823 // rekursiv GraphCrawler in der nᅵᅵchsten Ebene aufgerufen werden
3824
3825 *out << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
3826 *out << Verbose(1+verbosity) << "We are " << RootDistance << " away from Root, which is " << *FragmentSearch->Root << ", SubOrder is " << SubOrder << ", SetDimension is " << SetDimension << " and this means " << NumCombinations-1 << " combination(s)." << endl;
3827
3828 // initialised touched list (stores added atoms on this level)
3829 *out << Verbose(1+verbosity) << "Clearing touched list." << endl;
3830 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
3831 TouchedList[TouchedIndex] = -1;
3832 TouchedIndex = 0;
3833
3834 // create every possible combination of the endpieces
3835 *out << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
3836 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
3837 // count the set bit of i
3838 bits = 0;
3839 for (int j=SetDimension;j--;)
3840 bits += (i & (1 << j)) >> j;
3841
3842 *out << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
3843 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
3844 // --1-- add this set of the power set of bond partners to the snake stack
3845 Added = 0;
3846 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
3847 bit = ((i & (1 << j)) != 0); // mask the bit for the j-th bond
3848 if (bit) { // if bit is set, we add this bond partner
3849 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
3850 //*out << Verbose(1+verbosity) << "Current Bond is " << ListOfBondsPerAtom[Walker->nr][i] << ", checking on " << *OtherWalker << "." << endl;
3851 *out << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
3852 TestKeySetInsert = FragmentSearch->FragmentSet->insert(OtherWalker->nr);
3853 if (TestKeySetInsert.second) {
3854 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
3855 Added++;
3856 } else {
3857 *out << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
3858 }
3859 //FragmentSearch->UsedList[OtherWalker->nr][i] = true;
3860 //}
3861 } else {
3862 *out << Verbose(2+verbosity) << "Not adding." << endl;
3863 }
3864 }
3865
3866 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
3867 if (SpaceLeft > 0) {
3868 *out << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
3869 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
3870 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
3871 SP = RootDistance+1; // this is the next level
3872 // first count the members in the subset
3873 SubSetDimension = 0;
3874 Binder = FragmentSearch->BondsPerSPList[2*SP]; // start node for this level
3875 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) { // compare to end node of this level
3876 Binder = Binder->next;
3877 for (int k=TouchedIndex;k--;) {
3878 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
3879 SubSetDimension++;
3880 }
3881 }
3882 // then allocate and fill the list
3883 BondsList = (bond **) Malloc(sizeof(bond *)*SubSetDimension, "molecule::SPFragmentGenerator: **BondsList");
3884 SubSetDimension = 0;
3885 Binder = FragmentSearch->BondsPerSPList[2*SP];
3886 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) {
3887 Binder = Binder->next;
3888 for (int k=0;k<TouchedIndex;k++) {
3889 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
3890 BondsList[SubSetDimension++] = Binder;
3891 }
3892 }
3893 *out << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
3894 SPFragmentGenerator(out, FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
3895 Free((void **)&BondsList, "molecule::SPFragmentGenerator: **BondsList");
3896 }
3897 } else {
3898 // --2-- otherwise store the complete fragment
3899 *out << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
3900 // store fragment as a KeySet
3901 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
3902 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
3903 *out << (*runner) << " ";
3904 *out << endl;
3905 //if (!CheckForConnectedSubgraph(out, FragmentSearch->FragmentSet))
3906 //*out << Verbose(0) << "ERROR: The found fragment is not a connected subgraph!" << endl;
3907 InsertFragmentIntoGraph(out, FragmentSearch);
3908 //Removal = LookForRemovalCandidate(out, FragmentSearch->FragmentSet, FragmentSearch->ShortestPathList);
3909 //Removal = StoreFragmentFromStack(out, FragmentSearch->Root, FragmentSearch->Leaflet, FragmentSearch->FragmentStack, FragmentSearch->ShortestPathList, &FragmentSearch->FragmentCounter, FragmentSearch->configuration);
3910 }
3911
3912 // --3-- remove all added items in this level from snake stack
3913 *out << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
3914 for(int j=0;j<TouchedIndex;j++) {
3915 Removal = TouchedList[j];
3916 *out << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
3917 FragmentSearch->FragmentSet->erase(Removal);
3918 TouchedList[j] = -1;
3919 }
3920 *out << Verbose(2) << "Remaining local nr.s on snake stack are: ";
3921 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
3922 *out << (*runner) << " ";
3923 *out << endl;
3924 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
3925 } else {
3926 *out << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
3927 }
3928 }
3929 Free((void **)&TouchedList, "molecule::SPFragmentGenerator: *TouchedList");
3930 *out << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
3931};
3932
3933/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
3934 * \param *out output stream for debugging
3935 * \param *Fragment Keyset of fragment's vertices
3936 * \return true - connected, false - disconnected
3937 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
3938 */
3939bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment)
3940{
3941 atom *Walker = NULL, *Walker2 = NULL;
3942 bool BondStatus = false;
3943 int size;
3944
3945 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
3946 *out << Verbose(2) << "Disconnected atom: ";
3947
3948 // count number of atoms in graph
3949 size = 0;
3950 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
3951 size++;
3952 if (size > 1)
3953 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
3954 Walker = FindAtom(*runner);
3955 BondStatus = false;
3956 for(KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
3957 Walker2 = FindAtom(*runners);
3958 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
3959 if (ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker) == Walker2) {
3960 BondStatus = true;
3961 break;
3962 }
3963 if (BondStatus)
3964 break;
3965 }
3966 }
3967 if (!BondStatus) {
3968 *out << (*Walker) << endl;
3969 return false;
3970 }
3971 }
3972 else {
3973 *out << "none." << endl;
3974 return true;
3975 }
3976 *out << "none." << endl;
3977
3978 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
3979
3980 return true;
3981}
3982
3983/** Creates a list of all unique fragments of certain vertex size from a given graph \a Fragment for a given root vertex in the context of \a this molecule.
3984 * -# initialises UniqueFragments structure
3985 * -# fills edge list via BFS
3986 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
3987 root distance, the edge set, its dimension and the current suborder
3988 * -# Free'ing structure
3989 * Note that we may use the fact that the atoms are SP-ordered on the atomstack. I.e. when popping always the last, we first get all
3990 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
3991 * \param *out output stream for debugging
3992 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
3993 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
3994 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
3995 * \return number of inserted fragments
3996 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
3997 */
3998int molecule::PowerSetGenerator(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
3999{
4000 int SP, AtomKeyNr;
4001 atom *Walker = NULL, *OtherWalker = NULL, *Predecessor = NULL;
4002 bond *Binder = NULL;
4003 bond *CurrentEdge = NULL;
4004 bond **BondsList = NULL;
4005 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->nr;
4006 int Counter = FragmentSearch.FragmentCounter;
4007 int RemainingWalkers;
4008
4009 *out << endl;
4010 *out << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl;
4011
4012 // prepare Label and SP arrays of the BFS search
4013 FragmentSearch.ShortestPathList[FragmentSearch.Root->nr] = 0;
4014
4015 // prepare root level (SP = 0) and a loop bond denoting Root
4016 for (int i=1;i<Order;i++)
4017 FragmentSearch.BondsPerSPCount[i] = 0;
4018 FragmentSearch.BondsPerSPCount[0] = 1;
4019 Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
4020 add(Binder, FragmentSearch.BondsPerSPList[1]);
4021
4022 // do a BFS search to fill the SP lists and label the found vertices
4023 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into
4024 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning
4025 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth
4026 // (EdgeinSPLevel) of this tree ...
4027 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence
4028 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction.
4029 *out << endl;
4030 *out << Verbose(0) << "Starting BFS analysis ..." << endl;
4031 for (SP = 0; SP < (Order-1); SP++) {
4032 *out << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)";
4033 if (SP > 0) {
4034 *out << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl;
4035 FragmentSearch.BondsPerSPCount[SP] = 0;
4036 } else
4037 *out << "." << endl;
4038
4039 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
4040 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP]; /// start of this SP level's list
4041 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) { /// end of this SP level's list
4042 CurrentEdge = CurrentEdge->next;
4043 RemainingWalkers--;
4044 Walker = CurrentEdge->rightatom; // rightatom is always the one more distant
4045 Predecessor = CurrentEdge->leftatom; // ... and leftatom is predecessor
4046 AtomKeyNr = Walker->nr;
4047 *out << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl;
4048 // check for new sp level
4049 // go through all its bonds
4050 *out << Verbose(1) << "Going through all bonds of Walker." << endl;
4051 for (int i=0;i<NumberOfBondsPerAtom[AtomKeyNr];i++) {
4052 Binder = ListOfBondsPerAtom[AtomKeyNr][i];
4053 OtherWalker = Binder->GetOtherAtom(Walker);
4054 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end())
4055 #ifdef ADDHYDROGEN
4056 && (OtherWalker->type->Z != 1)
4057 #endif
4058 ) { // skip hydrogens and restrict to fragment
4059 *out << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *Binder << "." << endl;
4060 // set the label if not set (and push on root stack as well)
4061 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->nr > RootKeyNr)) { // only pass through those with label bigger than Root's
4062 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1;
4063 *out << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl;
4064 // add the bond in between to the SP list
4065 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
4066 add(Binder, FragmentSearch.BondsPerSPList[2*(SP+1)+1]);
4067 FragmentSearch.BondsPerSPCount[SP+1]++;
4068 *out << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl;
4069 } else {
4070 if (OtherWalker != Predecessor)
4071 *out << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->nr << " is smaller than that of Root " << RootKeyNr << "." << endl;
4072 else
4073 *out << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl;
4074 }
4075 } else *out << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
4076 }
4077 }
4078 }
4079
4080 // outputting all list for debugging
4081 *out << Verbose(0) << "Printing all found lists." << endl;
4082 for(int i=1;i<Order;i++) { // skip the root edge in the printing
4083 Binder = FragmentSearch.BondsPerSPList[2*i];
4084 *out << Verbose(1) << "Current SP level is " << i << "." << endl;
4085 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4086 Binder = Binder->next;
4087 *out << Verbose(2) << *Binder << endl;
4088 }
4089 }
4090
4091 // creating fragments with the found edge sets (may be done in reverse order, faster)
4092 SP = -1; // the Root <-> Root edge must be subtracted!
4093 for(int i=Order;i--;) { // sum up all found edges
4094 Binder = FragmentSearch.BondsPerSPList[2*i];
4095 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4096 Binder = Binder->next;
4097 SP ++;
4098 }
4099 }
4100 *out << Verbose(0) << "Total number of edges is " << SP << "." << endl;
4101 if (SP >= (Order-1)) {
4102 // start with root (push on fragment stack)
4103 *out << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->nr << "." << endl;
4104 FragmentSearch.FragmentSet->clear();
4105 *out << Verbose(0) << "Preparing subset for this root and calling generator." << endl;
4106 // prepare the subset and call the generator
4107 BondsList = (bond **) Malloc(sizeof(bond *)*FragmentSearch.BondsPerSPCount[0], "molecule::PowerSetGenerator: **BondsList");
4108 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond
4109
4110 SPFragmentGenerator(out, &FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
4111
4112 Free((void **)&BondsList, "molecule::PowerSetGenerator: **BondsList");
4113 } else {
4114 *out << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl;
4115 }
4116
4117 // as FragmentSearch structure is used only once, we don't have to clean it anymore
4118 // remove root from stack
4119 *out << Verbose(0) << "Removing root again from stack." << endl;
4120 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr);
4121
4122 // free'ing the bonds lists
4123 *out << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl;
4124 for(int i=Order;i--;) {
4125 *out << Verbose(1) << "Current SP level is " << i << ": ";
4126 Binder = FragmentSearch.BondsPerSPList[2*i];
4127 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4128 Binder = Binder->next;
4129 // *out << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local
4130 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1;
4131 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1;
4132 }
4133 // delete added bonds
4134 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]);
4135 // also start and end node
4136 *out << "cleaned." << endl;
4137 }
4138
4139 // return list
4140 *out << Verbose(0) << "End of PowerSetGenerator." << endl;
4141 return (FragmentSearch.FragmentCounter - Counter);
4142};
4143
4144/** Corrects the nuclei position if the fragment was created over the cell borders.
4145 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
4146 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
4147 * and re-add the bond. Looping on the distance check.
4148 * \param *out ofstream for debugging messages
4149 */
4150void molecule::ScanForPeriodicCorrection(ofstream *out)
4151{
4152 bond *Binder = NULL;
4153 bond *OtherBinder = NULL;
4154 atom *Walker = NULL;
4155 atom *OtherWalker = NULL;
4156 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
4157 enum Shading *ColorList = NULL;
4158 double tmp;
4159 Vector Translationvector;
4160 //class StackClass<atom *> *CompStack = NULL;
4161 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
4162 bool flag = true;
4163
4164 *out << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl;
4165
4166 ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::ScanForPeriodicCorrection: *ColorList");
4167 while (flag) {
4168 // remove bonds that are beyond bonddistance
4169 for(int i=NDIM;i--;)
4170 Translationvector.x[i] = 0.;
4171 // scan all bonds
4172 Binder = first;
4173 flag = false;
4174 while ((!flag) && (Binder->next != last)) {
4175 Binder = Binder->next;
4176 for (int i=NDIM;i--;) {
4177 tmp = fabs(Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]);
4178 //*out << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
4179 if (tmp > BondDistance) {
4180 OtherBinder = Binder->next; // note down binding partner for later re-insertion
4181 unlink(Binder); // unlink bond
4182 *out << Verbose(2) << "Correcting at bond " << *Binder << "." << endl;
4183 flag = true;
4184 break;
4185 }
4186 }
4187 }
4188 if (flag) {
4189 // create translation vector from their periodically modified distance
4190 for (int i=NDIM;i--;) {
4191 tmp = Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i];
4192 if (fabs(tmp) > BondDistance)
4193 Translationvector.x[i] = (tmp < 0) ? +1. : -1.;
4194 }
4195 Translationvector.MatrixMultiplication(matrix);
4196 //*out << Verbose(3) << "Translation vector is ";
4197 Translationvector.Output(out);
4198 *out << endl;
4199 // apply to all atoms of first component via BFS
4200 for (int i=AtomCount;i--;)
4201 ColorList[i] = white;
4202 AtomStack->Push(Binder->leftatom);
4203 while (!AtomStack->IsEmpty()) {
4204 Walker = AtomStack->PopFirst();
4205 //*out << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
4206 ColorList[Walker->nr] = black; // mark as explored
4207 Walker->x.AddVector(&Translationvector); // translate
4208 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through all binding partners
4209 if (ListOfBondsPerAtom[Walker->nr][i] != Binder) {
4210 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
4211 if (ColorList[OtherWalker->nr] == white) {
4212 AtomStack->Push(OtherWalker); // push if yet unexplored
4213 }
4214 }
4215 }
4216 }
4217 // re-add bond
4218 link(Binder, OtherBinder);
4219 } else {
4220 *out << Verbose(3) << "No corrections for this fragment." << endl;
4221 }
4222 //delete(CompStack);
4223 }
4224
4225 // free allocated space from ReturnFullMatrixforSymmetric()
4226 delete(AtomStack);
4227 Free((void **)&ColorList, "molecule::ScanForPeriodicCorrection: *ColorList");
4228 Free((void **)&matrix, "molecule::ScanForPeriodicCorrection: *matrix");
4229 *out << Verbose(2) << "End of ScanForPeriodicCorrection." << endl;
4230};
4231
4232/** Blows the 6-dimensional \a cell_size array up to a full NDIM by NDIM matrix.
4233 * \param *symm 6-dim array of unique symmetric matrix components
4234 * \return allocated NDIM*NDIM array with the symmetric matrix
4235 */
4236double * molecule::ReturnFullMatrixforSymmetric(double *symm)
4237{
4238 double *matrix = (double *) Malloc(sizeof(double)*NDIM*NDIM, "molecule::ReturnFullMatrixforSymmetric: *matrix");
4239 matrix[0] = symm[0];
4240 matrix[1] = symm[1];
4241 matrix[2] = symm[3];
4242 matrix[3] = symm[1];
4243 matrix[4] = symm[2];
4244 matrix[5] = symm[4];
4245 matrix[6] = symm[3];
4246 matrix[7] = symm[4];
4247 matrix[8] = symm[5];
4248 return matrix;
4249};
4250
4251bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
4252{
4253 //cout << "my check is used." << endl;
4254 if (SubgraphA.size() < SubgraphB.size()) {
4255 return true;
4256 } else {
4257 if (SubgraphA.size() > SubgraphB.size()) {
4258 return false;
4259 } else {
4260 KeySet::iterator IteratorA = SubgraphA.begin();
4261 KeySet::iterator IteratorB = SubgraphB.begin();
4262 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
4263 if ((*IteratorA) < (*IteratorB))
4264 return true;
4265 else if ((*IteratorA) > (*IteratorB)) {
4266 return false;
4267 } // else, go on to next index
4268 IteratorA++;
4269 IteratorB++;
4270 } // end of while loop
4271 }// end of check in case of equal sizes
4272 }
4273 return false; // if we reach this point, they are equal
4274};
4275
4276//bool operator < (KeySet SubgraphA, KeySet SubgraphB)
4277//{
4278// return KeyCompare(SubgraphA, SubgraphB);
4279//};
4280
4281/** Checking whether KeySet is not already present in Graph, if so just adds factor.
4282 * \param *out output stream for debugging
4283 * \param &set KeySet to insert
4284 * \param &graph Graph to insert into
4285 * \param *counter pointer to unique fragment count
4286 * \param factor energy factor for the fragment
4287 */
4288inline void InsertFragmentIntoGraph(ofstream *out, struct UniqueFragments *Fragment)
4289{
4290 GraphTestPair testGraphInsert;
4291
4292 testGraphInsert = Fragment->Leaflet->insert(GraphPair (*Fragment->FragmentSet,pair<int,double>(Fragment->FragmentCounter,Fragment->TEFactor))); // store fragment number and current factor
4293 if (testGraphInsert.second) {
4294 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " successfully inserted." << endl;
4295 Fragment->FragmentCounter++;
4296 } else {
4297 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
4298 ((*(testGraphInsert.first)).second).second += Fragment->TEFactor; // increase the "created" counter
4299 *out << Verbose(2) << "New factor is " << ((*(testGraphInsert.first)).second).second << "." << endl;
4300 }
4301};
4302//void inline InsertIntoGraph(ofstream *out, KeyStack &stack, Graph &graph, int *counter, double factor)
4303//{
4304// // copy stack contents to set and call overloaded function again
4305// KeySet set;
4306// for(KeyStack::iterator runner = stack.begin(); runner != stack.begin(); runner++)
4307// set.insert((*runner));
4308// InsertIntoGraph(out, set, graph, counter, factor);
4309//};
4310
4311/** Inserts each KeySet in \a graph2 into \a graph1.
4312 * \param *out output stream for debugging
4313 * \param graph1 first (dest) graph
4314 * \param graph2 second (source) graph
4315 * \param *counter keyset counter that gets increased
4316 */
4317inline void InsertGraphIntoGraph(ofstream *out, Graph &graph1, Graph &graph2, int *counter)
4318{
4319 GraphTestPair testGraphInsert;
4320
4321 for(Graph::iterator runner = graph2.begin(); runner != graph2.end(); runner++) {
4322 testGraphInsert = graph1.insert(GraphPair ((*runner).first,pair<int,double>((*counter)++,((*runner).second).second))); // store fragment number and current factor
4323 if (testGraphInsert.second) {
4324 *out << Verbose(2) << "KeySet " << (*counter)-1 << " successfully inserted." << endl;
4325 } else {
4326 *out << Verbose(2) << "KeySet " << (*counter)-1 << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
4327 ((*(testGraphInsert.first)).second).second += (*runner).second.second;
4328 *out << Verbose(2) << "New factor is " << (*(testGraphInsert.first)).second.second << "." << endl;
4329 }
4330 }
4331};
4332
4333
4334/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
4335 * -# constructs a complete keyset of the molecule
4336 * -# In a loop over all possible roots from the given rootstack
4337 * -# increases order of root site
4338 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
4339 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
4340as the restricted one and each site in the set as the root)
4341 * -# these are merged into a fragment list of keysets
4342 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
4343 * Important only is that we create all fragments, it is not important if we create them more than once
4344 * as these copies are filtered out via use of the hash table (KeySet).
4345 * \param *out output stream for debugging
4346 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
4347 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
4348 * \param *MinimumRingSize minimum ring size for each atom (molecule::Atomcount)
4349 * \return pointer to Graph list
4350 */
4351void molecule::FragmentBOSSANOVA(ofstream *out, Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize)
4352{
4353 Graph ***FragmentLowerOrdersList = NULL;
4354 int NumLevels, NumMolecules, TotalNumMolecules = 0, *NumMoleculesOfOrder = NULL;
4355 int counter = 0, Order;
4356 int UpgradeCount = RootStack.size();
4357 KeyStack FragmentRootStack;
4358 int RootKeyNr, RootNr;
4359 struct UniqueFragments FragmentSearch;
4360
4361 *out << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl;
4362
4363 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
4364 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
4365 NumMoleculesOfOrder = (int *) Malloc(sizeof(int)*UpgradeCount, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
4366 FragmentLowerOrdersList = (Graph ***) Malloc(sizeof(Graph **)*UpgradeCount, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
4367
4368 // initialise the fragments structure
4369 FragmentSearch.ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *ShortestPathList");
4370 FragmentSearch.FragmentCounter = 0;
4371 FragmentSearch.FragmentSet = new KeySet;
4372 FragmentSearch.Root = FindAtom(RootKeyNr);
4373 for (int i=AtomCount;i--;) {
4374 FragmentSearch.ShortestPathList[i] = -1;
4375 }
4376
4377 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
4378 atom *Walker = start;
4379 KeySet CompleteMolecule;
4380 while (Walker->next != end) {
4381 Walker = Walker->next;
4382 CompleteMolecule.insert(Walker->GetTrueFather()->nr);
4383 }
4384
4385 // this can easily be seen: if Order is 5, then the number of levels for each lower order is the total sum of the number of levels above, as
4386 // each has to be split up. E.g. for the second level we have one from 5th, one from 4th, two from 3th (which in turn is one from 5th, one from 4th),
4387 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
4388 // with the order along the cells as this: 5433222211111111 for BondOrder 5 needing 16=pow(2,5-1) cells (only we use bit-shifting which is faster)
4389 RootNr = 0; // counts through the roots in RootStack
4390 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
4391 RootKeyNr = RootStack.front();
4392 RootStack.pop_front();
4393 Walker = FindAtom(RootKeyNr);
4394 // check cyclic lengths
4395 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) {
4396 // *out << Verbose(0) << "Bond order " << Walker->GetTrueFather()->AdaptiveOrder << " of Root " << *Walker << " greater than or equal to Minimum Ring size of " << MinimumRingSize << " found is not allowed." << endl;
4397 //} else
4398 {
4399 // increase adaptive order by one
4400 Walker->GetTrueFather()->AdaptiveOrder++;
4401 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
4402
4403 // initialise Order-dependent entries of UniqueFragments structure
4404 FragmentSearch.BondsPerSPList = (bond **) Malloc(sizeof(bond *)*Order*2, "molecule::PowerSetGenerator: ***BondsPerSPList");
4405 FragmentSearch.BondsPerSPCount = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *BondsPerSPCount");
4406 for (int i=Order;i--;) {
4407 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node
4408 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node
4409 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two
4410 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i];
4411 FragmentSearch.BondsPerSPCount[i] = 0;
4412 }
4413
4414 // allocate memory for all lower level orders in this 1D-array of ptrs
4415 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
4416 FragmentLowerOrdersList[RootNr] = (Graph **) Malloc(sizeof(Graph *)*NumLevels, "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
4417 for (int i=0;i<NumLevels;i++)
4418 FragmentLowerOrdersList[RootNr][i] = NULL;
4419
4420 // create top order where nothing is reduced
4421 *out << Verbose(0) << "==============================================================================================================" << endl;
4422 *out << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl; // , NumLevels is " << NumLevels << "
4423
4424 // Create list of Graphs of current Bond Order (i.e. F_{ij})
4425 FragmentLowerOrdersList[RootNr][0] = new Graph;
4426 FragmentSearch.TEFactor = 1.;
4427 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
4428 FragmentSearch.Root = Walker;
4429 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(out, Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
4430 *out << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
4431 if (NumMoleculesOfOrder[RootNr] != 0) {
4432 NumMolecules = 0;
4433
4434 // we don't have to dive into suborders! These keysets are all already created on lower orders!
4435 // this was all ancient stuff, when we still depended on the TEFactors (and for those the suborders were needed)
4436
4437// if ((NumLevels >> 1) > 0) {
4438// // create lower order fragments
4439// *out << Verbose(0) << "Creating list of unique fragments of lower Bond Order terms to be subtracted." << endl;
4440// Order = Walker->AdaptiveOrder;
4441// for (int source=0;source<(NumLevels >> 1);source++) { // 1-terms don't need any more splitting, that's why only half is gone through (shift again)
4442// // step down to next order at (virtual) boundary of powers of 2 in array
4443// while (source >= (1 << (Walker->AdaptiveOrder-Order))) // (int)pow(2,Walker->AdaptiveOrder-Order))
4444// Order--;
4445// *out << Verbose(0) << "Current Order is: " << Order << "." << endl;
4446// for (int SubOrder=Order-1;SubOrder>0;SubOrder--) {
4447// int dest = source + (1 << (Walker->AdaptiveOrder-(SubOrder+1)));
4448// *out << Verbose(0) << "--------------------------------------------------------------------------------------------------------------" << endl;
4449// *out << Verbose(0) << "Current SubOrder is: " << SubOrder << " with source " << source << " to destination " << dest << "." << endl;
4450//
4451// // every molecule is split into a list of again (Order - 1) molecules, while counting all molecules
4452// //*out << Verbose(1) << "Splitting the " << (*FragmentLowerOrdersList[RootNr][source]).size() << " molecules of the " << source << "th cell in the array." << endl;
4453// //NumMolecules = 0;
4454// FragmentLowerOrdersList[RootNr][dest] = new Graph;
4455// for(Graph::iterator runner = (*FragmentLowerOrdersList[RootNr][source]).begin();runner != (*FragmentLowerOrdersList[RootNr][source]).end(); runner++) {
4456// for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
4457// Graph TempFragmentList;
4458// FragmentSearch.TEFactor = -(*runner).second.second;
4459// FragmentSearch.Leaflet = &TempFragmentList; // set to insertion graph
4460// FragmentSearch.Root = FindAtom(*sprinter);
4461// NumMoleculesOfOrder[RootNr] += PowerSetGenerator(out, SubOrder, FragmentSearch, (*runner).first);
4462// // insert new keysets FragmentList into FragmentLowerOrdersList[Walker->AdaptiveOrder-1][dest]
4463// *out << Verbose(1) << "Merging resulting key sets with those present in destination " << dest << "." << endl;
4464// InsertGraphIntoGraph(out, *FragmentLowerOrdersList[RootNr][dest], TempFragmentList, &NumMolecules);
4465// }
4466// }
4467// *out << Verbose(1) << "Number of resulting molecules for SubOrder " << SubOrder << " is: " << NumMolecules << "." << endl;
4468// }
4469// }
4470// }
4471 } else {
4472 Walker->GetTrueFather()->MaxOrder = true;
4473// *out << Verbose(1) << "Hence, we don't dive into SubOrders ... " << endl;
4474 }
4475 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
4476 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
4477 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
4478// *out << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
4479 RootStack.push_back(RootKeyNr); // put back on stack
4480 RootNr++;
4481
4482 // free Order-dependent entries of UniqueFragments structure for next loop cycle
4483 Free((void **)&FragmentSearch.BondsPerSPCount, "molecule::PowerSetGenerator: *BondsPerSPCount");
4484 for (int i=Order;i--;) {
4485 delete(FragmentSearch.BondsPerSPList[2*i]);
4486 delete(FragmentSearch.BondsPerSPList[2*i+1]);
4487 }
4488 Free((void **)&FragmentSearch.BondsPerSPList, "molecule::PowerSetGenerator: ***BondsPerSPList");
4489 }
4490 }
4491 *out << Verbose(0) << "==============================================================================================================" << endl;
4492 *out << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl;
4493 *out << Verbose(0) << "==============================================================================================================" << endl;
4494
4495 // cleanup FragmentSearch structure
4496 Free((void **)&FragmentSearch.ShortestPathList, "molecule::PowerSetGenerator: *ShortestPathList");
4497 delete(FragmentSearch.FragmentSet);
4498
4499 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
4500 // 5433222211111111
4501 // 43221111
4502 // 3211
4503 // 21
4504 // 1
4505
4506 // Subsequently, we combine all into a single list (FragmentList)
4507
4508 *out << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl;
4509 if (FragmentList == NULL) {
4510 FragmentList = new Graph;
4511 counter = 0;
4512 } else {
4513 counter = FragmentList->size();
4514 }
4515 RootNr = 0;
4516 while (!RootStack.empty()) {
4517 RootKeyNr = RootStack.front();
4518 RootStack.pop_front();
4519 Walker = FindAtom(RootKeyNr);
4520 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
4521 for(int i=0;i<NumLevels;i++) {
4522 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
4523 InsertGraphIntoGraph(out, *FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
4524 delete(FragmentLowerOrdersList[RootNr][i]);
4525 }
4526 }
4527 Free((void **)&FragmentLowerOrdersList[RootNr], "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
4528 RootNr++;
4529 }
4530 Free((void **)&FragmentLowerOrdersList, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
4531 Free((void **)&NumMoleculesOfOrder, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
4532
4533 *out << Verbose(0) << "End of FragmentBOSSANOVA." << endl;
4534};
4535
4536/** Comparison function for GSL heapsort on distances in two molecules.
4537 * \param *a
4538 * \param *b
4539 * \return <0, \a *a less than \a *b, ==0 if equal, >0 \a *a greater than \a *b
4540 */
4541inline int CompareDoubles (const void * a, const void * b)
4542{
4543 if (*(double *)a > *(double *)b)
4544 return -1;
4545 else if (*(double *)a < *(double *)b)
4546 return 1;
4547 else
4548 return 0;
4549};
4550
4551/** Determines whether two molecules actually contain the same atoms and coordination.
4552 * \param *out output stream for debugging
4553 * \param *OtherMolecule the molecule to compare this one to
4554 * \param threshold upper limit of difference when comparing the coordination.
4555 * \return NULL - not equal, otherwise an allocated (molecule::AtomCount) permutation map of the atom numbers (which corresponds to which)
4556 */
4557int * molecule::IsEqualToWithinThreshold(ofstream *out, molecule *OtherMolecule, double threshold)
4558{
4559 int flag;
4560 double *Distances = NULL, *OtherDistances = NULL;
4561 Vector CenterOfGravity, OtherCenterOfGravity;
4562 size_t *PermMap = NULL, *OtherPermMap = NULL;
4563 int *PermutationMap = NULL;
4564 atom *Walker = NULL;
4565 bool result = true; // status of comparison
4566
4567 *out << Verbose(3) << "Begin of IsEqualToWithinThreshold." << endl;
4568 /// first count both their atoms and elements and update lists thereby ...
4569 //*out << Verbose(0) << "Counting atoms, updating list" << endl;
4570 CountAtoms(out);
4571 OtherMolecule->CountAtoms(out);
4572 CountElements();
4573 OtherMolecule->CountElements();
4574
4575 /// ... and compare:
4576 /// -# AtomCount
4577 if (result) {
4578 if (AtomCount != OtherMolecule->AtomCount) {
4579 *out << Verbose(4) << "AtomCounts don't match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
4580 result = false;
4581 } else *out << Verbose(4) << "AtomCounts match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
4582 }
4583 /// -# ElementCount
4584 if (result) {
4585 if (ElementCount != OtherMolecule->ElementCount) {
4586 *out << Verbose(4) << "ElementCount don't match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
4587 result = false;
4588 } else *out << Verbose(4) << "ElementCount match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
4589 }
4590 /// -# ElementsInMolecule
4591 if (result) {
4592 for (flag=MAX_ELEMENTS;flag--;) {
4593 //*out << Verbose(5) << "Element " << flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl;
4594 if (ElementsInMolecule[flag] != OtherMolecule->ElementsInMolecule[flag])
4595 break;
4596 }
4597 if (flag < MAX_ELEMENTS) {
4598 *out << Verbose(4) << "ElementsInMolecule don't match." << endl;
4599 result = false;
4600 } else *out << Verbose(4) << "ElementsInMolecule match." << endl;
4601 }
4602 /// then determine and compare center of gravity for each molecule ...
4603 if (result) {
4604 *out << Verbose(5) << "Calculating Centers of Gravity" << endl;
4605 DetermineCenter(CenterOfGravity);
4606 OtherMolecule->DetermineCenter(OtherCenterOfGravity);
4607 *out << Verbose(5) << "Center of Gravity: ";
4608 CenterOfGravity.Output(out);
4609 *out << endl << Verbose(5) << "Other Center of Gravity: ";
4610 OtherCenterOfGravity.Output(out);
4611 *out << endl;
4612 if (CenterOfGravity.Distance(&OtherCenterOfGravity) > threshold) {
4613 *out << Verbose(4) << "Centers of gravity don't match." << endl;
4614 result = false;
4615 }
4616 }
4617
4618 /// ... then make a list with the euclidian distance to this center for each atom of both molecules
4619 if (result) {
4620 *out << Verbose(5) << "Calculating distances" << endl;
4621 Distances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: Distances");
4622 OtherDistances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: OtherDistances");
4623 Walker = start;
4624 while (Walker->next != end) {
4625 Walker = Walker->next;
4626 Distances[Walker->nr] = CenterOfGravity.Distance(&Walker->x);
4627 }
4628 Walker = OtherMolecule->start;
4629 while (Walker->next != OtherMolecule->end) {
4630 Walker = Walker->next;
4631 OtherDistances[Walker->nr] = OtherCenterOfGravity.Distance(&Walker->x);
4632 }
4633
4634 /// ... sort each list (using heapsort (o(N log N)) from GSL)
4635 *out << Verbose(5) << "Sorting distances" << endl;
4636 PermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermMap");
4637 OtherPermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
4638 gsl_heapsort_index (PermMap, Distances, AtomCount, sizeof(double), CompareDoubles);
4639 gsl_heapsort_index (OtherPermMap, OtherDistances, AtomCount, sizeof(double), CompareDoubles);
4640 PermutationMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermutationMap");
4641 *out << Verbose(5) << "Combining Permutation Maps" << endl;
4642 for(int i=AtomCount;i--;)
4643 PermutationMap[PermMap[i]] = (int) OtherPermMap[i];
4644
4645 /// ... and compare them step by step, whether the difference is individiually(!) below \a threshold for all
4646 *out << Verbose(4) << "Comparing distances" << endl;
4647 flag = 0;
4648 for (int i=0;i<AtomCount;i++) {
4649 *out << Verbose(5) << "Distances: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " << threshold << endl;
4650 if (fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) > threshold)
4651 flag = 1;
4652 }
4653 Free((void **)&PermMap, "molecule::IsEqualToWithinThreshold: *PermMap");
4654 Free((void **)&OtherPermMap, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
4655
4656 /// free memory
4657 Free((void **)&Distances, "molecule::IsEqualToWithinThreshold: Distances");
4658 Free((void **)&OtherDistances, "molecule::IsEqualToWithinThreshold: OtherDistances");
4659 if (flag) { // if not equal
4660 Free((void **)&PermutationMap, "molecule::IsEqualToWithinThreshold: *PermutationMap");
4661 result = false;
4662 }
4663 }
4664 /// return pointer to map if all distances were below \a threshold
4665 *out << Verbose(3) << "End of IsEqualToWithinThreshold." << endl;
4666 if (result) {
4667 *out << Verbose(3) << "Result: Equal." << endl;
4668 return PermutationMap;
4669 } else {
4670 *out << Verbose(3) << "Result: Not equal." << endl;
4671 return NULL;
4672 }
4673};
4674
4675/** Returns an index map for two father-son-molecules.
4676 * The map tells which atom in this molecule corresponds to which one in the other molecul with their fathers.
4677 * \param *out output stream for debugging
4678 * \param *OtherMolecule corresponding molecule with fathers
4679 * \return allocated map of size molecule::AtomCount with map
4680 * \todo make this with a good sort O(n), not O(n^2)
4681 */
4682int * molecule::GetFatherSonAtomicMap(ofstream *out, molecule *OtherMolecule)
4683{
4684 atom *Walker = NULL, *OtherWalker = NULL;
4685 *out << Verbose(3) << "Begin of GetFatherAtomicMap." << endl;
4686 int *AtomicMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::GetAtomicMap: *AtomicMap"); //Calloc
4687 for (int i=AtomCount;i--;)
4688 AtomicMap[i] = -1;
4689 if (OtherMolecule == this) { // same molecule
4690 for (int i=AtomCount;i--;) // no need as -1 means already that there is trivial correspondence
4691 AtomicMap[i] = i;
4692 *out << Verbose(4) << "Map is trivial." << endl;
4693 } else {
4694 *out << Verbose(4) << "Map is ";
4695 Walker = start;
4696 while (Walker->next != end) {
4697 Walker = Walker->next;
4698 if (Walker->father == NULL) {
4699 AtomicMap[Walker->nr] = -2;
4700 } else {
4701 OtherWalker = OtherMolecule->start;
4702 while (OtherWalker->next != OtherMolecule->end) {
4703 OtherWalker = OtherWalker->next;
4704 //for (int i=0;i<AtomCount;i++) { // search atom
4705 //for (int j=0;j<OtherMolecule->AtomCount;j++) {
4706 //*out << Verbose(4) << "Comparing father " << Walker->father << " with the other one " << OtherWalker->father << "." << endl;
4707 if (Walker->father == OtherWalker)
4708 AtomicMap[Walker->nr] = OtherWalker->nr;
4709 }
4710 }
4711 *out << AtomicMap[Walker->nr] << "\t";
4712 }
4713 *out << endl;
4714 }
4715 *out << Verbose(3) << "End of GetFatherAtomicMap." << endl;
4716 return AtomicMap;
4717};
4718
4719/** Stores the temperature evaluated from velocities in molecule::Trajectories.
4720 * We simply use the formula equivaleting temperature and kinetic energy:
4721 * \f$k_B T = \sum_i m_i v_i^2\f$
4722 * \param *out output stream for debugging
4723 * \param startstep first MD step in molecule::Trajectories
4724 * \param endstep last plus one MD step in molecule::Trajectories
4725 * \param *output output stream of temperature file
4726 * \return file written (true), failure on writing file (false)
4727 */
4728bool molecule::OutputTemperatureFromTrajectories(ofstream *out, int startstep, int endstep, ofstream *output)
4729{
4730 double temperature;
4731 atom *Walker = NULL;
4732 // test stream
4733 if (output == NULL)
4734 return false;
4735 else
4736 *output << "# Step Temperature [K] Temperature [a.u.]" << endl;
4737 for (int step=startstep;step < endstep; step++) { // loop over all time steps
4738 temperature = 0.;
4739 Walker = start;
4740 while (Walker->next != end) {
4741 Walker = Walker->next;
4742 for (int i=NDIM;i--;)
4743 temperature += Walker->type->mass * Trajectories[Walker].U.at(step).x[i]* Trajectories[Walker].U.at(step).x[i];
4744 }
4745 *output << step << "\t" << temperature*AtomicEnergyToKelvin << "\t" << temperature << endl;
4746 }
4747 return true;
4748};
Note: See TracBrowser for help on using the repository browser.