source: src/molecules.cpp@ 41f151

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 Candidate_v1.7.0 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 41f151 was 41f151, checked in by Frederik Heber <heber@…>, 17 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: 237.2 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/** Evaluates the potential energy used for constrained molecular dynamics.
1010 * \f$V_i^{con} = c^{bond} \cdot | r_{P(i)} - R_i | + sum_{i \neq j} C^{min} \cdot \frac{1}{C_{ij}} + C^{inj} \Bigl (1 - \theta \bigl (\prod_{i \neq j} (P(i) - P(j)) \bigr ) \Bigr )\f$
1011 * where the first term points to the target in minimum distance, the second is a penalty for trajectories lying too close to each other (\f$C_{ij}$ is minimum distance between
1012 * trajectories i and j) and the third term is a penalty for two atoms trying to each the same target point.
1013 * Note that for the second term we have to solve the following linear system:
1014 * \f$-c_1 \cdot n_1 + c_2 \cdot n_2 + C \cdot n_3 = - p_2 + p_1\f$, where \f$c_1\f$, \f$c_2\f$ and \f$C\f$ are constants,
1015 * offset vector \f$p_1\f$ in direction \f$n_1\f$, offset vector \f$p_2\f$ in direction \f$n_2\f$,
1016 * \f$n_3\f$ is the normal vector to both directions. \f$C\f$ would be the minimum distance between the two lines.
1017 * \sa molecule::MinimiseConstrainedPotential(), molecule::VerletForceIntegration()
1018 * \param *out output stream for debugging
1019 * \param *PermutationMap gives target ptr for each atom, array of size molecule::AtomCount (this is "x" in \f$V^{con}(x)\f$)
1020 * \param startstep start configuration (MDStep in molecule::trajectories)
1021 * \param endstep end configuration (MDStep in molecule::trajectories)
1022 * \param *constants constant in front of each term
1023 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false)
1024 * \return potential energy
1025 * \note This routine is scaling quadratically which is not optimal.
1026 * \todo There's a bit double counting going on for the first time, bu nothing to worry really about.
1027 */
1028double molecule::ConstrainedPotential(ofstream *out, atom **PermutationMap, int startstep, int endstep, double *constants, bool IsAngstroem)
1029{
1030 double result = 0., tmp, Norm1, Norm2;
1031 atom *Walker = NULL, *Runner = NULL, *Sprinter = NULL;
1032 Vector trajectory1, trajectory2, normal, TestVector;
1033 gsl_matrix *A = gsl_matrix_alloc(NDIM,NDIM);
1034 gsl_vector *x = gsl_vector_alloc(NDIM);
1035
1036 // go through every atom
1037 Walker = start;
1038 while (Walker->next != end) {
1039 Walker = Walker->next;
1040 // first term: distance to target
1041 Runner = PermutationMap[Walker->nr]; // find target point
1042 tmp = (Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(endstep)));
1043 tmp *= IsAngstroem ? 1. : 1./AtomicLengthToAngstroem;
1044 result += constants[0] * tmp;
1045 //*out << Verbose(4) << "Adding " << tmp*constants[0] << "." << endl;
1046
1047 // second term: sum of distances to other trajectories
1048 Runner = start;
1049 while (Runner->next != end) {
1050 Runner = Runner->next;
1051 if (Runner == Walker) // hence, we only go up to the Walker, not beyond (similar to i=0; i<j; i++)
1052 break;
1053 // determine normalized trajectories direction vector (n1, n2)
1054 Sprinter = PermutationMap[Walker->nr]; // find first target point
1055 trajectory1.CopyVector(&Trajectories[Sprinter].R.at(endstep));
1056 trajectory1.SubtractVector(&Trajectories[Walker].R.at(startstep));
1057 trajectory1.Normalize();
1058 Norm1 = trajectory1.Norm();
1059 Sprinter = PermutationMap[Runner->nr]; // find second target point
1060 trajectory2.CopyVector(&Trajectories[Sprinter].R.at(endstep));
1061 trajectory2.SubtractVector(&Trajectories[Runner].R.at(startstep));
1062 trajectory2.Normalize();
1063 Norm2 = trajectory1.Norm();
1064 // check whether either is zero()
1065 if ((Norm1 < MYEPSILON) && (Norm2 < MYEPSILON)) {
1066 tmp = Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(startstep));
1067 } else if (Norm1 < MYEPSILON) {
1068 Sprinter = PermutationMap[Walker->nr]; // find first target point
1069 trajectory1.CopyVector(&Trajectories[Sprinter].R.at(endstep)); // copy first offset
1070 trajectory1.SubtractVector(&Trajectories[Runner].R.at(startstep)); // subtract second offset
1071 trajectory2.Scale( trajectory1.ScalarProduct(&trajectory2) ); // trajectory2 is scaled to unity, hence we don't need to divide by anything
1072 trajectory1.SubtractVector(&trajectory2); // project the part in norm direction away
1073 tmp = trajectory1.Norm(); // remaining norm is distance
1074 } else if (Norm2 < MYEPSILON) {
1075 Sprinter = PermutationMap[Runner->nr]; // find second target point
1076 trajectory2.CopyVector(&Trajectories[Sprinter].R.at(endstep)); // copy second offset
1077 trajectory2.SubtractVector(&Trajectories[Walker].R.at(startstep)); // subtract first offset
1078 trajectory1.Scale( trajectory2.ScalarProduct(&trajectory1) ); // trajectory1 is scaled to unity, hence we don't need to divide by anything
1079 trajectory2.SubtractVector(&trajectory1); // project the part in norm direction away
1080 tmp = trajectory2.Norm(); // remaining norm is distance
1081 } else if ((fabs(trajectory1.ScalarProduct(&trajectory2)/Norm1/Norm2) - 1.) < MYEPSILON) { // check whether they're linear dependent
1082// *out << Verbose(3) << "Both trajectories of " << *Walker << " and " << *Runner << " are linear dependent: ";
1083// *out << trajectory1;
1084// *out << " and ";
1085// *out << trajectory2;
1086 tmp = Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(startstep));
1087// *out << " with distance " << tmp << "." << endl;
1088 } else { // determine distance by finding minimum distance
1089// *out << Verbose(3) << "Both trajectories of " << *Walker << " and " << *Runner << " are linear independent ";
1090// *out << endl;
1091// *out << "First Trajectory: ";
1092// *out << trajectory1 << endl;
1093// *out << "Second Trajectory: ";
1094// *out << trajectory2 << endl;
1095 // determine normal vector for both
1096 normal.MakeNormalVector(&trajectory1, &trajectory2);
1097 // print all vectors for debugging
1098// *out << "Normal vector in between: ";
1099// *out << normal << endl;
1100 // setup matrix
1101 for (int i=NDIM;i--;) {
1102 gsl_matrix_set(A, 0, i, trajectory1.x[i]);
1103 gsl_matrix_set(A, 1, i, trajectory2.x[i]);
1104 gsl_matrix_set(A, 2, i, normal.x[i]);
1105 gsl_vector_set(x,i, (Trajectories[Walker].R.at(startstep).x[i] - Trajectories[Runner].R.at(startstep).x[i]));
1106 }
1107 // solve the linear system by Householder transformations
1108 gsl_linalg_HH_svx(A, x);
1109 // distance from last component
1110 tmp = gsl_vector_get(x,2);
1111// *out << " with distance " << tmp << "." << endl;
1112 // test whether we really have the intersection (by checking on c_1 and c_2)
1113 TestVector.CopyVector(&Trajectories[Runner].R.at(startstep));
1114 trajectory2.Scale(gsl_vector_get(x,1));
1115 TestVector.AddVector(&trajectory2);
1116 normal.Scale(gsl_vector_get(x,2));
1117 TestVector.AddVector(&normal);
1118 TestVector.SubtractVector(&Trajectories[Walker].R.at(startstep));
1119 trajectory1.Scale(gsl_vector_get(x,0));
1120 TestVector.SubtractVector(&trajectory1);
1121 if (TestVector.Norm() < MYEPSILON) {
1122// *out << Verbose(2) << "Test: ok.\tDistance of " << tmp << " is correct." << endl;
1123 } else {
1124// *out << Verbose(2) << "Test: failed.\tIntersection is off by ";
1125// *out << TestVector;
1126// *out << "." << endl;
1127 }
1128 }
1129 // add up
1130 tmp *= IsAngstroem ? 1. : 1./AtomicLengthToAngstroem;
1131 if (fabs(tmp) > MYEPSILON) {
1132 result += constants[1] * 1./tmp;
1133 //*out << Verbose(4) << "Adding " << 1./tmp*constants[1] << "." << endl;
1134 }
1135 }
1136
1137 // third term: penalty for equal targets
1138 Runner = start;
1139 while (Runner->next != end) {
1140 Runner = Runner->next;
1141 if ((PermutationMap[Walker->nr] == PermutationMap[Runner->nr]) && (Walker->nr < Runner->nr)) {
1142 Sprinter = PermutationMap[Walker->nr];
1143// *out << *Walker << " and " << *Runner << " are heading to the same target at ";
1144// *out << Trajectories[Sprinter].R.at(endstep);
1145// *out << ", penalting." << endl;
1146 result += constants[2];
1147 //*out << Verbose(4) << "Adding " << constants[2] << "." << endl;
1148 }
1149 }
1150 }
1151
1152 return result;
1153};
1154
1155void PrintPermutationMap(ofstream *out, atom **PermutationMap, int Nr)
1156{
1157 stringstream zeile1, zeile2;
1158 int *DoubleList = (int *) Malloc(Nr*sizeof(int), "PrintPermutationMap: *DoubleList");
1159 int doubles = 0;
1160 for (int i=0;i<Nr;i++)
1161 DoubleList[i] = 0;
1162 zeile1 << "PermutationMap: ";
1163 zeile2 << " ";
1164 for (int i=0;i<Nr;i++) {
1165 DoubleList[PermutationMap[i]->nr]++;
1166 zeile1 << i << " ";
1167 zeile2 << PermutationMap[i]->nr << " ";
1168 }
1169 for (int i=0;i<Nr;i++)
1170 if (DoubleList[i] > 1)
1171 doubles++;
1172 // *out << "Found " << doubles << " Doubles." << endl;
1173 Free((void **)&DoubleList, "PrintPermutationMap: *DoubleList");
1174// *out << zeile1.str() << endl << zeile2.str() << endl;
1175};
1176
1177/** Minimises the extra potential for constrained molecular dynamics and gives forces and the constrained potential energy.
1178 * We do the following:
1179 * -# Generate a distance list from all source to all target points
1180 * -# Sort this per source point
1181 * -# Take for each source point the target point with minimum distance, use this as initial permutation
1182 * -# check whether molecule::ConstrainedPotential() is greater than injective penalty
1183 * -# If so, we go through each source point, stepping down in the sorted target point distance list and re-checking potential.
1184 * -# Next, we only apply transformations that keep the injectivity of the permutations list.
1185 * -# Hence, for one source point we step down the ladder and seek the corresponding owner of this new target
1186 * point and try to change it for one with lesser distance, or for the next one with greater distance, but only
1187 * if this decreases the conditional potential.
1188 * -# finished.
1189 * -# Then, we calculate the forces by taking the spatial derivative, where we scale the potential to such a degree,
1190 * that the total force is always pointing in direction of the constraint force (ensuring that we move in the
1191 * right direction).
1192 * -# Finally, we calculate the potential energy and return.
1193 * \param *out output stream for debugging
1194 * \param **PermutationMap on return: mapping between the atom label of the initial and the final configuration
1195 * \param startstep current MD step giving initial position between which and \a endstep we perform the constrained MD (as further steps are always concatenated)
1196 * \param endstep step giving final position in constrained MD
1197 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false)
1198 * \sa molecule::VerletForceIntegration()
1199 * \return potential energy (and allocated **PermutationMap (array of molecule::AtomCount ^2)
1200 * \todo The constrained potential's constants are set to fixed values right now, but they should scale based on checks of the system in order
1201 * to ensure they're properties (e.g. constants[2] always greater than the energy of the system).
1202 * \bug this all is not O(N log N) but O(N^2)
1203 */
1204double molecule::MinimiseConstrainedPotential(ofstream *out, atom **&PermutationMap, int startstep, int endstep, bool IsAngstroem)
1205{
1206 double Potential, OldPotential, OlderPotential;
1207 PermutationMap = (atom **) Malloc(AtomCount*sizeof(atom *), "molecule::MinimiseConstrainedPotential: **PermutationMap");
1208 DistanceMap **DistanceList = (DistanceMap **) Malloc(AtomCount*sizeof(DistanceMap *), "molecule::MinimiseConstrainedPotential: **DistanceList");
1209 DistanceMap::iterator *DistanceIterators = (DistanceMap::iterator *) Malloc(AtomCount*sizeof(DistanceMap::iterator), "molecule::MinimiseConstrainedPotential: *DistanceIterators");
1210 int *DoubleList = (int *) Malloc(AtomCount*sizeof(int), "molecule::MinimiseConstrainedPotential: *DoubleList");
1211 DistanceMap::iterator *StepList = (DistanceMap::iterator *) Malloc(AtomCount*sizeof(DistanceMap::iterator), "molecule::MinimiseConstrainedPotential: *StepList");
1212 double constants[3];
1213 int round;
1214 atom *Walker = NULL, *Runner = NULL, *Sprinter = NULL;
1215 DistanceMap::iterator Rider, Strider;
1216
1217 /// Minimise the potential
1218 // set Lagrange multiplier constants
1219 constants[0] = 10.;
1220 constants[1] = 1.;
1221 constants[2] = 1e+7; // just a huge penalty
1222 // generate the distance list
1223 *out << Verbose(1) << "Creating the distance list ... " << endl;
1224 for (int i=AtomCount; i--;) {
1225 DoubleList[i] = 0; // stores for how many atoms in startstep this atom is a target in endstep
1226 DistanceList[i] = new DistanceMap; // is the distance sorted target list per atom
1227 DistanceList[i]->clear();
1228 }
1229 *out << Verbose(1) << "Filling the distance list ... " << endl;
1230 Walker = start;
1231 while (Walker->next != end) {
1232 Walker = Walker->next;
1233 Runner = start;
1234 while(Runner->next != end) {
1235 Runner = Runner->next;
1236 DistanceList[Walker->nr]->insert( DistancePair(Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(endstep)), Runner) );
1237 }
1238 }
1239 // create the initial PermutationMap (source -> target)
1240 Walker = start;
1241 while (Walker->next != end) {
1242 Walker = Walker->next;
1243 StepList[Walker->nr] = DistanceList[Walker->nr]->begin(); // stores the step to the next iterator that could be a possible next target
1244 PermutationMap[Walker->nr] = DistanceList[Walker->nr]->begin()->second; // always pick target with the smallest distance
1245 DoubleList[DistanceList[Walker->nr]->begin()->second->nr]++; // increase this target's source count (>1? not injective)
1246 DistanceIterators[Walker->nr] = DistanceList[Walker->nr]->begin(); // and remember which one we picked
1247 *out << *Walker << " starts with distance " << DistanceList[Walker->nr]->begin()->first << "." << endl;
1248 }
1249 *out << Verbose(1) << "done." << endl;
1250 // make the PermutationMap injective by checking whether we have a non-zero constants[2] term in it
1251 *out << Verbose(1) << "Making the PermutationMap injective ... " << endl;
1252 Walker = start;
1253 DistanceMap::iterator NewBase;
1254 OldPotential = fabs(ConstrainedPotential(out, PermutationMap, startstep, endstep, constants, IsAngstroem));
1255 while ((OldPotential) > constants[2]) {
1256 PrintPermutationMap(out, PermutationMap, AtomCount);
1257 Walker = Walker->next;
1258 if (Walker == end) // round-robin at the end
1259 Walker = start->next;
1260 if (DoubleList[DistanceIterators[Walker->nr]->second->nr] <= 1) // no need to make those injective that aren't
1261 continue;
1262 // now, try finding a new one
1263 NewBase = DistanceIterators[Walker->nr]; // store old base
1264 do {
1265 NewBase++; // take next further distance in distance to targets list that's a target of no one
1266 } while ((DoubleList[NewBase->second->nr] != 0) && (NewBase != DistanceList[Walker->nr]->end()));
1267 if (NewBase != DistanceList[Walker->nr]->end()) {
1268 PermutationMap[Walker->nr] = NewBase->second;
1269 Potential = fabs(ConstrainedPotential(out, PermutationMap, startstep, endstep, constants, IsAngstroem));
1270 if (Potential > OldPotential) { // undo
1271 PermutationMap[Walker->nr] = DistanceIterators[Walker->nr]->second;
1272 } else { // do
1273 DoubleList[DistanceIterators[Walker->nr]->second->nr]--; // decrease the old entry in the doubles list
1274 DoubleList[NewBase->second->nr]++; // increase the old entry in the doubles list
1275 DistanceIterators[Walker->nr] = NewBase;
1276 OldPotential = Potential;
1277 *out << Verbose(3) << "Found a new permutation, new potential is " << OldPotential << "." << endl;
1278 }
1279 }
1280 }
1281 for (int i=AtomCount; i--;) // now each single entry in the DoubleList should be <=1
1282 if (DoubleList[i] > 1) {
1283 cerr << "Failed to create an injective PermutationMap!" << endl;
1284 exit(1);
1285 }
1286 *out << Verbose(1) << "done." << endl;
1287 Free((void **)&DoubleList, "molecule::MinimiseConstrainedPotential: *DoubleList");
1288 // argument minimise the constrained potential in this injective PermutationMap
1289 *out << Verbose(1) << "Argument minimising the PermutationMap, at current potential " << OldPotential << " ... " << endl;
1290 OldPotential = 1e+10;
1291 round = 0;
1292 do {
1293 *out << "Starting round " << ++round << " ... " << endl;
1294 OlderPotential = OldPotential;
1295 do {
1296 Walker = start;
1297 while (Walker->next != end) { // pick one
1298 Walker = Walker->next;
1299 PrintPermutationMap(out, PermutationMap, AtomCount);
1300 Sprinter = DistanceIterators[Walker->nr]->second; // store initial partner
1301 Strider = DistanceIterators[Walker->nr]; //remember old iterator
1302 DistanceIterators[Walker->nr] = StepList[Walker->nr];
1303 if (DistanceIterators[Walker->nr] == DistanceList[Walker->nr]->end()) {// stop, before we run through the list and still on
1304 DistanceIterators[Walker->nr] == DistanceList[Walker->nr]->begin();
1305 break;
1306 }
1307 //*out << Verbose(2) << "Current Walker: " << *Walker << " with old/next candidate " << *Sprinter << "/" << *DistanceIterators[Walker->nr]->second << "." << endl;
1308 // find source of the new target
1309 Runner = start->next;
1310 while(Runner != end) { // find the source whose toes we might be stepping on (Walker's new target should be in use by another already)
1311 if (PermutationMap[Runner->nr] == DistanceIterators[Walker->nr]->second) {
1312 //*out << Verbose(2) << "Found the corresponding owner " << *Runner << " to " << *PermutationMap[Runner->nr] << "." << endl;
1313 break;
1314 }
1315 Runner = Runner->next;
1316 }
1317 if (Runner != end) { // we found the other source
1318 // then look in its distance list for Sprinter
1319 Rider = DistanceList[Runner->nr]->begin();
1320 for (; Rider != DistanceList[Runner->nr]->end(); Rider++)
1321 if (Rider->second == Sprinter)
1322 break;
1323 if (Rider != DistanceList[Runner->nr]->end()) { // if we have found one
1324 //*out << Verbose(2) << "Current Other: " << *Runner << " with old/next candidate " << *PermutationMap[Runner->nr] << "/" << *Rider->second << "." << endl;
1325 // exchange both
1326 PermutationMap[Walker->nr] = DistanceIterators[Walker->nr]->second; // put next farther distance into PermutationMap
1327 PermutationMap[Runner->nr] = Sprinter; // and hand the old target to its respective owner
1328 PrintPermutationMap(out, PermutationMap, AtomCount);
1329 // calculate the new potential
1330 //*out << Verbose(2) << "Checking new potential ..." << endl;
1331 Potential = ConstrainedPotential(out, PermutationMap, startstep, endstep, constants, IsAngstroem);
1332 if (Potential > OldPotential) { // we made everything worse! Undo ...
1333 //*out << Verbose(3) << "Nay, made the potential worse: " << Potential << " vs. " << OldPotential << "!" << endl;
1334 //*out << Verbose(3) << "Setting " << *Runner << "'s source to " << *DistanceIterators[Runner->nr]->second << "." << endl;
1335 // Undo for Runner (note, we haven't moved the iteration yet, we may use this)
1336 PermutationMap[Runner->nr] = DistanceIterators[Runner->nr]->second;
1337 // Undo for Walker
1338 DistanceIterators[Walker->nr] = Strider; // take next farther distance target
1339 //*out << Verbose(3) << "Setting " << *Walker << "'s source to " << *DistanceIterators[Walker->nr]->second << "." << endl;
1340 PermutationMap[Walker->nr] = DistanceIterators[Walker->nr]->second;
1341 } else {
1342 DistanceIterators[Runner->nr] = Rider; // if successful also move the pointer in the iterator list
1343 *out << Verbose(3) << "Found a better permutation, new potential is " << Potential << " vs." << OldPotential << "." << endl;
1344 OldPotential = Potential;
1345 }
1346 if (Potential > constants[2]) {
1347 cerr << "ERROR: The two-step permutation procedure did not maintain injectivity!" << endl;
1348 exit(255);
1349 }
1350 //*out << endl;
1351 } else {
1352 cerr << "ERROR: " << *Runner << " was not the owner of " << *Sprinter << "!" << endl;
1353 exit(255);
1354 }
1355 } else {
1356 PermutationMap[Walker->nr] = DistanceIterators[Walker->nr]->second; // new target has no source!
1357 }
1358 StepList[Walker->nr]++; // take next farther distance target
1359 }
1360 } while (Walker->next != end);
1361 } while ((OlderPotential - OldPotential) > 1e-3);
1362 *out << Verbose(1) << "done." << endl;
1363
1364
1365 /// free memory and return with evaluated potential
1366 for (int i=AtomCount; i--;)
1367 DistanceList[i]->clear();
1368 Free((void **)&DistanceList, "molecule::MinimiseConstrainedPotential: **DistanceList");
1369 Free((void **)&DistanceIterators, "molecule::MinimiseConstrainedPotential: *DistanceIterators");
1370 return ConstrainedPotential(out, PermutationMap, startstep, endstep, constants, IsAngstroem);
1371};
1372
1373/** Evaluates the (distance-related part) of the constrained potential for the constrained forces.
1374 * \param *out output stream for debugging
1375 * \param startstep current MD step giving initial position between which and \a endstep we perform the constrained MD (as further steps are always concatenated)
1376 * \param endstep step giving final position in constrained MD
1377 * \param **PermutationMap mapping between the atom label of the initial and the final configuration
1378 * \param *Force ForceMatrix containing force vectors from the external energy functional minimisation.
1379 * \todo the constant for the constrained potential distance part is hard-coded independently of the hard-coded value in MinimiseConstrainedPotential()
1380 */
1381void molecule::EvaluateConstrainedForces(ofstream *out, int startstep, int endstep, atom **PermutationMap, ForceMatrix *Force)
1382{
1383 double constant = 10.;
1384 atom *Walker = NULL, *Sprinter = NULL;
1385
1386 /// evaluate forces (only the distance to target dependent part) with the final PermutationMap
1387 *out << Verbose(1) << "Calculating forces and adding onto ForceMatrix ... " << endl;
1388 Walker = start;
1389 while (Walker->next != NULL) {
1390 Walker = Walker->next;
1391 Sprinter = PermutationMap[Walker->nr];
1392 // set forces
1393 for (int i=NDIM;i++;)
1394 Force->Matrix[0][Walker->nr][5+i] += 2.*constant*sqrt(Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Sprinter].R.at(endstep)));
1395 }
1396 *out << Verbose(1) << "done." << endl;
1397};
1398
1399/** Performs a linear interpolation between two desired atomic configurations with a given number of steps.
1400 * Note, step number is config::MaxOuterStep
1401 * \param *out output stream for debugging
1402 * \param startstep stating initial configuration in molecule::Trajectories
1403 * \param endstep stating final configuration in molecule::Trajectories
1404 * \param &config configuration structure
1405 * \return true - success in writing step files, false - error writing files or only one step in molecule::Trajectories
1406 */
1407bool molecule::LinearInterpolationBetweenConfiguration(ofstream *out, int startstep, int endstep, const char *prefix, config &configuration)
1408{
1409 bool status = true;
1410 int MaxSteps = configuration.MaxOuterStep;
1411 MoleculeListClass *MoleculePerStep = new MoleculeListClass(MaxSteps+1, AtomCount);
1412 // Get the Permutation Map by MinimiseConstrainedPotential
1413 atom **PermutationMap = NULL;
1414 atom *Walker = NULL, *Sprinter = NULL;
1415 MinimiseConstrainedPotential(out, PermutationMap, startstep, endstep, configuration.GetIsAngstroem());
1416
1417 // check whether we have sufficient space in Trajectories for each atom
1418 Walker = start;
1419 while (Walker->next != end) {
1420 Walker = Walker->next;
1421 if (Trajectories[Walker].R.size() <= (unsigned int)(MaxSteps)) {
1422 //cout << "Increasing size for trajectory array of " << keyword << " to " << (MaxSteps+1) << "." << endl;
1423 Trajectories[Walker].R.resize(MaxSteps+1);
1424 Trajectories[Walker].U.resize(MaxSteps+1);
1425 Trajectories[Walker].F.resize(MaxSteps+1);
1426 }
1427 }
1428 // push endstep to last one
1429 Walker = start;
1430 while (Walker->next != end) { // remove the endstep (is now the very last one)
1431 Walker = Walker->next;
1432 for (int n=NDIM;n--;) {
1433 Trajectories[Walker].R.at(MaxSteps).x[n] = Trajectories[Walker].R.at(endstep).x[n];
1434 Trajectories[Walker].U.at(MaxSteps).x[n] = Trajectories[Walker].U.at(endstep).x[n];
1435 Trajectories[Walker].F.at(MaxSteps).x[n] = Trajectories[Walker].F.at(endstep).x[n];
1436 }
1437 }
1438 endstep = MaxSteps;
1439
1440 // go through all steps and add the molecular configuration to the list and to the Trajectories of \a this molecule
1441 *out << Verbose(1) << "Filling intermediate " << MaxSteps << " steps with MDSteps of " << MDSteps << "." << endl;
1442 for (int step = 0; step <= MaxSteps; step++) {
1443 MoleculePerStep->ListOfMolecules[step] = new molecule(elemente);
1444 Walker = start;
1445 while (Walker->next != end) {
1446 Walker = Walker->next;
1447 // add to molecule list
1448 Sprinter = MoleculePerStep->ListOfMolecules[step]->AddCopyAtom(Walker);
1449 for (int n=NDIM;n--;) {
1450 Sprinter->x.x[n] = Trajectories[Walker].R.at(startstep).x[n] + (Trajectories[PermutationMap[Walker->nr]].R.at(endstep).x[n] - Trajectories[Walker].R.at(startstep).x[n])*((double)step/(double)MaxSteps);
1451 // add to Trajectories
1452 //*out << Verbose(3) << step << ">=" << MDSteps-1 << endl;
1453 if (step < MaxSteps) {
1454 Trajectories[Walker].R.at(step).x[n] = Trajectories[Walker].R.at(startstep).x[n] + (Trajectories[PermutationMap[Walker->nr]].R.at(endstep).x[n] - Trajectories[Walker].R.at(startstep).x[n])*((double)step/(double)MaxSteps);
1455 Trajectories[Walker].U.at(step).x[n] = 0.;
1456 Trajectories[Walker].F.at(step).x[n] = 0.;
1457 }
1458 }
1459 }
1460 }
1461 MDSteps = MaxSteps+1; // otherwise new Trajectories' points aren't stored on save&exit
1462
1463 // store the list to single step files
1464 int *SortIndex = (int *) Malloc(AtomCount*sizeof(int), "molecule::LinearInterpolationBetweenConfiguration: *SortIndex");
1465 for (int i=AtomCount; i--; )
1466 SortIndex[i] = i;
1467 status = MoleculePerStep->OutputConfigForListOfFragments(out, "ConstrainedStep", &configuration, SortIndex, false, false);
1468
1469 // free and return
1470 Free((void **)&PermutationMap, "molecule::MinimiseConstrainedPotential: *PermutationMap");
1471 delete(MoleculePerStep);
1472 return status;
1473};
1474
1475/** Parses nuclear forces from file and performs Verlet integration.
1476 * Note that we assume the parsed forces to be in atomic units (hence, if coordinates are in angstroem, we
1477 * have to transform them).
1478 * This adds a new MD step to the config file.
1479 * \param *out output stream for debugging
1480 * \param *file filename
1481 * \param delta_t time step width in atomic units
1482 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false)
1483 * \param DoConstrained whether we perform a constrained (>0, target step in molecule::trajectories) or unconstrained (0) molecular dynamics, \sa molecule::MinimiseConstrainedPotential()
1484 * \return true - file found and parsed, false - file not found or imparsable
1485 * \todo This is not yet checked if it is correctly working with DoConstrained set to true.
1486 */
1487bool molecule::VerletForceIntegration(ofstream *out, char *file, double delta_t, bool IsAngstroem, int DoConstrained)
1488{
1489 element *runner = elemente->start;
1490 atom *walker = NULL;
1491 int AtomNo;
1492 ifstream input(file);
1493 string token;
1494 stringstream item;
1495 double a, IonMass, Vector[NDIM], ConstrainedPotentialEnergy;
1496 ForceMatrix Force;
1497
1498 CountElements(); // make sure ElementsInMolecule is up to date
1499
1500 // check file
1501 if (input == NULL) {
1502 return false;
1503 } else {
1504 // parse file into ForceMatrix
1505 if (!Force.ParseMatrix(file, 0,0,0)) {
1506 cerr << "Could not parse Force Matrix file " << file << "." << endl;
1507 return false;
1508 }
1509 if (Force.RowCounter[0] != AtomCount) {
1510 cerr << "Mismatch between number of atoms in file " << Force.RowCounter[0] << " and in molecule " << AtomCount << "." << endl;
1511 return false;
1512 }
1513 // correct Forces
1514 for(int d=0;d<NDIM;d++)
1515 Vector[d] = 0.;
1516 for(int i=0;i<AtomCount;i++)
1517 for(int d=0;d<NDIM;d++) {
1518 Vector[d] += Force.Matrix[0][i][d+5];
1519 }
1520 for(int i=0;i<AtomCount;i++)
1521 for(int d=0;d<NDIM;d++) {
1522 Force.Matrix[0][i][d+5] -= Vector[d]/(double)AtomCount;
1523 }
1524 // solve a constrained potential if we are meant to
1525 if (DoConstrained) {
1526 // calculate forces and potential
1527 atom **PermutationMap = NULL;
1528 ConstrainedPotentialEnergy = MinimiseConstrainedPotential(out, PermutationMap, DoConstrained, 0, IsAngstroem);
1529 EvaluateConstrainedForces(out, DoConstrained, 0, PermutationMap, &Force);
1530 Free((void **)&PermutationMap, "molecule::MinimiseConstrainedPotential: *PermutationMap");
1531 }
1532
1533 // and perform Verlet integration for each atom with position, velocity and force vector
1534 runner = elemente->start;
1535 while (runner->next != elemente->end) { // go through every element
1536 runner = runner->next;
1537 IonMass = runner->mass;
1538 a = delta_t*0.5/IonMass; // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a
1539 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1540 AtomNo = 0;
1541 walker = start;
1542 while (walker->next != end) { // go through every atom of this element
1543 walker = walker->next;
1544 if (walker->type == runner) { // if this atom fits to element
1545 // check size of vectors
1546 if (Trajectories[walker].R.size() <= (unsigned int)(MDSteps)) {
1547 //out << "Increasing size for trajectory array of " << *walker << " to " << (size+10) << "." << endl;
1548 Trajectories[walker].R.resize(MDSteps+10);
1549 Trajectories[walker].U.resize(MDSteps+10);
1550 Trajectories[walker].F.resize(MDSteps+10);
1551 }
1552
1553 // Update R (and F)
1554 for (int d=0; d<NDIM; d++) {
1555 Trajectories[walker].F.at(MDSteps).x[d] = -Force.Matrix[0][AtomNo][d+5]*(IsAngstroem ? AtomicLengthToAngstroem : 1.);
1556 Trajectories[walker].R.at(MDSteps).x[d] = Trajectories[walker].R.at(MDSteps-1).x[d];
1557 Trajectories[walker].R.at(MDSteps).x[d] += delta_t*(Trajectories[walker].U.at(MDSteps-1).x[d]);
1558 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
1559 }
1560 // Update U
1561 for (int d=0; d<NDIM; d++) {
1562 Trajectories[walker].U.at(MDSteps).x[d] = Trajectories[walker].U.at(MDSteps-1).x[d];
1563 Trajectories[walker].U.at(MDSteps).x[d] += a * (Trajectories[walker].F.at(MDSteps).x[d]+Trajectories[walker].F.at(MDSteps-1).x[d]);
1564 }
1565// out << "Integrated position&velocity of step " << (MDSteps) << ": (";
1566// for (int d=0;d<NDIM;d++)
1567// out << Trajectories[walker].R.at(MDSteps).x[d] << " "; // next step
1568// out << ")\t(";
1569// for (int d=0;d<NDIM;d++)
1570// cout << Trajectories[walker].U.at(MDSteps).x[d] << " "; // next step
1571// out << ")" << endl;
1572 // next atom
1573 AtomNo++;
1574 }
1575 }
1576 }
1577 }
1578 }
1579// // correct velocities (rather momenta) so that center of mass remains motionless
1580// for(int d=0;d<NDIM;d++)
1581// Vector[d] = 0.;
1582// IonMass = 0.;
1583// walker = start;
1584// while (walker->next != end) { // go through every atom
1585// walker = walker->next;
1586// IonMass += walker->type->mass; // sum up total mass
1587// for(int d=0;d<NDIM;d++) {
1588// Vector[d] += Trajectories[walker].U.at(MDSteps).x[d]*walker->type->mass;
1589// }
1590// }
1591// walker = start;
1592// while (walker->next != end) { // go through every atom of this element
1593// walker = walker->next;
1594// for(int d=0;d<NDIM;d++) {
1595// Trajectories[walker].U.at(MDSteps).x[d] -= Vector[d]*walker->type->mass/IonMass;
1596// }
1597// }
1598 MDSteps++;
1599
1600
1601 // exit
1602 return true;
1603};
1604
1605/** Align all atoms in such a manner that given vector \a *n is along z axis.
1606 * \param n[] alignment vector.
1607 */
1608void molecule::Align(Vector *n)
1609{
1610 atom *ptr = start;
1611 double alpha, tmp;
1612 Vector z_axis;
1613 z_axis.x[0] = 0.;
1614 z_axis.x[1] = 0.;
1615 z_axis.x[2] = 1.;
1616
1617 // rotate on z-x plane
1618 cout << Verbose(0) << "Begin of Aligning all atoms." << endl;
1619 alpha = atan(-n->x[0]/n->x[2]);
1620 cout << Verbose(1) << "Z-X-angle: " << alpha << " ... ";
1621 while (ptr->next != end) {
1622 ptr = ptr->next;
1623 tmp = ptr->x.x[0];
1624 ptr->x.x[0] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];
1625 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2];
1626 for (int j=0;j<MDSteps;j++) {
1627 tmp = Trajectories[ptr].R.at(j).x[0];
1628 Trajectories[ptr].R.at(j).x[0] = cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2];
1629 Trajectories[ptr].R.at(j).x[2] = -sin(alpha) * tmp + cos(alpha) * Trajectories[ptr].R.at(j).x[2];
1630 }
1631 }
1632 // rotate n vector
1633 tmp = n->x[0];
1634 n->x[0] = cos(alpha) * tmp + sin(alpha) * n->x[2];
1635 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2];
1636 cout << Verbose(1) << "alignment vector after first rotation: ";
1637 n->Output((ofstream *)&cout);
1638 cout << endl;
1639
1640 // rotate on z-y plane
1641 ptr = start;
1642 alpha = atan(-n->x[1]/n->x[2]);
1643 cout << Verbose(1) << "Z-Y-angle: " << alpha << " ... ";
1644 while (ptr->next != end) {
1645 ptr = ptr->next;
1646 tmp = ptr->x.x[1];
1647 ptr->x.x[1] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];
1648 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2];
1649 for (int j=0;j<MDSteps;j++) {
1650 tmp = Trajectories[ptr].R.at(j).x[1];
1651 Trajectories[ptr].R.at(j).x[1] = cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2];
1652 Trajectories[ptr].R.at(j).x[2] = -sin(alpha) * tmp + cos(alpha) * Trajectories[ptr].R.at(j).x[2];
1653 }
1654 }
1655 // rotate n vector (for consistency check)
1656 tmp = n->x[1];
1657 n->x[1] = cos(alpha) * tmp + sin(alpha) * n->x[2];
1658 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2];
1659
1660 cout << Verbose(1) << "alignment vector after second rotation: ";
1661 n->Output((ofstream *)&cout);
1662 cout << Verbose(1) << endl;
1663 cout << Verbose(0) << "End of Aligning all atoms." << endl;
1664};
1665
1666/** Removes atom from molecule list.
1667 * \param *pointer atom to be removed
1668 * \return true - succeeded, false - atom not found in list
1669 */
1670bool molecule::RemoveAtom(atom *pointer)
1671{
1672 if (ElementsInMolecule[pointer->type->Z] != 0) // this would indicate an error
1673 ElementsInMolecule[pointer->type->Z]--; // decrease number of atom of this element
1674 else
1675 cerr << "ERROR: Atom " << pointer->Name << " is of element " << pointer->type->Z << " but the entry in the table of the molecule is 0!" << endl;
1676 if (ElementsInMolecule[pointer->type->Z] == 0) // was last atom of this element?
1677 ElementCount--;
1678 Trajectories.erase(pointer);
1679 return remove(pointer, start, end);
1680};
1681
1682/** Removes every atom from molecule list.
1683 * \return true - succeeded, false - atom not found in list
1684 */
1685bool molecule::CleanupMolecule()
1686{
1687 return (cleanup(start,end) && cleanup(first,last));
1688};
1689
1690/** Finds an atom specified by its continuous number.
1691 * \param Nr number of atom withim molecule
1692 * \return pointer to atom or NULL
1693 */
1694atom * molecule::FindAtom(int Nr) const{
1695 atom * walker = find(&Nr, start,end);
1696 if (walker != NULL) {
1697 //cout << Verbose(0) << "Found Atom Nr. " << walker->nr << endl;
1698 return walker;
1699 } else {
1700 cout << Verbose(0) << "Atom not found in list." << endl;
1701 return NULL;
1702 }
1703};
1704
1705/** Asks for atom number, and checks whether in list.
1706 * \param *text question before entering
1707 */
1708atom * molecule::AskAtom(string text)
1709{
1710 int No;
1711 atom *ion = NULL;
1712 do {
1713 //cout << Verbose(0) << "============Atom list==========================" << endl;
1714 //mol->Output((ofstream *)&cout);
1715 //cout << Verbose(0) << "===============================================" << endl;
1716 cout << Verbose(0) << text;
1717 cin >> No;
1718 ion = this->FindAtom(No);
1719 } while (ion == NULL);
1720 return ion;
1721};
1722
1723/** Checks if given coordinates are within cell volume.
1724 * \param *x array of coordinates
1725 * \return true - is within, false - out of cell
1726 */
1727bool molecule::CheckBounds(const Vector *x) const
1728{
1729 bool result = true;
1730 int j =-1;
1731 for (int i=0;i<NDIM;i++) {
1732 j += i+1;
1733 result = result && ((x->x[i] >= 0) && (x->x[i] < cell_size[j]));
1734 }
1735 //return result;
1736 return true; /// probably not gonna use the check no more
1737};
1738
1739/** Calculates sum over least square distance to line hidden in \a *x.
1740 * \param *x offset and direction vector
1741 * \param *params pointer to lsq_params structure
1742 * \return \f$ sum_i^N | y_i - (a + t_i b)|^2\f$
1743 */
1744double LeastSquareDistance (const gsl_vector * x, void * params)
1745{
1746 double res = 0, t;
1747 Vector a,b,c,d;
1748 struct lsq_params *par = (struct lsq_params *)params;
1749 atom *ptr = par->mol->start;
1750
1751 // initialize vectors
1752 a.x[0] = gsl_vector_get(x,0);
1753 a.x[1] = gsl_vector_get(x,1);
1754 a.x[2] = gsl_vector_get(x,2);
1755 b.x[0] = gsl_vector_get(x,3);
1756 b.x[1] = gsl_vector_get(x,4);
1757 b.x[2] = gsl_vector_get(x,5);
1758 // go through all atoms
1759 while (ptr != par->mol->end) {
1760 ptr = ptr->next;
1761 if (ptr->type == ((struct lsq_params *)params)->type) { // for specific type
1762 c.CopyVector(&ptr->x); // copy vector to temporary one
1763 c.SubtractVector(&a); // subtract offset vector
1764 t = c.ScalarProduct(&b); // get direction parameter
1765 d.CopyVector(&b); // and create vector
1766 d.Scale(&t);
1767 c.SubtractVector(&d); // ... yielding distance vector
1768 res += d.ScalarProduct((const Vector *)&d); // add squared distance
1769 }
1770 }
1771 return res;
1772};
1773
1774/** By minimizing the least square distance gains alignment vector.
1775 * \bug this is not yet working properly it seems
1776 */
1777void molecule::GetAlignvector(struct lsq_params * par) const
1778{
1779 int np = 6;
1780
1781 const gsl_multimin_fminimizer_type *T =
1782 gsl_multimin_fminimizer_nmsimplex;
1783 gsl_multimin_fminimizer *s = NULL;
1784 gsl_vector *ss;
1785 gsl_multimin_function minex_func;
1786
1787 size_t iter = 0, i;
1788 int status;
1789 double size;
1790
1791 /* Initial vertex size vector */
1792 ss = gsl_vector_alloc (np);
1793
1794 /* Set all step sizes to 1 */
1795 gsl_vector_set_all (ss, 1.0);
1796
1797 /* Starting point */
1798 par->x = gsl_vector_alloc (np);
1799 par->mol = this;
1800
1801 gsl_vector_set (par->x, 0, 0.0); // offset
1802 gsl_vector_set (par->x, 1, 0.0);
1803 gsl_vector_set (par->x, 2, 0.0);
1804 gsl_vector_set (par->x, 3, 0.0); // direction
1805 gsl_vector_set (par->x, 4, 0.0);
1806 gsl_vector_set (par->x, 5, 1.0);
1807
1808 /* Initialize method and iterate */
1809 minex_func.f = &LeastSquareDistance;
1810 minex_func.n = np;
1811 minex_func.params = (void *)par;
1812
1813 s = gsl_multimin_fminimizer_alloc (T, np);
1814 gsl_multimin_fminimizer_set (s, &minex_func, par->x, ss);
1815
1816 do
1817 {
1818 iter++;
1819 status = gsl_multimin_fminimizer_iterate(s);
1820
1821 if (status)
1822 break;
1823
1824 size = gsl_multimin_fminimizer_size (s);
1825 status = gsl_multimin_test_size (size, 1e-2);
1826
1827 if (status == GSL_SUCCESS)
1828 {
1829 printf ("converged to minimum at\n");
1830 }
1831
1832 printf ("%5d ", (int)iter);
1833 for (i = 0; i < (size_t)np; i++)
1834 {
1835 printf ("%10.3e ", gsl_vector_get (s->x, i));
1836 }
1837 printf ("f() = %7.3f size = %.3f\n", s->fval, size);
1838 }
1839 while (status == GSL_CONTINUE && iter < 100);
1840
1841 for (i=0;i<(size_t)np;i++)
1842 gsl_vector_set(par->x, i, gsl_vector_get(s->x, i));
1843 //gsl_vector_free(par->x);
1844 gsl_vector_free(ss);
1845 gsl_multimin_fminimizer_free (s);
1846};
1847
1848/** Prints molecule to *out.
1849 * \param *out output stream
1850 */
1851bool molecule::Output(ofstream *out)
1852{
1853 element *runner;
1854 atom *walker = NULL;
1855 int ElementNo, AtomNo;
1856 CountElements();
1857
1858 if (out == NULL) {
1859 return false;
1860 } else {
1861 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
1862 ElementNo = 0;
1863 runner = elemente->start;
1864 while (runner->next != elemente->end) { // go through every element
1865 runner = runner->next;
1866 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1867 ElementNo++;
1868 AtomNo = 0;
1869 walker = start;
1870 while (walker->next != end) { // go through every atom of this element
1871 walker = walker->next;
1872 if (walker->type == runner) { // if this atom fits to element
1873 AtomNo++;
1874 walker->Output(ElementNo, AtomNo, out); // removed due to trajectories
1875 }
1876 }
1877 }
1878 }
1879 return true;
1880 }
1881};
1882
1883/** Prints molecule with all atomic trajectory positions to *out.
1884 * \param *out output stream
1885 */
1886bool molecule::OutputTrajectories(ofstream *out)
1887{
1888 element *runner = NULL;
1889 atom *walker = NULL;
1890 int ElementNo, AtomNo;
1891 CountElements();
1892
1893 if (out == NULL) {
1894 return false;
1895 } else {
1896 for (int step = 0; step < MDSteps; step++) {
1897 if (step == 0) {
1898 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
1899 } else {
1900 *out << "# ====== MD step " << step << " =========" << endl;
1901 }
1902 ElementNo = 0;
1903 runner = elemente->start;
1904 while (runner->next != elemente->end) { // go through every element
1905 runner = runner->next;
1906 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1907 ElementNo++;
1908 AtomNo = 0;
1909 walker = start;
1910 while (walker->next != end) { // go through every atom of this element
1911 walker = walker->next;
1912 if (walker->type == runner) { // if this atom fits to element
1913 AtomNo++;
1914 *out << "Ion_Type" << ElementNo << "_" << AtomNo << "\t" << fixed << setprecision(9) << showpoint;
1915 *out << Trajectories[walker].R.at(step).x[0] << "\t" << Trajectories[walker].R.at(step).x[1] << "\t" << Trajectories[walker].R.at(step).x[2];
1916 *out << "\t" << walker->FixedIon;
1917 if (Trajectories[walker].U.at(step).Norm() > MYEPSILON)
1918 *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";
1919 if (Trajectories[walker].F.at(step).Norm() > MYEPSILON)
1920 *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";
1921 *out << "\t# Number in molecule " << walker->nr << endl;
1922 }
1923 }
1924 }
1925 }
1926 }
1927 return true;
1928 }
1929};
1930
1931/** Outputs contents of molecule::ListOfBondsPerAtom.
1932 * \param *out output stream
1933 */
1934void molecule::OutputListOfBonds(ofstream *out) const
1935{
1936 *out << Verbose(2) << endl << "From Contents of ListOfBondsPerAtom, all non-hydrogen atoms:" << endl;
1937 atom *Walker = start;
1938 while (Walker->next != end) {
1939 Walker = Walker->next;
1940#ifdef ADDHYDROGEN
1941 if (Walker->type->Z != 1) { // regard only non-hydrogen
1942#endif
1943 *out << Verbose(2) << "Atom " << Walker->Name << " has Bonds: "<<endl;
1944 for(int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
1945 *out << Verbose(3) << *(ListOfBondsPerAtom)[Walker->nr][j] << endl;
1946 }
1947#ifdef ADDHYDROGEN
1948 }
1949#endif
1950 }
1951 *out << endl;
1952};
1953
1954/** Output of element before the actual coordination list.
1955 * \param *out stream pointer
1956 */
1957bool molecule::Checkout(ofstream *out) const
1958{
1959 return elemente->Checkout(out, ElementsInMolecule);
1960};
1961
1962/** Prints molecule with all its trajectories to *out as xyz file.
1963 * \param *out output stream
1964 */
1965bool molecule::OutputTrajectoriesXYZ(ofstream *out)
1966{
1967 atom *walker = NULL;
1968 int No = 0;
1969 time_t now;
1970
1971 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
1972 walker = start;
1973 while (walker->next != end) { // go through every atom and count
1974 walker = walker->next;
1975 No++;
1976 }
1977 if (out != NULL) {
1978 for (int step=0;step<MDSteps;step++) {
1979 *out << No << "\n\tCreated by molecuilder, step " << step << ", on " << ctime(&now);
1980 walker = start;
1981 while (walker->next != end) { // go through every atom of this element
1982 walker = walker->next;
1983 *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;
1984 }
1985 }
1986 return true;
1987 } else
1988 return false;
1989};
1990
1991/** Prints molecule to *out as xyz file.
1992* \param *out output stream
1993 */
1994bool molecule::OutputXYZ(ofstream *out) const
1995{
1996 atom *walker = NULL;
1997 int No = 0;
1998 time_t now;
1999
2000 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
2001 walker = start;
2002 while (walker->next != end) { // go through every atom and count
2003 walker = walker->next;
2004 No++;
2005 }
2006 if (out != NULL) {
2007 *out << No << "\n\tCreated by molecuilder on " << ctime(&now);
2008 walker = start;
2009 while (walker->next != end) { // go through every atom of this element
2010 walker = walker->next;
2011 walker->OutputXYZLine(out);
2012 }
2013 return true;
2014 } else
2015 return false;
2016};
2017
2018/** Brings molecule::AtomCount and atom::*Name up-to-date.
2019 * \param *out output stream for debugging
2020 */
2021void molecule::CountAtoms(ofstream *out)
2022{
2023 int i = 0;
2024 atom *Walker = start;
2025 while (Walker->next != end) {
2026 Walker = Walker->next;
2027 i++;
2028 }
2029 if ((AtomCount == 0) || (i != AtomCount)) {
2030 *out << Verbose(3) << "Mismatch in AtomCount " << AtomCount << " and recounted number " << i << ", renaming all." << endl;
2031 AtomCount = i;
2032
2033 // count NonHydrogen atoms and give each atom a unique name
2034 if (AtomCount != 0) {
2035 i=0;
2036 NoNonHydrogen = 0;
2037 Walker = start;
2038 while (Walker->next != end) {
2039 Walker = Walker->next;
2040 Walker->nr = i; // update number in molecule (for easier referencing in FragmentMolecule lateron)
2041 if (Walker->type->Z != 1) // count non-hydrogen atoms whilst at it
2042 NoNonHydrogen++;
2043 Free((void **)&Walker->Name, "molecule::CountAtoms: *walker->Name");
2044 Walker->Name = (char *) Malloc(sizeof(char)*6, "molecule::CountAtoms: *walker->Name");
2045 sprintf(Walker->Name, "%2s%02d", Walker->type->symbol, Walker->nr+1);
2046 *out << "Naming atom nr. " << Walker->nr << " " << Walker->Name << "." << endl;
2047 i++;
2048 }
2049 } else
2050 *out << Verbose(3) << "AtomCount is still " << AtomCount << ", thus counting nothing." << endl;
2051 }
2052};
2053
2054/** Brings molecule::ElementCount and molecule::ElementsInMolecule up-to-date.
2055 */
2056void molecule::CountElements()
2057{
2058 int i = 0;
2059 for(i=MAX_ELEMENTS;i--;)
2060 ElementsInMolecule[i] = 0;
2061 ElementCount = 0;
2062
2063 atom *walker = start;
2064 while (walker->next != end) {
2065 walker = walker->next;
2066 ElementsInMolecule[walker->type->Z]++;
2067 i++;
2068 }
2069 for(i=MAX_ELEMENTS;i--;)
2070 ElementCount += (ElementsInMolecule[i] != 0 ? 1 : 0);
2071};
2072
2073/** Counts all cyclic bonds and returns their number.
2074 * \note Hydrogen bonds can never by cyclic, thus no check for that
2075 * \param *out output stream for debugging
2076 * \return number opf cyclic bonds
2077 */
2078int molecule::CountCyclicBonds(ofstream *out)
2079{
2080 int No = 0;
2081 int *MinimumRingSize = NULL;
2082 MoleculeLeafClass *Subgraphs = NULL;
2083 class StackClass<bond *> *BackEdgeStack = NULL;
2084 bond *Binder = first;
2085 if ((Binder->next != last) && (Binder->next->Type == Undetermined)) {
2086 *out << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl;
2087 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack);
2088 while (Subgraphs->next != NULL) {
2089 Subgraphs = Subgraphs->next;
2090 delete(Subgraphs->previous);
2091 }
2092 delete(Subgraphs);
2093 delete[](MinimumRingSize);
2094 }
2095 while(Binder->next != last) {
2096 Binder = Binder->next;
2097 if (Binder->Cyclic)
2098 No++;
2099 }
2100 delete(BackEdgeStack);
2101 return No;
2102};
2103/** Returns Shading as a char string.
2104 * \param color the Shading
2105 * \return string of the flag
2106 */
2107string molecule::GetColor(enum Shading color)
2108{
2109 switch(color) {
2110 case white:
2111 return "white";
2112 break;
2113 case lightgray:
2114 return "lightgray";
2115 break;
2116 case darkgray:
2117 return "darkgray";
2118 break;
2119 case black:
2120 return "black";
2121 break;
2122 default:
2123 return "uncolored";
2124 break;
2125 };
2126};
2127
2128
2129/** Counts necessary number of valence electrons and returns number and SpinType.
2130 * \param configuration containing everything
2131 */
2132void molecule::CalculateOrbitals(class config &configuration)
2133{
2134 configuration.MaxPsiDouble = configuration.PsiMaxNoDown = configuration.PsiMaxNoUp = configuration.PsiType = 0;
2135 for(int i=MAX_ELEMENTS;i--;) {
2136 if (ElementsInMolecule[i] != 0) {
2137 //cout << "CalculateOrbitals: " << elemente->FindElement(i)->name << " has a valence of " << (int)elemente->FindElement(i)->Valence << " and there are " << ElementsInMolecule[i] << " of it." << endl;
2138 configuration.MaxPsiDouble += ElementsInMolecule[i]*((int)elemente->FindElement(i)->Valence);
2139 }
2140 }
2141 configuration.PsiMaxNoDown = configuration.MaxPsiDouble/2 + (configuration.MaxPsiDouble % 2);
2142 configuration.PsiMaxNoUp = configuration.MaxPsiDouble/2;
2143 configuration.MaxPsiDouble /= 2;
2144 configuration.PsiType = (configuration.PsiMaxNoDown == configuration.PsiMaxNoUp) ? 0 : 1;
2145 if ((configuration.PsiType == 1) && (configuration.ProcPEPsi < 2)) {
2146 configuration.ProcPEGamma /= 2;
2147 configuration.ProcPEPsi *= 2;
2148 } else {
2149 configuration.ProcPEGamma *= configuration.ProcPEPsi;
2150 configuration.ProcPEPsi = 1;
2151 }
2152 configuration.InitMaxMinStopStep = configuration.MaxMinStopStep = configuration.MaxPsiDouble;
2153};
2154
2155/** Creates an adjacency list of the molecule.
2156 * Generally, we use the CSD approach to bond recognition, that is the the distance
2157 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
2158 * a threshold t = 0.4 Angstroem.
2159 * To make it O(N log N) the function uses the linked-cell technique as follows:
2160 * The procedure is step-wise:
2161 * -# Remove every bond in list
2162 * -# Count the atoms in the molecule with CountAtoms()
2163 * -# partition cell into smaller linked cells of size \a bonddistance
2164 * -# put each atom into its corresponding cell
2165 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true
2166 * -# create the list of bonds via CreateListOfBondsPerAtom()
2167 * -# correct the bond degree iteratively (single->double->triple bond)
2168 * -# finally print the bond list to \a *out if desired
2169 * \param *out out stream for printing the matrix, NULL if no output
2170 * \param bonddistance length of linked cells (i.e. maximum minimal length checked)
2171 * \param IsAngstroem whether coordinate system is gauged to Angstroem or Bohr radii
2172 */
2173void molecule::CreateAdjacencyList(ofstream *out, double bonddistance, bool IsAngstroem)
2174{
2175 atom *Walker = NULL, *OtherWalker = NULL, *Candidate = NULL;
2176 int No, NoBonds, CandidateBondNo;
2177 int NumberCells, divisor[NDIM], n[NDIM], N[NDIM], index, Index, j;
2178 molecule **CellList;
2179 double distance, MinDistance, MaxDistance;
2180 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
2181 Vector x;
2182 int FalseBondDegree = 0;
2183
2184 BondDistance = bonddistance; // * ((IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem);
2185 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl;
2186 // remove every bond from the list
2187 if ((first->next != last) && (last->previous != first)) { // there are bonds present
2188 cleanup(first,last);
2189 }
2190
2191 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering)
2192 CountAtoms(out);
2193 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl;
2194
2195 if (AtomCount != 0) {
2196 // 1. find divisor for each axis, such that a sphere with radius of at least bonddistance can be placed into each cell
2197 j=-1;
2198 for (int i=0;i<NDIM;i++) {
2199 j += i+1;
2200 divisor[i] = (int)floor(cell_size[j]/bonddistance); // take smaller value such that size of linked cell is at least bonddistance
2201 //*out << Verbose(1) << "divisor[" << i << "] = " << divisor[i] << "." << endl;
2202 }
2203 // 2a. allocate memory for the cell list
2204 NumberCells = divisor[0]*divisor[1]*divisor[2];
2205 *out << Verbose(1) << "Allocating " << NumberCells << " cells." << endl;
2206 CellList = (molecule **) Malloc(sizeof(molecule *)*NumberCells, "molecule::CreateAdjacencyList - ** CellList");
2207 for (int i=NumberCells;i--;)
2208 CellList[i] = NULL;
2209
2210 // 2b. put all atoms into its corresponding list
2211 Walker = start;
2212 while(Walker->next != end) {
2213 Walker = Walker->next;
2214 //*out << Verbose(1) << "Current atom is " << *Walker << " with coordinates ";
2215 //Walker->x.Output(out);
2216 //*out << "." << endl;
2217 // compute the cell by the atom's coordinates
2218 j=-1;
2219 for (int i=0;i<NDIM;i++) {
2220 j += i+1;
2221 x.CopyVector(&(Walker->x));
2222 x.KeepPeriodic(out, matrix);
2223 n[i] = (int)floor(x.x[i]/cell_size[j]*(double)divisor[i]);
2224 }
2225 index = n[2] + (n[1] + n[0] * divisor[1]) * divisor[2];
2226 //*out << Verbose(1) << "Atom " << *Walker << " goes into cell number [" << n[0] << "," << n[1] << "," << n[2] << "] = " << index << "." << endl;
2227 // add copy atom to this cell
2228 if (CellList[index] == NULL) // allocate molecule if not done
2229 CellList[index] = new molecule(elemente);
2230 OtherWalker = CellList[index]->AddCopyAtom(Walker); // add a copy of walker to this atom, father will be walker for later reference
2231 //*out << Verbose(1) << "Copy Atom is " << *OtherWalker << "." << endl;
2232 }
2233 //for (int i=0;i<NumberCells;i++)
2234 //*out << Verbose(1) << "Cell number " << i << ": " << CellList[i] << "." << endl;
2235
2236 // 3a. go through every cell
2237 for (N[0]=divisor[0];N[0]--;)
2238 for (N[1]=divisor[1];N[1]--;)
2239 for (N[2]=divisor[2];N[2]--;) {
2240 Index = N[2] + (N[1] + N[0] * divisor[1]) * divisor[2];
2241 if (CellList[Index] != NULL) { // if there atoms in this cell
2242 //*out << Verbose(1) << "Current cell is " << Index << "." << endl;
2243 // 3b. for every atom therein
2244 Walker = CellList[Index]->start;
2245 while (Walker->next != CellList[Index]->end) { // go through every atom
2246 Walker = Walker->next;
2247 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl;
2248 // 3c. check for possible bond between each atom in this and every one in the 27 cells
2249 for (n[0]=-1;n[0]<=1;n[0]++)
2250 for (n[1]=-1;n[1]<=1;n[1]++)
2251 for (n[2]=-1;n[2]<=1;n[2]++) {
2252 // compute the index of this comparison cell and make it periodic
2253 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];
2254 //*out << Verbose(1) << "Number of comparison cell is " << index << "." << endl;
2255 if (CellList[index] != NULL) { // if there are any atoms in this cell
2256 OtherWalker = CellList[index]->start;
2257 while(OtherWalker->next != CellList[index]->end) { // go through every atom in this cell
2258 OtherWalker = OtherWalker->next;
2259 //*out << Verbose(0) << "Current comparison atom is " << *OtherWalker << "." << endl;
2260 /// \todo periodic check is missing here!
2261 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl;
2262 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius;
2263 MinDistance *= (IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem;
2264 MaxDistance = MinDistance + BONDTHRESHOLD;
2265 MinDistance -= BONDTHRESHOLD;
2266 distance = OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size);
2267 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance*MaxDistance) && (distance >= MinDistance*MinDistance)) { // create bond if distance is smaller
2268 //*out << Verbose(0) << "Adding Bond between " << *Walker << " and " << *OtherWalker << "." << endl;
2269 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount
2270 BondCount++;
2271 } else {
2272 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl;
2273 }
2274 }
2275 }
2276 }
2277 }
2278 }
2279 }
2280 // 4. free the cell again
2281 for (int i=NumberCells;i--;)
2282 if (CellList[i] != NULL) {
2283 delete(CellList[i]);
2284 }
2285 Free((void **)&CellList, "molecule::CreateAdjacencyList - ** CellList");
2286
2287 // create the adjacency list per atom
2288 CreateListOfBondsPerAtom(out);
2289
2290 // correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees,
2291 // iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene
2292 // preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of
2293 // double bonds as was expected.
2294 if (BondCount != 0) {
2295 NoCyclicBonds = 0;
2296 *out << Verbose(1) << "Correcting Bond degree of each bond ... ";
2297 do {
2298 No = 0; // No acts as breakup flag (if 1 we still continue)
2299 Walker = start;
2300 while (Walker->next != end) { // go through every atom
2301 Walker = Walker->next;
2302 // count valence of first partner
2303 NoBonds = 0;
2304 for(j=0;j<NumberOfBondsPerAtom[Walker->nr];j++)
2305 NoBonds += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
2306 *out << Verbose(3) << "Walker " << *Walker << ": " << (int)Walker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
2307 if ((int)(Walker->type->NoValenceOrbitals) > NoBonds) { // we have a mismatch, check all bonding partners for mismatch
2308 Candidate = NULL;
2309 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through each of its bond partners
2310 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
2311 // count valence of second partner
2312 NoBonds = 0;
2313 for(j=0;j<NumberOfBondsPerAtom[OtherWalker->nr];j++)
2314 NoBonds += ListOfBondsPerAtom[OtherWalker->nr][j]->BondDegree;
2315 *out << Verbose(3) << "OtherWalker " << *OtherWalker << ": " << (int)OtherWalker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
2316 if ((int)(OtherWalker->type->NoValenceOrbitals) > NoBonds) { // check if possible candidate
2317 if ((Candidate == NULL) || (NumberOfBondsPerAtom[Candidate->nr] > NumberOfBondsPerAtom[OtherWalker->nr])) { // pick the one with fewer number of bonds first
2318 Candidate = OtherWalker;
2319 CandidateBondNo = i;
2320 *out << Verbose(3) << "New candidate is " << *Candidate << "." << endl;
2321 }
2322 }
2323 }
2324 if (Candidate != NULL) {
2325 ListOfBondsPerAtom[Walker->nr][CandidateBondNo]->BondDegree++;
2326 *out << Verbose(2) << "Increased bond degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl;
2327 } else
2328 *out << Verbose(2) << "Could not find correct degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl;
2329 FalseBondDegree++;
2330 }
2331 }
2332 } while (No);
2333 *out << " done." << endl;
2334 } else
2335 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl;
2336 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << bonddistance << ", " << FalseBondDegree << " bonds could not be corrected." << endl;
2337
2338 // output bonds for debugging (if bond chain list was correctly installed)
2339 *out << Verbose(1) << endl << "From contents of bond chain list:";
2340 bond *Binder = first;
2341 while(Binder->next != last) {
2342 Binder = Binder->next;
2343 *out << *Binder << "\t" << endl;
2344 }
2345 *out << endl;
2346 } else
2347 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl;
2348 *out << Verbose(0) << "End of CreateAdjacencyList." << endl;
2349 Free((void **)&matrix, "molecule::CreateAdjacencyList: *matrix");
2350};
2351
2352/** Performs a Depth-First search on this molecule.
2353 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
2354 * articulations points, ...
2355 * We use the algorithm from [Even, Graph Algorithms, p.62].
2356 * \param *out output stream for debugging
2357 * \param *&BackEdgeStack NULL pointer to StackClass with all the found back edges, allocated and filled on return
2358 * \return list of each disconnected subgraph as an individual molecule class structure
2359 */
2360MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, class StackClass<bond *> *&BackEdgeStack)
2361{
2362 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
2363 BackEdgeStack = new StackClass<bond *> (BondCount);
2364 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
2365 MoleculeLeafClass *LeafWalker = SubGraphs;
2366 int CurrentGraphNr = 0, OldGraphNr;
2367 int ComponentNumber = 0;
2368 atom *Walker = NULL, *OtherAtom = NULL, *Root = start->next;
2369 bond *Binder = NULL;
2370 bool BackStepping = false;
2371
2372 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl;
2373
2374 ResetAllBondsToUnused();
2375 ResetAllAtomNumbers();
2376 InitComponentNumbers();
2377 BackEdgeStack->ClearStack();
2378 while (Root != end) { // if there any atoms at all
2379 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all
2380 AtomStack->ClearStack();
2381
2382 // put into new subgraph molecule and add this to list of subgraphs
2383 LeafWalker = new MoleculeLeafClass(LeafWalker);
2384 LeafWalker->Leaf = new molecule(elemente);
2385 LeafWalker->Leaf->AddCopyAtom(Root);
2386
2387 OldGraphNr = CurrentGraphNr;
2388 Walker = Root;
2389 do { // (10)
2390 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
2391 if (!BackStepping) { // if we don't just return from (8)
2392 Walker->GraphNr = CurrentGraphNr;
2393 Walker->LowpointNr = CurrentGraphNr;
2394 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl;
2395 AtomStack->Push(Walker);
2396 CurrentGraphNr++;
2397 }
2398 do { // (3) if Walker has no unused egdes, go to (5)
2399 BackStepping = false; // reset backstepping flag for (8)
2400 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
2401 Binder = FindNextUnused(Walker);
2402 if (Binder == NULL)
2403 break;
2404 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl;
2405 // (4) Mark Binder used, ...
2406 Binder->MarkUsed(black);
2407 OtherAtom = Binder->GetOtherAtom(Walker);
2408 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl;
2409 if (OtherAtom->GraphNr != -1) {
2410 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
2411 Binder->Type = BackEdge;
2412 BackEdgeStack->Push(Binder);
2413 Walker->LowpointNr = ( Walker->LowpointNr < OtherAtom->GraphNr ) ? Walker->LowpointNr : OtherAtom->GraphNr;
2414 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl;
2415 } else {
2416 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
2417 Binder->Type = TreeEdge;
2418 OtherAtom->Ancestor = Walker;
2419 Walker = OtherAtom;
2420 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl;
2421 break;
2422 }
2423 Binder = NULL;
2424 } while (1); // (3)
2425 if (Binder == NULL) {
2426 *out << Verbose(2) << "No more Unused Bonds." << endl;
2427 break;
2428 } else
2429 Binder = NULL;
2430 } while (1); // (2)
2431
2432 // 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!
2433 if ((Walker == Root) && (Binder == NULL))
2434 break;
2435
2436 // (5) if Ancestor of Walker is ...
2437 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl;
2438 if (Walker->Ancestor->GraphNr != Root->GraphNr) {
2439 // (6) (Ancestor of Walker is not Root)
2440 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
2441 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
2442 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
2443 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl;
2444 } else {
2445 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
2446 Walker->Ancestor->SeparationVertex = true;
2447 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl;
2448 SetNextComponentNumber(Walker->Ancestor, ComponentNumber);
2449 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << ComponentNumber << "." << endl;
2450 SetNextComponentNumber(Walker, ComponentNumber);
2451 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << ComponentNumber << "." << endl;
2452 do {
2453 OtherAtom = AtomStack->PopLast();
2454 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
2455 SetNextComponentNumber(OtherAtom, ComponentNumber);
2456 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
2457 } while (OtherAtom != Walker);
2458 ComponentNumber++;
2459 }
2460 // (8) Walker becomes its Ancestor, go to (3)
2461 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl;
2462 Walker = Walker->Ancestor;
2463 BackStepping = true;
2464 }
2465 if (!BackStepping) { // coming from (8) want to go to (3)
2466 // (9) remove all from stack till Walker (including), these and Root form a component
2467 AtomStack->Output(out);
2468 SetNextComponentNumber(Root, ComponentNumber);
2469 *out << Verbose(3) << "(9) Root[" << Root->Name << "]'s Component is " << ComponentNumber << "." << endl;
2470 SetNextComponentNumber(Walker, ComponentNumber);
2471 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << ComponentNumber << "." << endl;
2472 do {
2473 OtherAtom = AtomStack->PopLast();
2474 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
2475 SetNextComponentNumber(OtherAtom, ComponentNumber);
2476 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
2477 } while (OtherAtom != Walker);
2478 ComponentNumber++;
2479
2480 // (11) Root is separation vertex, set Walker to Root and go to (4)
2481 Walker = Root;
2482 Binder = FindNextUnused(Walker);
2483 *out << Verbose(1) << "(10) Walker is Root[" << Root->Name << "], next Unused Bond is " << Binder << "." << endl;
2484 if (Binder != NULL) { // Root is separation vertex
2485 *out << Verbose(1) << "(11) Root is a separation vertex." << endl;
2486 Walker->SeparationVertex = true;
2487 }
2488 }
2489 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
2490
2491 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
2492 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << CurrentGraphNr << "." << endl;
2493 LeafWalker->Leaf->Output(out);
2494 *out << endl;
2495
2496 // step on to next root
2497 while ((Root != end) && (Root->GraphNr != -1)) {
2498 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl;
2499 if (Root->GraphNr != -1) // if already discovered, step on
2500 Root = Root->next;
2501 }
2502 }
2503 // set cyclic bond criterium on "same LP" basis
2504 Binder = first;
2505 while(Binder->next != last) {
2506 Binder = Binder->next;
2507 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ??
2508 Binder->Cyclic = true;
2509 NoCyclicBonds++;
2510 }
2511 }
2512
2513
2514 *out << Verbose(1) << "Final graph info for each atom is:" << endl;
2515 Walker = start;
2516 while (Walker->next != end) {
2517 Walker = Walker->next;
2518 *out << Verbose(2) << "Atom " << Walker->Name << " is " << ((Walker->SeparationVertex) ? "a" : "not a") << " separation vertex, components are ";
2519 OutputComponentNumber(out, Walker);
2520 *out << " with Lowpoint " << Walker->LowpointNr << " and Graph Nr. " << Walker->GraphNr << "." << endl;
2521 }
2522
2523 *out << Verbose(1) << "Final graph info for each bond is:" << endl;
2524 Binder = first;
2525 while(Binder->next != last) {
2526 Binder = Binder->next;
2527 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
2528 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
2529 OutputComponentNumber(out, Binder->leftatom);
2530 *out << " === ";
2531 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
2532 OutputComponentNumber(out, Binder->rightatom);
2533 *out << ">." << endl;
2534 if (Binder->Cyclic) // cyclic ??
2535 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl;
2536 }
2537
2538 // free all and exit
2539 delete(AtomStack);
2540 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl;
2541 return SubGraphs;
2542};
2543
2544/** Analyses the cycles found and returns minimum of all cycle lengths.
2545 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
2546 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
2547 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
2548 * as cyclic and print out the cycles.
2549 * \param *out output stream for debugging
2550 * \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!
2551 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
2552 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
2553 */
2554void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize)
2555{
2556 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList");
2557 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList");
2558 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CyclicStructureAnalysis: *ColorList");
2559 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring
2560 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop)
2561 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL;
2562 bond *Binder = NULL, *BackEdge = NULL;
2563 int RingSize, NumCycles, MinRingSize = -1;
2564
2565 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
2566 for (int i=AtomCount;i--;) {
2567 PredecessorList[i] = NULL;
2568 ShortestPathList[i] = -1;
2569 ColorList[i] = white;
2570 }
2571
2572 *out << Verbose(1) << "Back edge list - ";
2573 BackEdgeStack->Output(out);
2574
2575 *out << Verbose(1) << "Analysing cycles ... " << endl;
2576 NumCycles = 0;
2577 while (!BackEdgeStack->IsEmpty()) {
2578 BackEdge = BackEdgeStack->PopFirst();
2579 // this is the target
2580 Root = BackEdge->leftatom;
2581 // this is the source point
2582 Walker = BackEdge->rightatom;
2583 ShortestPathList[Walker->nr] = 0;
2584 BFSStack->ClearStack(); // start with empty BFS stack
2585 BFSStack->Push(Walker);
2586 TouchedStack->Push(Walker);
2587 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
2588 OtherAtom = NULL;
2589 do { // look for Root
2590 Walker = BFSStack->PopFirst();
2591 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
2592 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2593 Binder = ListOfBondsPerAtom[Walker->nr][i];
2594 if (Binder != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
2595 OtherAtom = Binder->GetOtherAtom(Walker);
2596#ifdef ADDHYDROGEN
2597 if (OtherAtom->type->Z != 1) {
2598#endif
2599 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2600 if (ColorList[OtherAtom->nr] == white) {
2601 TouchedStack->Push(OtherAtom);
2602 ColorList[OtherAtom->nr] = lightgray;
2603 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2604 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2605 *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;
2606 //if (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
2607 *out << Verbose(3) << "Putting OtherAtom into queue." << endl;
2608 BFSStack->Push(OtherAtom);
2609 //}
2610 } else {
2611 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
2612 }
2613 if (OtherAtom == Root)
2614 break;
2615#ifdef ADDHYDROGEN
2616 } else {
2617 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl;
2618 ColorList[OtherAtom->nr] = black;
2619 }
2620#endif
2621 } else {
2622 *out << Verbose(2) << "Bond " << *Binder << " not Visiting, is the back edge." << endl;
2623 }
2624 }
2625 ColorList[Walker->nr] = black;
2626 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2627 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
2628 // step through predecessor list
2629 while (OtherAtom != BackEdge->rightatom) {
2630 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
2631 break;
2632 else
2633 OtherAtom = PredecessorList[OtherAtom->nr];
2634 }
2635 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
2636 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;\
2637 do {
2638 OtherAtom = TouchedStack->PopLast();
2639 if (PredecessorList[OtherAtom->nr] == Walker) {
2640 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl;
2641 PredecessorList[OtherAtom->nr] = NULL;
2642 ShortestPathList[OtherAtom->nr] = -1;
2643 ColorList[OtherAtom->nr] = white;
2644 BFSStack->RemoveItem(OtherAtom);
2645 }
2646 } while ((!TouchedStack->IsEmpty()) && (PredecessorList[OtherAtom->nr] == NULL));
2647 TouchedStack->Push(OtherAtom); // last was wrongly popped
2648 OtherAtom = BackEdge->rightatom; // set to not Root
2649 } else
2650 OtherAtom = Root;
2651 }
2652 } while ((!BFSStack->IsEmpty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr])));
2653
2654 if (OtherAtom == Root) {
2655 // now climb back the predecessor list and thus find the cycle members
2656 NumCycles++;
2657 RingSize = 1;
2658 Root->GetTrueFather()->IsCyclic = true;
2659 *out << Verbose(1) << "Found ring contains: ";
2660 Walker = Root;
2661 while (Walker != BackEdge->rightatom) {
2662 *out << Walker->Name << " <-> ";
2663 Walker = PredecessorList[Walker->nr];
2664 Walker->GetTrueFather()->IsCyclic = true;
2665 RingSize++;
2666 }
2667 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl;
2668 // walk through all and set MinimumRingSize
2669 Walker = Root;
2670 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
2671 while (Walker != BackEdge->rightatom) {
2672 Walker = PredecessorList[Walker->nr];
2673 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr])
2674 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
2675 }
2676 if ((RingSize < MinRingSize) || (MinRingSize == -1))
2677 MinRingSize = RingSize;
2678 } else {
2679 *out << Verbose(1) << "No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl;
2680 }
2681
2682 // now clean the lists
2683 while (!TouchedStack->IsEmpty()){
2684 Walker = TouchedStack->PopFirst();
2685 PredecessorList[Walker->nr] = NULL;
2686 ShortestPathList[Walker->nr] = -1;
2687 ColorList[Walker->nr] = white;
2688 }
2689 }
2690 if (MinRingSize != -1) {
2691 // go over all atoms
2692 Root = start;
2693 while(Root->next != end) {
2694 Root = Root->next;
2695
2696 if (MinimumRingSize[Root->GetTrueFather()->nr] == AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is
2697 Walker = Root;
2698 ShortestPathList[Walker->nr] = 0;
2699 BFSStack->ClearStack(); // start with empty BFS stack
2700 BFSStack->Push(Walker);
2701 TouchedStack->Push(Walker);
2702 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
2703 OtherAtom = Walker;
2704 while (OtherAtom != NULL) { // look for Root
2705 Walker = BFSStack->PopFirst();
2706 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
2707 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2708 Binder = ListOfBondsPerAtom[Walker->nr][i];
2709 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
2710 OtherAtom = Binder->GetOtherAtom(Walker);
2711 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2712 if (ColorList[OtherAtom->nr] == white) {
2713 TouchedStack->Push(OtherAtom);
2714 ColorList[OtherAtom->nr] = lightgray;
2715 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2716 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2717 //*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;
2718 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
2719 MinimumRingSize[Root->GetTrueFather()->nr] = ShortestPathList[OtherAtom->nr]+MinimumRingSize[OtherAtom->GetTrueFather()->nr];
2720 OtherAtom = NULL; //break;
2721 break;
2722 } else
2723 BFSStack->Push(OtherAtom);
2724 } else {
2725 //*out << Verbose(3) << "Not Adding, has already been visited." << endl;
2726 }
2727 } else {
2728 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl;
2729 }
2730 }
2731 ColorList[Walker->nr] = black;
2732 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2733 }
2734
2735 // now clean the lists
2736 while (!TouchedStack->IsEmpty()){
2737 Walker = TouchedStack->PopFirst();
2738 PredecessorList[Walker->nr] = NULL;
2739 ShortestPathList[Walker->nr] = -1;
2740 ColorList[Walker->nr] = white;
2741 }
2742 }
2743 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl;
2744 }
2745 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl;
2746 } else
2747 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
2748
2749 Free((void **)&PredecessorList, "molecule::CyclicStructureAnalysis: **PredecessorList");
2750 Free((void **)&ShortestPathList, "molecule::CyclicStructureAnalysis: **ShortestPathList");
2751 Free((void **)&ColorList, "molecule::CyclicStructureAnalysis: **ColorList");
2752 delete(BFSStack);
2753};
2754
2755/** Sets the next component number.
2756 * This is O(N) as the number of bonds per atom is bound.
2757 * \param *vertex atom whose next atom::*ComponentNr is to be set
2758 * \param nr number to use
2759 */
2760void molecule::SetNextComponentNumber(atom *vertex, int nr)
2761{
2762 int i=0;
2763 if (vertex != NULL) {
2764 for(;i<NumberOfBondsPerAtom[vertex->nr];i++) {
2765 if (vertex->ComponentNr[i] == -1) { // check if not yet used
2766 vertex->ComponentNr[i] = nr;
2767 break;
2768 }
2769 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
2770 break; // breaking here will not cause error!
2771 }
2772 if (i == NumberOfBondsPerAtom[vertex->nr])
2773 cerr << "Error: All Component entries are already occupied!" << endl;
2774 } else
2775 cerr << "Error: Given vertex is NULL!" << endl;
2776};
2777
2778/** Output a list of flags, stating whether the bond was visited or not.
2779 * \param *out output stream for debugging
2780 */
2781void molecule::OutputComponentNumber(ofstream *out, atom *vertex)
2782{
2783 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
2784 *out << vertex->ComponentNr[i] << " ";
2785};
2786
2787/** Allocates memory for all atom::*ComponentNr in this molecule and sets each entry to -1.
2788 */
2789void molecule::InitComponentNumbers()
2790{
2791 atom *Walker = start;
2792 while(Walker->next != end) {
2793 Walker = Walker->next;
2794 if (Walker->ComponentNr != NULL)
2795 Free((void **)&Walker->ComponentNr, "molecule::InitComponentNumbers: **Walker->ComponentNr");
2796 Walker->ComponentNr = (int *) Malloc(sizeof(int)*NumberOfBondsPerAtom[Walker->nr], "molecule::InitComponentNumbers: *Walker->ComponentNr");
2797 for (int i=NumberOfBondsPerAtom[Walker->nr];i--;)
2798 Walker->ComponentNr[i] = -1;
2799 }
2800};
2801
2802/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
2803 * \param *vertex atom to regard
2804 * \return bond class or NULL
2805 */
2806bond * molecule::FindNextUnused(atom *vertex)
2807{
2808 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
2809 if (ListOfBondsPerAtom[vertex->nr][i]->IsUsed() == white)
2810 return(ListOfBondsPerAtom[vertex->nr][i]);
2811 return NULL;
2812};
2813
2814/** Resets bond::Used flag of all bonds in this molecule.
2815 * \return true - success, false - -failure
2816 */
2817void molecule::ResetAllBondsToUnused()
2818{
2819 bond *Binder = first;
2820 while (Binder->next != last) {
2821 Binder = Binder->next;
2822 Binder->ResetUsed();
2823 }
2824};
2825
2826/** Resets atom::nr to -1 of all atoms in this molecule.
2827 */
2828void molecule::ResetAllAtomNumbers()
2829{
2830 atom *Walker = start;
2831 while (Walker->next != end) {
2832 Walker = Walker->next;
2833 Walker->GraphNr = -1;
2834 }
2835};
2836
2837/** Output a list of flags, stating whether the bond was visited or not.
2838 * \param *out output stream for debugging
2839 * \param *list
2840 */
2841void OutputAlreadyVisited(ofstream *out, int *list)
2842{
2843 *out << Verbose(4) << "Already Visited Bonds:\t";
2844 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " ";
2845 *out << endl;
2846};
2847
2848/** Estimates by educated guessing (using upper limit) the expected number of fragments.
2849 * The upper limit is
2850 * \f[
2851 * n = N \cdot C^k
2852 * \f]
2853 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
2854 * \param *out output stream for debugging
2855 * \param order bond order k
2856 * \return number n of fragments
2857 */
2858int molecule::GuesstimateFragmentCount(ofstream *out, int order)
2859{
2860 int c = 0;
2861 int FragmentCount;
2862 // get maximum bond degree
2863 atom *Walker = start;
2864 while (Walker->next != end) {
2865 Walker = Walker->next;
2866 c = (NumberOfBondsPerAtom[Walker->nr] > c) ? NumberOfBondsPerAtom[Walker->nr] : c;
2867 }
2868 FragmentCount = NoNonHydrogen*(1 << (c*order));
2869 *out << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl;
2870 return FragmentCount;
2871};
2872
2873/** Scans a single line for number and puts them into \a KeySet.
2874 * \param *out output stream for debugging
2875 * \param *buffer buffer to scan
2876 * \param &CurrentSet filled KeySet on return
2877 * \return true - at least one valid atom id parsed, false - CurrentSet is empty
2878 */
2879bool molecule::ScanBufferIntoKeySet(ofstream *out, char *buffer, KeySet &CurrentSet)
2880{
2881 stringstream line;
2882 int AtomNr;
2883 int status = 0;
2884
2885 line.str(buffer);
2886 while (!line.eof()) {
2887 line >> AtomNr;
2888 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
2889 CurrentSet.insert(AtomNr); // insert at end, hence in same order as in file!
2890 status++;
2891 } // else it's "-1" or else and thus must not be added
2892 }
2893 *out << Verbose(1) << "The scanned KeySet is ";
2894 for(KeySet::iterator runner = CurrentSet.begin(); runner != CurrentSet.end(); runner++) {
2895 *out << (*runner) << "\t";
2896 }
2897 *out << endl;
2898 return (status != 0);
2899};
2900
2901/** Parses the KeySet file and fills \a *FragmentList from the known molecule structure.
2902 * Does two-pass scanning:
2903 * -# Scans the keyset file and initialises a temporary graph
2904 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
2905 * Finally, the temporary graph is inserted into the given \a FragmentList for return.
2906 * \param *out output stream for debugging
2907 * \param *path path to file
2908 * \param *FragmentList empty, filled on return
2909 * \return true - parsing successfully, false - failure on parsing (FragmentList will be NULL)
2910 */
2911bool molecule::ParseKeySetFile(ofstream *out, char *path, Graph *&FragmentList)
2912{
2913 bool status = true;
2914 ifstream InputFile;
2915 stringstream line;
2916 GraphTestPair testGraphInsert;
2917 int NumberOfFragments = 0;
2918 double TEFactor;
2919 char *filename = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - filename");
2920
2921 if (FragmentList == NULL) { // check list pointer
2922 FragmentList = new Graph;
2923 }
2924
2925 // 1st pass: open file and read
2926 *out << Verbose(1) << "Parsing the KeySet file ... " << endl;
2927 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, KEYSETFILE);
2928 InputFile.open(filename);
2929 if (InputFile != NULL) {
2930 // each line represents a new fragment
2931 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - *buffer");
2932 // 1. parse keysets and insert into temp. graph
2933 while (!InputFile.eof()) {
2934 InputFile.getline(buffer, MAXSTRINGSIZE);
2935 KeySet CurrentSet;
2936 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(out, buffer, CurrentSet))) { // if at least one valid atom was added, write config
2937 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1))); // store fragment number and current factor
2938 if (!testGraphInsert.second) {
2939 cerr << "KeySet file must be corrupt as there are two equal key sets therein!" << endl;
2940 }
2941 //FragmentList->ListOfMolecules[NumberOfFragments++] = StoreFragmentFromKeySet(out, CurrentSet, IsAngstroem);
2942 }
2943 }
2944 // 2. Free and done
2945 InputFile.close();
2946 InputFile.clear();
2947 Free((void **)&buffer, "molecule::ParseKeySetFile - *buffer");
2948 *out << Verbose(1) << "done." << endl;
2949 } else {
2950 *out << Verbose(1) << "File " << filename << " not found." << endl;
2951 status = false;
2952 }
2953
2954 // 2nd pass: open TEFactors file and read
2955 *out << Verbose(1) << "Parsing the TEFactors file ... " << endl;
2956 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, TEFACTORSFILE);
2957 InputFile.open(filename);
2958 if (InputFile != NULL) {
2959 // 3. add found TEFactors to each keyset
2960 NumberOfFragments = 0;
2961 for(Graph::iterator runner = FragmentList->begin();runner != FragmentList->end(); runner++) {
2962 if (!InputFile.eof()) {
2963 InputFile >> TEFactor;
2964 (*runner).second.second = TEFactor;
2965 *out << Verbose(2) << "Setting " << ++NumberOfFragments << " fragment's TEFactor to " << (*runner).second.second << "." << endl;
2966 } else {
2967 status = false;
2968 break;
2969 }
2970 }
2971 // 4. Free and done
2972 InputFile.close();
2973 *out << Verbose(1) << "done." << endl;
2974 } else {
2975 *out << Verbose(1) << "File " << filename << " not found." << endl;
2976 status = false;
2977 }
2978
2979 // free memory
2980 Free((void **)&filename, "molecule::ParseKeySetFile - filename");
2981
2982 return status;
2983};
2984
2985/** Stores keysets and TEFactors to file.
2986 * \param *out output stream for debugging
2987 * \param KeySetList Graph with Keysets and factors
2988 * \param *path path to file
2989 * \return true - file written successfully, false - writing failed
2990 */
2991bool molecule::StoreKeySetFile(ofstream *out, Graph &KeySetList, char *path)
2992{
2993 ofstream output;
2994 bool status = true;
2995 string line;
2996
2997 // open KeySet file
2998 line = path;
2999 line.append("/");
3000 line += FRAGMENTPREFIX;
3001 line += KEYSETFILE;
3002 output.open(line.c_str(), ios::out);
3003 *out << Verbose(1) << "Saving key sets of the total graph ... ";
3004 if(output != NULL) {
3005 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) {
3006 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
3007 if (sprinter != (*runner).first.begin())
3008 output << "\t";
3009 output << *sprinter;
3010 }
3011 output << endl;
3012 }
3013 *out << "done." << endl;
3014 } else {
3015 cerr << "Unable to open " << line << " for writing keysets!" << endl;
3016 status = false;
3017 }
3018 output.close();
3019 output.clear();
3020
3021 // open TEFactors file
3022 line = path;
3023 line.append("/");
3024 line += FRAGMENTPREFIX;
3025 line += TEFACTORSFILE;
3026 output.open(line.c_str(), ios::out);
3027 *out << Verbose(1) << "Saving TEFactors of the total graph ... ";
3028 if(output != NULL) {
3029 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++)
3030 output << (*runner).second.second << endl;
3031 *out << Verbose(1) << "done." << endl;
3032 } else {
3033 *out << Verbose(1) << "failed to open " << line << "." << endl;
3034 status = false;
3035 }
3036 output.close();
3037
3038 return status;
3039};
3040
3041/** Storing the bond structure of a molecule to file.
3042 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
3043 * \param *out output stream for debugging
3044 * \param *path path to file
3045 * \return true - file written successfully, false - writing failed
3046 */
3047bool molecule::StoreAdjacencyToFile(ofstream *out, char *path)
3048{
3049 ofstream AdjacencyFile;
3050 atom *Walker = NULL;
3051 stringstream line;
3052 bool status = true;
3053
3054 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
3055 AdjacencyFile.open(line.str().c_str(), ios::out);
3056 *out << Verbose(1) << "Saving adjacency list ... ";
3057 if (AdjacencyFile != NULL) {
3058 Walker = start;
3059 while(Walker->next != end) {
3060 Walker = Walker->next;
3061 AdjacencyFile << Walker->nr << "\t";
3062 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
3063 AdjacencyFile << ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker)->nr << "\t";
3064 AdjacencyFile << endl;
3065 }
3066 AdjacencyFile.close();
3067 *out << Verbose(1) << "done." << endl;
3068 } else {
3069 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
3070 status = false;
3071 }
3072
3073 return status;
3074};
3075
3076/** Checks contents of adjacency file against bond structure in structure molecule.
3077 * \param *out output stream for debugging
3078 * \param *path path to file
3079 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
3080 * \return true - structure is equal, false - not equivalence
3081 */
3082bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms)
3083{
3084 ifstream File;
3085 stringstream filename;
3086 bool status = true;
3087 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
3088
3089 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
3090 File.open(filename.str().c_str(), ios::out);
3091 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... ";
3092 if (File != NULL) {
3093 // allocate storage structure
3094 int NonMatchNumber = 0; // will number of atoms with differing bond structure
3095 int *CurrentBonds = (int *) Malloc(sizeof(int)*8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
3096 int CurrentBondsOfAtom;
3097
3098 // Parse the file line by line and count the bonds
3099 while (!File.eof()) {
3100 File.getline(buffer, MAXSTRINGSIZE);
3101 stringstream line;
3102 line.str(buffer);
3103 int AtomNr = -1;
3104 line >> AtomNr;
3105 CurrentBondsOfAtom = -1; // we count one too far due to line end
3106 // parse into structure
3107 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
3108 while (!line.eof())
3109 line >> CurrentBonds[ ++CurrentBondsOfAtom ];
3110 // compare against present bonds
3111 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
3112 if (CurrentBondsOfAtom == NumberOfBondsPerAtom[AtomNr]) {
3113 for(int i=0;i<NumberOfBondsPerAtom[AtomNr];i++) {
3114 int id = ListOfBondsPerAtom[AtomNr][i]->GetOtherAtom(ListOfAtoms[AtomNr])->nr;
3115 int j = 0;
3116 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds
3117 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms
3118 ListOfAtoms[AtomNr] = NULL;
3119 NonMatchNumber++;
3120 status = false;
3121 //out << "[" << id << "]\t";
3122 } else {
3123 //out << id << "\t";
3124 }
3125 }
3126 //out << endl;
3127 } else {
3128 *out << "Number of bonds for Atom " << *ListOfAtoms[AtomNr] << " does not match, parsed " << CurrentBondsOfAtom << " against " << NumberOfBondsPerAtom[AtomNr] << "." << endl;
3129 status = false;
3130 }
3131 }
3132 }
3133 File.close();
3134 File.clear();
3135 if (status) { // if equal we parse the KeySetFile
3136 *out << Verbose(1) << "done: Equal." << endl;
3137 status = true;
3138 } else
3139 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
3140 Free((void **)&CurrentBonds, "molecule::CheckAdjacencyFileAgainstMolecule - **CurrentBonds");
3141 } else {
3142 *out << Verbose(1) << "Adjacency file not found." << endl;
3143 status = false;
3144 }
3145 *out << endl;
3146 Free((void **)&buffer, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
3147
3148 return status;
3149};
3150
3151/** Checks whether the OrderAtSite is still below \a Order at some site.
3152 * \param *out output stream for debugging
3153 * \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
3154 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
3155 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
3156 * \param *MinimumRingSize array of max. possible order to avoid loops
3157 * \param *path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
3158 * \return true - needs further fragmentation, false - does not need fragmentation
3159 */
3160bool molecule::CheckOrderAtSite(ofstream *out, bool *AtomMask, Graph *GlobalKeySetList, int Order, int *MinimumRingSize, char *path)
3161{
3162 atom *Walker = start;
3163 bool status = false;
3164 ifstream InputFile;
3165
3166 // initialize mask list
3167 for(int i=AtomCount;i--;)
3168 AtomMask[i] = false;
3169
3170 if (Order < 0) { // adaptive increase of BondOrder per site
3171 if (AtomMask[AtomCount] == true) // break after one step
3172 return false;
3173 // parse the EnergyPerFragment file
3174 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckOrderAtSite: *buffer");
3175 sprintf(buffer, "%s/%s%s.dat", path, FRAGMENTPREFIX, ENERGYPERFRAGMENT);
3176 InputFile.open(buffer, ios::in);
3177 if ((InputFile != NULL) && (GlobalKeySetList != NULL)) {
3178 // transmorph graph keyset list into indexed KeySetList
3179 map<int,KeySet> IndexKeySetList;
3180 for(Graph::iterator runner = GlobalKeySetList->begin(); runner != GlobalKeySetList->end(); runner++) {
3181 IndexKeySetList.insert( pair<int,KeySet>(runner->second.first,runner->first) );
3182 }
3183 int lines = 0;
3184 // count the number of lines, i.e. the number of fragments
3185 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
3186 InputFile.getline(buffer, MAXSTRINGSIZE);
3187 while(!InputFile.eof()) {
3188 InputFile.getline(buffer, MAXSTRINGSIZE);
3189 lines++;
3190 }
3191 //*out << Verbose(2) << "Scanned " << lines-1 << " lines." << endl; // one endline too much
3192 InputFile.clear();
3193 InputFile.seekg(ios::beg);
3194 map<int, pair<double,int> > AdaptiveCriteriaList; // (Root No., (Value, Order)) !
3195 int No, FragOrder;
3196 double Value;
3197 // each line represents a fragment root (Atom::nr) id and its energy contribution
3198 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
3199 InputFile.getline(buffer, MAXSTRINGSIZE);
3200 while(!InputFile.eof()) {
3201 InputFile.getline(buffer, MAXSTRINGSIZE);
3202 if (strlen(buffer) > 2) {
3203 //*out << Verbose(2) << "Scanning: " << buffer << endl;
3204 stringstream line(buffer);
3205 line >> FragOrder;
3206 line >> ws >> No;
3207 line >> ws >> Value; // skip time entry
3208 line >> ws >> Value;
3209 No -= 1; // indices start at 1 in file, not 0
3210 //*out << Verbose(2) << " - yields (" << No << "," << Value << ", " << FragOrder << ")" << endl;
3211
3212 // clean the list of those entries that have been superceded by higher order terms already
3213 map<int,KeySet>::iterator marker = IndexKeySetList.find(No); // find keyset to Frag No.
3214 if (marker != IndexKeySetList.end()) { // if found
3215 Value *= 1 + MYEPSILON*(*((*marker).second.begin())); // in case of equal energies this makes em not equal without changing anything actually
3216 // 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
3217 pair <map<int, pair<double,int> >::iterator, bool> InsertedElement = AdaptiveCriteriaList.insert( make_pair(*((*marker).second.begin()), pair<double,int>( fabs(Value), FragOrder) ));
3218 map<int, pair<double,int> >::iterator PresentItem = InsertedElement.first;
3219 if (!InsertedElement.second) { // this root is already present
3220 if ((*PresentItem).second.second < FragOrder) // if order there is lower, update entry with higher-order term
3221 //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)
3222 { // if value is smaller, update value and order
3223 (*PresentItem).second.first = fabs(Value);
3224 (*PresentItem).second.second = FragOrder;
3225 *out << Verbose(2) << "Updated element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;
3226 } else {
3227 *out << Verbose(2) << "Did not update element " << (*PresentItem).first << " as " << FragOrder << " is less than or equal to " << (*PresentItem).second.second << "." << endl;
3228 }
3229 } else {
3230 *out << Verbose(2) << "Inserted element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;
3231 }
3232 } else {
3233 *out << Verbose(1) << "No Fragment under No. " << No << "found." << endl;
3234 }
3235 }
3236 }
3237 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
3238 map<double, pair<int,int> > FinalRootCandidates;
3239 *out << Verbose(1) << "Root candidate list is: " << endl;
3240 for(map<int, pair<double,int> >::iterator runner = AdaptiveCriteriaList.begin(); runner != AdaptiveCriteriaList.end(); runner++) {
3241 Walker = FindAtom((*runner).first);
3242 if (Walker != NULL) {
3243 //if ((*runner).second.second >= Walker->AdaptiveOrder) { // only insert if this is an "active" root site for the current order
3244 if (!Walker->MaxOrder) {
3245 *out << Verbose(2) << "(" << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "])" << endl;
3246 FinalRootCandidates.insert( make_pair( (*runner).second.first, pair<int,int>((*runner).first, (*runner).second.second) ) );
3247 } else {
3248 *out << Verbose(2) << "Excluding (" << *Walker << ", " << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "]), as it has reached its maximum order." << endl;
3249 }
3250 } else {
3251 cerr << "Atom No. " << (*runner).second.first << " was not found in this molecule." << endl;
3252 }
3253 }
3254 // pick the ones still below threshold and mark as to be adaptively updated
3255 for(map<double, pair<int,int> >::iterator runner = FinalRootCandidates.upper_bound(pow(10.,Order)); runner != FinalRootCandidates.end(); runner++) {
3256 No = (*runner).second.first;
3257 Walker = FindAtom(No);
3258 //if (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]) {
3259 *out << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", setting entry " << No << " of Atom mask to true." << endl;
3260 AtomMask[No] = true;
3261 status = true;
3262 //} else
3263 //*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;
3264 }
3265 // close and done
3266 InputFile.close();
3267 InputFile.clear();
3268 } else {
3269 cerr << "Unable to parse " << buffer << " file, incrementing all." << endl;
3270 while (Walker->next != end) {
3271 Walker = Walker->next;
3272 #ifdef ADDHYDROGEN
3273 if (Walker->type->Z != 1) // skip hydrogen
3274 #endif
3275 {
3276 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms
3277 status = true;
3278 }
3279 }
3280 }
3281 Free((void **)&buffer, "molecule::CheckOrderAtSite: *buffer");
3282 // pick a given number of highest values and set AtomMask
3283 } else { // global increase of Bond Order
3284 while (Walker->next != end) {
3285 Walker = Walker->next;
3286 #ifdef ADDHYDROGEN
3287 if (Walker->type->Z != 1) // skip hydrogen
3288 #endif
3289 {
3290 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms
3291 if ((Order != 0) && (Walker->AdaptiveOrder < Order)) // && (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]))
3292 status = true;
3293 }
3294 }
3295 if ((Order == 0) && (AtomMask[AtomCount] == false)) // single stepping, just check
3296 status = true;
3297
3298 if (!status) {
3299 if (Order == 0)
3300 *out << Verbose(1) << "Single stepping done." << endl;
3301 else
3302 *out << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl;
3303 }
3304 }
3305
3306 // print atom mask for debugging
3307 *out << " ";
3308 for(int i=0;i<AtomCount;i++)
3309 *out << (i % 10);
3310 *out << endl << "Atom mask is: ";
3311 for(int i=0;i<AtomCount;i++)
3312 *out << (AtomMask[i] ? "t" : "f");
3313 *out << endl;
3314
3315 return status;
3316};
3317
3318/** Create a SortIndex to map from atomic labels to the sequence in which the atoms are given in the config file.
3319 * \param *out output stream for debugging
3320 * \param *&SortIndex Mapping array of size molecule::AtomCount
3321 * \return true - success, false - failure of SortIndex alloc
3322 */
3323bool molecule::CreateMappingLabelsToConfigSequence(ofstream *out, int *&SortIndex)
3324{
3325 element *runner = elemente->start;
3326 int AtomNo = 0;
3327 atom *Walker = NULL;
3328
3329 if (SortIndex != NULL) {
3330 *out << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl;
3331 return false;
3332 }
3333 SortIndex = (int *) Malloc(sizeof(int)*AtomCount, "molecule::FragmentMolecule: *SortIndex");
3334 for(int i=AtomCount;i--;)
3335 SortIndex[i] = -1;
3336 while (runner->next != elemente->end) { // go through every element
3337 runner = runner->next;
3338 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
3339 Walker = start;
3340 while (Walker->next != end) { // go through every atom of this element
3341 Walker = Walker->next;
3342 if (Walker->type->Z == runner->Z) // if this atom fits to element
3343 SortIndex[Walker->nr] = AtomNo++;
3344 }
3345 }
3346 }
3347 return true;
3348};
3349
3350/** Performs a many-body bond order analysis for a given bond order.
3351 * -# parses adjacency, keysets and orderatsite files
3352 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
3353 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
3354y contribution", and that's why this consciously not done in the following loop)
3355 * -# in a loop over all subgraphs
3356 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
3357 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
3358 * -# combines the generated molecule lists from all subgraphs
3359 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
3360 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
3361 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
3362 * subgraph in the MoleculeListClass.
3363 * \param *out output stream for debugging
3364 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
3365 * \param *configuration configuration for writing config files for each fragment
3366 * \return 1 - continue, 2 - stop (no fragmentation occured)
3367 */
3368int molecule::FragmentMolecule(ofstream *out, int Order, config *configuration)
3369{
3370 MoleculeListClass *BondFragments = NULL;
3371 int *SortIndex = NULL;
3372 int *MinimumRingSize = new int[AtomCount];
3373 int FragmentCounter;
3374 MoleculeLeafClass *MolecularWalker = NULL;
3375 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
3376 fstream File;
3377 bool FragmentationToDo = true;
3378 class StackClass<bond *> *BackEdgeStack = NULL, *LocalBackEdgeStack = NULL;
3379 bool CheckOrder = false;
3380 Graph **FragmentList = NULL;
3381 Graph *ParsedFragmentList = NULL;
3382 Graph TotalGraph; // graph with all keysets however local numbers
3383 int TotalNumberOfKeySets = 0;
3384 atom **ListOfAtoms = NULL;
3385 atom ***ListOfLocalAtoms = NULL;
3386 bool *AtomMask = NULL;
3387
3388 *out << endl;
3389#ifdef ADDHYDROGEN
3390 *out << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl;
3391#else
3392 *out << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl;
3393#endif
3394
3395 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
3396
3397 // ===== 1. Check whether bond structure is same as stored in files ====
3398
3399 // fill the adjacency list
3400 CreateListOfBondsPerAtom(out);
3401
3402 // create lookup table for Atom::nr
3403 FragmentationToDo = FragmentationToDo && CreateFatherLookupTable(out, start, end, ListOfAtoms, AtomCount);
3404
3405 // === compare it with adjacency file ===
3406 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(out, configuration->configpath, ListOfAtoms);
3407 Free((void **)&ListOfAtoms, "molecule::FragmentMolecule - **ListOfAtoms");
3408
3409 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
3410 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack);
3411 // fill the bond structure of the individually stored subgraphs
3412 Subgraphs->next->FillBondStructureFromReference(out, this, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms
3413 // analysis of the cycles (print rings, get minimum cycle length) for each subgraph
3414 for(int i=AtomCount;i--;)
3415 MinimumRingSize[i] = AtomCount;
3416 MolecularWalker = Subgraphs;
3417 FragmentCounter = 0;
3418 while (MolecularWalker->next != NULL) {
3419 MolecularWalker = MolecularWalker->next;
3420 *out << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl;
3421 LocalBackEdgeStack = new StackClass<bond *> (MolecularWalker->Leaf->BondCount);
3422// // check the list of local atoms for debugging
3423// *out << Verbose(0) << "ListOfLocalAtoms for this subgraph is:" << endl;
3424// for (int i=0;i<AtomCount;i++)
3425// if (ListOfLocalAtoms[FragmentCounter][i] == NULL)
3426// *out << "\tNULL";
3427// else
3428// *out << "\t" << ListOfLocalAtoms[FragmentCounter][i]->Name;
3429 MolecularWalker->Leaf->PickLocalBackEdges(out, ListOfLocalAtoms[FragmentCounter++], BackEdgeStack, LocalBackEdgeStack);
3430 MolecularWalker->Leaf->CyclicStructureAnalysis(out, LocalBackEdgeStack, MinimumRingSize);
3431 delete(LocalBackEdgeStack);
3432 }
3433
3434 // ===== 3. if structure still valid, parse key set file and others =====
3435 FragmentationToDo = FragmentationToDo && ParseKeySetFile(out, configuration->configpath, ParsedFragmentList);
3436
3437 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
3438 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(out, configuration->configpath);
3439
3440 // =================================== Begin of FRAGMENTATION ===============================
3441 // ===== 6a. assign each keyset to its respective subgraph =====
3442 Subgraphs->next->AssignKeySetsToFragment(out, this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, (FragmentCounter = 0), true);
3443
3444 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
3445 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
3446 AtomMask = new bool[AtomCount+1];
3447 AtomMask[AtomCount] = false;
3448 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
3449 while ((CheckOrder = CheckOrderAtSite(out, AtomMask, ParsedFragmentList, Order, MinimumRingSize, configuration->configpath))) {
3450 FragmentationToDo = FragmentationToDo || CheckOrder;
3451 AtomMask[AtomCount] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
3452 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
3453 Subgraphs->next->FillRootStackForSubgraphs(out, RootStack, AtomMask, (FragmentCounter = 0));
3454
3455 // ===== 7. fill the bond fragment list =====
3456 FragmentCounter = 0;
3457 MolecularWalker = Subgraphs;
3458 while (MolecularWalker->next != NULL) {
3459 MolecularWalker = MolecularWalker->next;
3460 *out << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl;
3461 // output ListOfBondsPerAtom for debugging
3462 MolecularWalker->Leaf->OutputListOfBonds(out);
3463 if (MolecularWalker->Leaf->first->next != MolecularWalker->Leaf->last) {
3464
3465 // call BOSSANOVA method
3466 *out << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl;
3467 MolecularWalker->Leaf->FragmentBOSSANOVA(out, FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize);
3468 } else {
3469 cerr << "Subgraph " << MolecularWalker << " has no atoms!" << endl;
3470 }
3471 FragmentCounter++; // next fragment list
3472 }
3473 }
3474 delete[](RootStack);
3475 delete[](AtomMask);
3476 delete(ParsedFragmentList);
3477 delete[](MinimumRingSize);
3478
3479
3480 // ==================================== End of FRAGMENTATION ============================================
3481
3482 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
3483 Subgraphs->next->TranslateIndicesToGlobalIDs(out, FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
3484
3485 // free subgraph memory again
3486 FragmentCounter = 0;
3487 if (Subgraphs != NULL) {
3488 while (Subgraphs->next != NULL) {
3489 Subgraphs = Subgraphs->next;
3490 delete(FragmentList[FragmentCounter++]);
3491 delete(Subgraphs->previous);
3492 }
3493 delete(Subgraphs);
3494 }
3495 Free((void **)&FragmentList, "molecule::FragmentMolecule - **FragmentList");
3496
3497 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
3498 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
3499 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
3500 BondFragments = new MoleculeListClass(TotalGraph.size(), AtomCount);
3501 int k=0;
3502 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
3503 KeySet test = (*runner).first;
3504 *out << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl;
3505 BondFragments->ListOfMolecules[k] = StoreFragmentFromKeySet(out, test, configuration);
3506 k++;
3507 }
3508 *out << k << "/" << BondFragments->NumberOfMolecules << " fragments generated from the keysets." << endl;
3509
3510 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
3511 if (BondFragments->NumberOfMolecules != 0) {
3512 // create the SortIndex from BFS labels to order in the config file
3513 CreateMappingLabelsToConfigSequence(out, SortIndex);
3514
3515 *out << Verbose(1) << "Writing " << BondFragments->NumberOfMolecules << " possible bond fragmentation configs" << endl;
3516 if (BondFragments->OutputConfigForListOfFragments(out, FRAGMENTPREFIX, configuration, SortIndex, true, true))
3517 *out << Verbose(1) << "All configs written." << endl;
3518 else
3519 *out << Verbose(1) << "Some config writing failed." << endl;
3520
3521 // store force index reference file
3522 BondFragments->StoreForcesFile(out, configuration->configpath, SortIndex);
3523
3524 // store keysets file
3525 StoreKeySetFile(out, TotalGraph, configuration->configpath);
3526
3527 // store Adjacency file
3528 StoreAdjacencyToFile(out, configuration->configpath);
3529
3530 // store Hydrogen saturation correction file
3531 BondFragments->AddHydrogenCorrection(out, configuration->configpath);
3532
3533 // store adaptive orders into file
3534 StoreOrderAtSiteFile(out, configuration->configpath);
3535
3536 // restore orbital and Stop values
3537 CalculateOrbitals(*configuration);
3538
3539 // free memory for bond part
3540 *out << Verbose(1) << "Freeing bond memory" << endl;
3541 delete(FragmentList); // remove bond molecule from memory
3542 Free((void **)&SortIndex, "molecule::FragmentMolecule: *SortIndex");
3543 } else
3544 *out << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl;
3545 //} else
3546 // *out << Verbose(1) << "No fragments to store." << endl;
3547 *out << Verbose(0) << "End of bond fragmentation." << endl;
3548
3549 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
3550};
3551
3552
3553/** Picks from a global stack with all back edges the ones in the fragment.
3554 * \param *out output stream for debugging
3555 * \param **ListOfLocalAtoms array of father atom::nr to local atom::nr (reverse of atom::father)
3556 * \param *ReferenceStack stack with all the back egdes
3557 * \param *LocalStack stack to be filled
3558 * \return true - everything ok, false - ReferenceStack was empty
3559 */
3560bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack)
3561{
3562 bool status = true;
3563 if (ReferenceStack->IsEmpty()) {
3564 cerr << "ReferenceStack is empty!" << endl;
3565 return false;
3566 }
3567 bond *Binder = ReferenceStack->PopFirst();
3568 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
3569 atom *Walker = NULL, *OtherAtom = NULL;
3570 ReferenceStack->Push(Binder);
3571
3572 do { // go through all bonds and push local ones
3573 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule
3574 if (Walker == NULL) // if this Walker exists in the subgraph ...
3575 continue;
3576 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through the local list of bonds
3577 OtherAtom = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
3578 if (OtherAtom == ListOfLocalAtoms[Binder->rightatom->nr]) { // found the bond
3579 LocalStack->Push(ListOfBondsPerAtom[Walker->nr][i]);
3580 break;
3581 }
3582 }
3583 Binder = ReferenceStack->PopFirst(); // loop the stack for next item
3584 ReferenceStack->Push(Binder);
3585 } while (FirstBond != Binder);
3586
3587 return status;
3588};
3589
3590/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
3591 * Atoms not present in the file get "-1".
3592 * \param *out output stream for debugging
3593 * \param *path path to file ORDERATSITEFILE
3594 * \return true - file writable, false - not writable
3595 */
3596bool molecule::StoreOrderAtSiteFile(ofstream *out, char *path)
3597{
3598 stringstream line;
3599 ofstream file;
3600
3601 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
3602 file.open(line.str().c_str());
3603 *out << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl;
3604 if (file != NULL) {
3605 atom *Walker = start;
3606 while (Walker->next != end) {
3607 Walker = Walker->next;
3608 file << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << endl;
3609 *out << Verbose(2) << "Storing: " << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << "." << endl;
3610 }
3611 file.close();
3612 *out << Verbose(1) << "done." << endl;
3613 return true;
3614 } else {
3615 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
3616 return false;
3617 }
3618};
3619
3620/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
3621 * Atoms not present in the file get "0".
3622 * \param *out output stream for debugging
3623 * \param *path path to file ORDERATSITEFILEe
3624 * \return true - file found and scanned, false - file not found
3625 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
3626 */
3627bool molecule::ParseOrderAtSiteFromFile(ofstream *out, char *path)
3628{
3629 unsigned char *OrderArray = (unsigned char *) Malloc(sizeof(unsigned char)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
3630 bool *MaxArray = (bool *) Malloc(sizeof(bool)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
3631 bool status;
3632 int AtomNr, value;
3633 stringstream line;
3634 ifstream file;
3635
3636 *out << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl;
3637 for(int i=AtomCount;i--;)
3638 OrderArray[i] = 0;
3639 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
3640 file.open(line.str().c_str());
3641 if (file != NULL) {
3642 for (int i=AtomCount;i--;) { // initialise with 0
3643 OrderArray[i] = 0;
3644 MaxArray[i] = 0;
3645 }
3646 while (!file.eof()) { // parse from file
3647 AtomNr = -1;
3648 file >> AtomNr;
3649 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
3650 file >> value;
3651 OrderArray[AtomNr] = value;
3652 file >> value;
3653 MaxArray[AtomNr] = value;
3654 //*out << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
3655 }
3656 }
3657 atom *Walker = start;
3658 while (Walker->next != end) { // fill into atom classes
3659 Walker = Walker->next;
3660 Walker->AdaptiveOrder = OrderArray[Walker->nr];
3661 Walker->MaxOrder = MaxArray[Walker->nr];
3662 *out << Verbose(2) << *Walker << " gets order " << (int)Walker->AdaptiveOrder << " and is " << (!Walker->MaxOrder ? "not " : " ") << "maxed." << endl;
3663 }
3664 file.close();
3665 *out << Verbose(1) << "done." << endl;
3666 status = true;
3667 } else {
3668 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
3669 status = false;
3670 }
3671 Free((void **)&OrderArray, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
3672 Free((void **)&MaxArray, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
3673
3674 *out << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl;
3675 return status;
3676};
3677
3678/** Creates an 2d array of pointer with an entry for each atom and each bond it has.
3679 * Updates molecule::ListOfBondsPerAtom, molecule::NumberOfBondsPerAtom by parsing through
3680 * bond chain list, using molecule::AtomCount and molecule::BondCount.
3681 * Allocates memory, fills the array and exits
3682 * \param *out output stream for debugging
3683 */
3684void molecule::CreateListOfBondsPerAtom(ofstream *out)
3685{
3686 bond *Binder = NULL;
3687 atom *Walker = NULL;
3688 int TotalDegree;
3689 *out << Verbose(1) << "Begin of Creating ListOfBondsPerAtom: AtomCount = " << AtomCount << "\tBondCount = " << BondCount << "\tNoNonBonds = " << NoNonBonds << "." << endl;
3690
3691 // re-allocate memory
3692 *out << Verbose(2) << "(Re-)Allocating memory." << endl;
3693 if (ListOfBondsPerAtom != NULL) {
3694 for(int i=AtomCount;i--;)
3695 Free((void **)&ListOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom[i]");
3696 Free((void **)&ListOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom");
3697 }
3698 if (NumberOfBondsPerAtom != NULL)
3699 Free((void **)&NumberOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: NumberOfBondsPerAtom");
3700 ListOfBondsPerAtom = (bond ***) Malloc(sizeof(bond **)*AtomCount, "molecule::CreateListOfBondsPerAtom: ***ListOfBondsPerAtom");
3701 NumberOfBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfBondsPerAtom: *NumberOfBondsPerAtom");
3702
3703 // reset bond counts per atom
3704 for(int i=AtomCount;i--;)
3705 NumberOfBondsPerAtom[i] = 0;
3706 // count bonds per atom
3707 Binder = first;
3708 while (Binder->next != last) {
3709 Binder = Binder->next;
3710 NumberOfBondsPerAtom[Binder->leftatom->nr]++;
3711 NumberOfBondsPerAtom[Binder->rightatom->nr]++;
3712 }
3713 for(int i=AtomCount;i--;) {
3714 // allocate list of bonds per atom
3715 ListOfBondsPerAtom[i] = (bond **) Malloc(sizeof(bond *)*NumberOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: **ListOfBondsPerAtom[]");
3716 // clear the list again, now each NumberOfBondsPerAtom marks current free field
3717 NumberOfBondsPerAtom[i] = 0;
3718 }
3719 // fill the list
3720 Binder = first;
3721 while (Binder->next != last) {
3722 Binder = Binder->next;
3723 ListOfBondsPerAtom[Binder->leftatom->nr][NumberOfBondsPerAtom[Binder->leftatom->nr]++] = Binder;
3724 ListOfBondsPerAtom[Binder->rightatom->nr][NumberOfBondsPerAtom[Binder->rightatom->nr]++] = Binder;
3725 }
3726
3727 // output list for debugging
3728 *out << Verbose(3) << "ListOfBondsPerAtom for each atom:" << endl;
3729 Walker = start;
3730 while (Walker->next != end) {
3731 Walker = Walker->next;
3732 *out << Verbose(4) << "Atom " << Walker->Name << "/" << Walker->nr << " with " << NumberOfBondsPerAtom[Walker->nr] << " bonds: ";
3733 TotalDegree = 0;
3734 for (int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
3735 *out << *ListOfBondsPerAtom[Walker->nr][j] << "\t";
3736 TotalDegree += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
3737 }
3738 *out << " -- TotalDegree: " << TotalDegree << endl;
3739 }
3740 *out << Verbose(1) << "End of Creating ListOfBondsPerAtom." << endl << endl;
3741};
3742
3743/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
3744 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
3745 * white and putting into queue.
3746 * \param *out output stream for debugging
3747 * \param *Mol Molecule class to add atoms to
3748 * \param **AddedAtomList list with added atom pointers, index is atom father's number
3749 * \param **AddedBondList list with added bond pointers, index is bond father's number
3750 * \param *Root root vertex for BFS
3751 * \param *Bond bond not to look beyond
3752 * \param BondOrder maximum distance for vertices to add
3753 * \param IsAngstroem lengths are in angstroem or bohrradii
3754 */
3755void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
3756{
3757 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList");
3758 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList");
3759 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList");
3760 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
3761 atom *Walker = NULL, *OtherAtom = NULL;
3762 bond *Binder = NULL;
3763
3764 // add Root if not done yet
3765 AtomStack->ClearStack();
3766 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
3767 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
3768 AtomStack->Push(Root);
3769
3770 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
3771 for (int i=AtomCount;i--;) {
3772 PredecessorList[i] = NULL;
3773 ShortestPathList[i] = -1;
3774 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited
3775 ColorList[i] = lightgray;
3776 else
3777 ColorList[i] = white;
3778 }
3779 ShortestPathList[Root->nr] = 0;
3780
3781 // and go on ... Queue always contains all lightgray vertices
3782 while (!AtomStack->IsEmpty()) {
3783 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
3784 // 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
3785 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
3786 // followed by n+1 till top of stack.
3787 Walker = AtomStack->PopFirst(); // pop oldest added
3788 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl;
3789 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
3790 Binder = ListOfBondsPerAtom[Walker->nr][i];
3791 if (Binder != NULL) { // don't look at bond equal NULL
3792 OtherAtom = Binder->GetOtherAtom(Walker);
3793 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
3794 if (ColorList[OtherAtom->nr] == white) {
3795 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)
3796 ColorList[OtherAtom->nr] = lightgray;
3797 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
3798 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
3799 *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;
3800 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance
3801 *out << Verbose(3);
3802 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
3803 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
3804 *out << "Added OtherAtom " << OtherAtom->Name;
3805 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3806 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3807 AddedBondList[Binder->nr]->Type = Binder->Type;
3808 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
3809 } 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)
3810 *out << "Not adding OtherAtom " << OtherAtom->Name;
3811 if (AddedBondList[Binder->nr] == NULL) {
3812 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3813 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3814 AddedBondList[Binder->nr]->Type = Binder->Type;
3815 *out << ", added Bond " << *(AddedBondList[Binder->nr]);
3816 } else
3817 *out << ", not added Bond ";
3818 }
3819 *out << ", putting OtherAtom into queue." << endl;
3820 AtomStack->Push(OtherAtom);
3821 } else { // out of bond order, then replace
3822 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
3823 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
3824 if (Binder == Bond)
3825 *out << Verbose(3) << "Not Queueing, is the Root bond";
3826 else if (ShortestPathList[OtherAtom->nr] >= BondOrder)
3827 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder;
3828 if (!Binder->Cyclic)
3829 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
3830 if (AddedBondList[Binder->nr] == NULL) {
3831 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
3832 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3833 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3834 AddedBondList[Binder->nr]->Type = Binder->Type;
3835 } else {
3836#ifdef ADDHYDROGEN
3837 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
3838#endif
3839 }
3840 }
3841 }
3842 } else {
3843 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
3844 // This has to be a cyclic bond, check whether it's present ...
3845 if (AddedBondList[Binder->nr] == NULL) {
3846 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) {
3847 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3848 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3849 AddedBondList[Binder->nr]->Type = Binder->Type;
3850 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
3851#ifdef ADDHYDROGEN
3852 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
3853#endif
3854 }
3855 }
3856 }
3857 }
3858 }
3859 ColorList[Walker->nr] = black;
3860 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
3861 }
3862 Free((void **)&PredecessorList, "molecule::BreadthFirstSearchAdd: **PredecessorList");
3863 Free((void **)&ShortestPathList, "molecule::BreadthFirstSearchAdd: **ShortestPathList");
3864 Free((void **)&ColorList, "molecule::BreadthFirstSearchAdd: **ColorList");
3865 delete(AtomStack);
3866};
3867
3868/** Adds bond structure to this molecule from \a Father molecule.
3869 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
3870 * with end points present in this molecule, bond is created in this molecule.
3871 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
3872 * \param *out output stream for debugging
3873 * \param *Father father molecule
3874 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
3875 * \todo not checked, not fully working probably
3876 */
3877bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
3878{
3879 atom *Walker = NULL, *OtherAtom = NULL;
3880 bool status = true;
3881 atom **ParentList = (atom **) Malloc(sizeof(atom *)*Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList");
3882
3883 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
3884
3885 // reset parent list
3886 *out << Verbose(3) << "Resetting ParentList." << endl;
3887 for (int i=Father->AtomCount;i--;)
3888 ParentList[i] = NULL;
3889
3890 // fill parent list with sons
3891 *out << Verbose(3) << "Filling Parent List." << endl;
3892 Walker = start;
3893 while (Walker->next != end) {
3894 Walker = Walker->next;
3895 ParentList[Walker->father->nr] = Walker;
3896 // Outputting List for debugging
3897 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
3898 }
3899
3900 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
3901 *out << Verbose(3) << "Creating bonds." << endl;
3902 Walker = Father->start;
3903 while (Walker->next != Father->end) {
3904 Walker = Walker->next;
3905 if (ParentList[Walker->nr] != NULL) {
3906 if (ParentList[Walker->nr]->father != Walker) {
3907 status = false;
3908 } else {
3909 for (int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) {
3910 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
3911 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
3912 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i] << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
3913 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree);
3914 }
3915 }
3916 }
3917 }
3918 }
3919
3920 Free((void **)&ParentList, "molecule::BuildInducedSubgraph: **ParentList");
3921 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
3922 return status;
3923};
3924
3925
3926/** Looks through a StackClass<atom *> and returns the likeliest removal candiate.
3927 * \param *out output stream for debugging messages
3928 * \param *&Leaf KeySet to look through
3929 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
3930 * \param index of the atom suggested for removal
3931 */
3932int molecule::LookForRemovalCandidate(ofstream *&out, KeySet *&Leaf, int *&ShortestPathList)
3933{
3934 atom *Runner = NULL;
3935 int SP, Removal;
3936
3937 *out << Verbose(2) << "Looking for removal candidate." << endl;
3938 SP = -1; //0; // not -1, so that Root is never removed
3939 Removal = -1;
3940 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
3941 Runner = FindAtom((*runner));
3942 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack
3943 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
3944 SP = ShortestPathList[(*runner)];
3945 Removal = (*runner);
3946 }
3947 }
3948 }
3949 return Removal;
3950};
3951
3952/** Stores a fragment from \a KeySet into \a molecule.
3953 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
3954 * molecule and adds missing hydrogen where bonds were cut.
3955 * \param *out output stream for debugging messages
3956 * \param &Leaflet pointer to KeySet structure
3957 * \param IsAngstroem whether we have Ansgtroem or bohrradius
3958 * \return pointer to constructed molecule
3959 */
3960molecule * molecule::StoreFragmentFromKeySet(ofstream *out, KeySet &Leaflet, bool IsAngstroem)
3961{
3962 atom *Runner = NULL, *FatherOfRunner = NULL, *OtherFather = NULL;
3963 atom **SonList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::StoreFragmentFromStack: **SonList");
3964 molecule *Leaf = new molecule(elemente);
3965 bool LonelyFlag = false;
3966 int size;
3967
3968// *out << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
3969
3970 Leaf->BondDistance = BondDistance;
3971 for(int i=NDIM*2;i--;)
3972 Leaf->cell_size[i] = cell_size[i];
3973
3974 // initialise SonList (indicates when we need to replace a bond with hydrogen instead)
3975 for(int i=AtomCount;i--;)
3976 SonList[i] = NULL;
3977
3978 // first create the minimal set of atoms from the KeySet
3979 size = 0;
3980 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
3981 FatherOfRunner = FindAtom((*runner)); // find the id
3982 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner);
3983 size++;
3984 }
3985
3986 // create the bonds between all: Make it an induced subgraph and add hydrogen
3987// *out << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
3988 Runner = Leaf->start;
3989 while (Runner->next != Leaf->end) {
3990 Runner = Runner->next;
3991 LonelyFlag = true;
3992 FatherOfRunner = Runner->father;
3993 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list
3994 // create all bonds
3995 for (int i=0;i<NumberOfBondsPerAtom[FatherOfRunner->nr];i++) { // go through every bond of father
3996 OtherFather = ListOfBondsPerAtom[FatherOfRunner->nr][i]->GetOtherAtom(FatherOfRunner);
3997// *out << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
3998 if (SonList[OtherFather->nr] != NULL) {
3999// *out << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
4000 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
4001// *out << Verbose(3) << "Adding Bond: ";
4002// *out <<
4003 Leaf->AddBond(Runner, SonList[OtherFather->nr], ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree);
4004// *out << "." << endl;
4005 //NumBonds[Runner->nr]++;
4006 } else {
4007// *out << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
4008 }
4009 LonelyFlag = false;
4010 } else {
4011// *out << ", who has no son in this fragment molecule." << endl;
4012#ifdef ADDHYDROGEN
4013 //*out << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl;
4014 Leaf->AddHydrogenReplacementAtom(out, ListOfBondsPerAtom[FatherOfRunner->nr][i], Runner, FatherOfRunner, OtherFather, ListOfBondsPerAtom[FatherOfRunner->nr],NumberOfBondsPerAtom[FatherOfRunner->nr], IsAngstroem);
4015#endif
4016 //NumBonds[Runner->nr] += ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree;
4017 }
4018 }
4019 } else {
4020 *out << Verbose(0) << "ERROR: Son " << Runner->Name << " has father " << FatherOfRunner->Name << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl;
4021 }
4022 if ((LonelyFlag) && (size > 1)) {
4023 *out << Verbose(0) << *Runner << "has got bonds only to hydrogens!" << endl;
4024 }
4025#ifdef ADDHYDROGEN
4026 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen
4027 Runner = Runner->next;
4028#endif
4029 }
4030 Leaf->CreateListOfBondsPerAtom(out);
4031 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
4032 Free((void **)&SonList, "molecule::StoreFragmentFromStack: **SonList");
4033// *out << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
4034 return Leaf;
4035};
4036
4037/** Creates \a MoleculeListClass of all unique fragments of the \a molecule containing \a Order atoms or vertices.
4038 * The picture to have in mind is that of a DFS "snake" of a certain length \a Order, i.e. as in the infamous
4039 * computer game, that winds through the connected graph representing the molecule. Color (white,
4040 * lightgray, darkgray, black) indicates whether a vertex has been discovered so far or not. Labels will help in
4041 * creating only unique fragments and not additional ones with vertices simply in different sequence.
4042 * The Predecessor is always the one that came before in discovering, needed on backstepping. And
4043 * finally, the ShortestPath is needed for removing vertices from the snake stack during the back-
4044 * stepping.
4045 * \param *out output stream for debugging
4046 * \param Order number of atoms in each fragment
4047 * \param *configuration configuration for writing config files for each fragment
4048 * \return List of all unique fragments with \a Order atoms
4049 */
4050/*
4051MoleculeListClass * molecule::CreateListOfUniqueFragmentsOfOrder(ofstream *out, int Order, config *configuration)
4052{
4053 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
4054 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
4055 int *Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
4056 enum Shading *ColorVertexList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
4057 enum Shading *ColorEdgeList = (enum Shading *) Malloc(sizeof(enum Shading)*BondCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorBondList");
4058 StackClass<atom *> *RootStack = new StackClass<atom *>(AtomCount);
4059 StackClass<atom *> *TouchedStack = new StackClass<atom *>((int)pow(4,Order)+2); // number of atoms reached from one with maximal 4 bonds plus Root itself
4060 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!
4061 MoleculeLeafClass *Leaflet = NULL, *TempLeaf = NULL;
4062 MoleculeListClass *FragmentList = NULL;
4063 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Removal = NULL;
4064 bond *Binder = NULL;
4065 int RunningIndex = 0, FragmentCounter = 0;
4066
4067 *out << Verbose(1) << "Begin of CreateListOfUniqueFragmentsOfOrder." << endl;
4068
4069 // reset parent list
4070 *out << Verbose(3) << "Resetting labels, parent, predecessor, color and shortest path lists." << endl;
4071 for (int i=0;i<AtomCount;i++) { // reset all atom labels
4072 // initialise each vertex as white with no predecessor, empty queue, color lightgray, not labelled, no sons
4073 Labels[i] = -1;
4074 SonList[i] = NULL;
4075 PredecessorList[i] = NULL;
4076 ColorVertexList[i] = white;
4077 ShortestPathList[i] = -1;
4078 }
4079 for (int i=0;i<BondCount;i++)
4080 ColorEdgeList[i] = white;
4081 RootStack->ClearStack(); // clearstack and push first atom if exists
4082 TouchedStack->ClearStack();
4083 Walker = start->next;
4084 while ((Walker != end)
4085#ifdef ADDHYDROGEN
4086 && (Walker->type->Z == 1)
4087#endif
4088 ) { // search for first non-hydrogen atom
4089 *out << Verbose(4) << "Current Root candidate is " << Walker->Name << "." << endl;
4090 Walker = Walker->next;
4091 }
4092 if (Walker != end)
4093 RootStack->Push(Walker);
4094 else
4095 *out << Verbose(0) << "ERROR: Could not find an appropriate Root atom!" << endl;
4096 *out << Verbose(3) << "Root " << Walker->Name << " is on AtomStack, beginning loop through all vertices ..." << endl;
4097
4098 ///// OUTER LOOP ////////////
4099 while (!RootStack->IsEmpty()) {
4100 // get new root vertex from atom stack
4101 Root = RootStack->PopFirst();
4102 ShortestPathList[Root->nr] = 0;
4103 if (Labels[Root->nr] == -1)
4104 Labels[Root->nr] = RunningIndex++; // prevent it from getting again on AtomStack
4105 PredecessorList[Root->nr] = Root;
4106 TouchedStack->Push(Root);
4107 *out << Verbose(0) << "Root for this loop is: " << Root->Name << ".\n";
4108
4109 // clear snake stack
4110 SnakeStack->ClearStack();
4111 //SnakeStack->TestImplementation(out, start->next);
4112
4113 ///// INNER LOOP ////////////
4114 // Problems:
4115 // - what about cyclic bonds?
4116 Walker = Root;
4117 do {
4118 *out << Verbose(1) << "Current Walker is: " << Walker->Name;
4119 // initial setting of the new Walker: label, color, shortest path and put on stacks
4120 if (Labels[Walker->nr] == -1) { // give atom a unique, monotonely increasing number
4121 Labels[Walker->nr] = RunningIndex++;
4122 RootStack->Push(Walker);
4123 }
4124 *out << ", has label " << Labels[Walker->nr];
4125 if ((ColorVertexList[Walker->nr] == white) || ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white))) { // color it if newly discovered and push on stacks (and if within reach!)
4126 if ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white)) {
4127 // Binder ought to be set still from last neighbour search
4128 *out << ", coloring bond " << *Binder << " black";
4129 ColorEdgeList[Binder->nr] = black; // mark this bond as used
4130 }
4131 if (ShortestPathList[Walker->nr] == -1) {
4132 ShortestPathList[Walker->nr] = ShortestPathList[PredecessorList[Walker->nr]->nr]+1;
4133 TouchedStack->Push(Walker); // mark every atom for lists cleanup later, whose shortest path has been changed
4134 }
4135 if ((ShortestPathList[Walker->nr] < Order) && (ColorVertexList[Walker->nr] != darkgray)) { // if not already on snake stack
4136 SnakeStack->Push(Walker);
4137 ColorVertexList[Walker->nr] = darkgray; // mark as dark gray of on snake stack
4138 }
4139 }
4140 *out << ", SP of " << ShortestPathList[Walker->nr] << " and its color is " << GetColor(ColorVertexList[Walker->nr]) << "." << endl;
4141
4142 // then check the stack for a newly stumbled upon fragment
4143 if (SnakeStack->ItemCount() == Order) { // is stack full?
4144 // store the fragment if it is one and get a removal candidate
4145 Removal = StoreFragmentFromStack(out, Root, Walker, Leaflet, SnakeStack, ShortestPathList, SonList, Labels, &FragmentCounter, configuration);
4146 // remove the candidate if one was found
4147 if (Removal != NULL) {
4148 *out << Verbose(2) << "Removing item " << Removal->Name << " with SP of " << ShortestPathList[Removal->nr] << " from snake stack." << endl;
4149 SnakeStack->RemoveItem(Removal);
4150 ColorVertexList[Removal->nr] = lightgray; // return back to not on snake stack but explored marking
4151 if (Walker == Removal) { // if the current atom is to be removed, we also have to take a step back
4152 Walker = PredecessorList[Removal->nr];
4153 *out << Verbose(2) << "Stepping back to " << Walker->Name << "." << endl;
4154 }
4155 }
4156 } else
4157 Removal = NULL;
4158
4159 // finally, look for a white neighbour as the next Walker
4160 Binder = NULL;
4161 if ((Removal == NULL) || (Walker != PredecessorList[Removal->nr])) { // don't look, if a new walker has been set above
4162 *out << Verbose(2) << "Snake has currently " << SnakeStack->ItemCount() << " item(s)." << endl;
4163 OtherAtom = NULL; // this is actually not needed, every atom has at least one neighbour
4164 if (ShortestPathList[Walker->nr] < Order) {
4165 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
4166 Binder = ListOfBondsPerAtom[Walker->nr][i];
4167 *out << Verbose(2) << "Current bond is " << *Binder << ": ";
4168 OtherAtom = Binder->GetOtherAtom(Walker);
4169 if ((Labels[OtherAtom->nr] != -1) && (Labels[OtherAtom->nr] < Labels[Root->nr])) { // we don't step up to labels bigger than us
4170 *out << "Label " << Labels[OtherAtom->nr] << " is smaller than Root's " << Labels[Root->nr] << "." << endl;
4171 //ColorVertexList[OtherAtom->nr] = lightgray; // mark as explored
4172 } else { // otherwise check its colour and element
4173 if (
4174#ifdef ADDHYDROGEN
4175 (OtherAtom->type->Z != 1) &&
4176#endif
4177 (ColorEdgeList[Binder->nr] == white)) { // skip hydrogen, look for unexplored vertices
4178 *out << "Moving along " << GetColor(ColorEdgeList[Binder->nr]) << " bond " << Binder << " to " << ((ColorVertexList[OtherAtom->nr] == white) ? "unexplored" : "explored") << " item: " << OtherAtom->Name << "." << endl;
4179 // i find it currently rather sensible to always set the predecessor in order to find one's way back
4180 //if (PredecessorList[OtherAtom->nr] == NULL) {
4181 PredecessorList[OtherAtom->nr] = Walker;
4182 *out << Verbose(3) << "Setting Predecessor of " << OtherAtom->Name << " to " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
4183 //} else {
4184 // *out << Verbose(3) << "Predecessor of " << OtherAtom->Name << " is " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
4185 //}
4186 Walker = OtherAtom;
4187 break;
4188 } else {
4189 if (OtherAtom->type->Z == 1)
4190 *out << "Links to a hydrogen atom." << endl;
4191 else
4192 *out << "Bond has not white but " << GetColor(ColorEdgeList[Binder->nr]) << " color." << endl;
4193 }
4194 }
4195 }
4196 } else { // means we have stepped beyond the horizon: Return!
4197 Walker = PredecessorList[Walker->nr];
4198 OtherAtom = Walker;
4199 *out << Verbose(3) << "We have gone too far, stepping back to " << Walker->Name << "." << endl;
4200 }
4201 if (Walker != OtherAtom) { // if no white neighbours anymore, color it black
4202 *out << Verbose(2) << "Coloring " << Walker->Name << " black." << endl;
4203 ColorVertexList[Walker->nr] = black;
4204 Walker = PredecessorList[Walker->nr];
4205 }
4206 }
4207 } while ((Walker != Root) || (ColorVertexList[Root->nr] != black));
4208 *out << Verbose(2) << "Inner Looping is finished." << endl;
4209
4210 // if we reset all AtomCount atoms, we have again technically O(N^2) ...
4211 *out << Verbose(2) << "Resetting lists." << endl;
4212 Walker = NULL;
4213 Binder = NULL;
4214 while (!TouchedStack->IsEmpty()) {
4215 Walker = TouchedStack->PopLast();
4216 *out << Verbose(3) << "Re-initialising entries of " << *Walker << "." << endl;
4217 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
4218 ColorEdgeList[ListOfBondsPerAtom[Walker->nr][i]->nr] = white;
4219 PredecessorList[Walker->nr] = NULL;
4220 ColorVertexList[Walker->nr] = white;
4221 ShortestPathList[Walker->nr] = -1;
4222 }
4223 }
4224 *out << Verbose(1) << "Outer Looping over all vertices is done." << endl;
4225
4226 // copy together
4227 *out << Verbose(1) << "Copying all fragments into MoleculeList structure." << endl;
4228 FragmentList = new MoleculeListClass(FragmentCounter, AtomCount);
4229 RunningIndex = 0;
4230 while ((Leaflet != NULL) && (RunningIndex < FragmentCounter)) {
4231 FragmentList->ListOfMolecules[RunningIndex++] = Leaflet->Leaf;
4232 Leaflet->Leaf = NULL; // prevent molecule from being removed
4233 TempLeaf = Leaflet;
4234 Leaflet = Leaflet->previous;
4235 delete(TempLeaf);
4236 };
4237
4238 // free memory and exit
4239 Free((void **)&PredecessorList, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
4240 Free((void **)&ShortestPathList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
4241 Free((void **)&Labels, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
4242 Free((void **)&ColorVertexList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
4243 delete(RootStack);
4244 delete(TouchedStack);
4245 delete(SnakeStack);
4246
4247 *out << Verbose(1) << "End of CreateListOfUniqueFragmentsOfOrder." << endl;
4248 return FragmentList;
4249};
4250*/
4251
4252/** Structure containing all values in power set combination generation.
4253 */
4254struct UniqueFragments {
4255 config *configuration;
4256 atom *Root;
4257 Graph *Leaflet;
4258 KeySet *FragmentSet;
4259 int ANOVAOrder;
4260 int FragmentCounter;
4261 int CurrentIndex;
4262 double TEFactor;
4263 int *ShortestPathList;
4264 bool **UsedList;
4265 bond **BondsPerSPList;
4266 int *BondsPerSPCount;
4267};
4268
4269/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
4270 * -# loops over every possible combination (2^dimension of edge set)
4271 * -# inserts current set, if there's still space left
4272 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
4273ance+1
4274 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
4275 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
4276distance) and current set
4277 * \param *out output stream for debugging
4278 * \param FragmentSearch UniqueFragments structure with all values needed
4279 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
4280 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
4281 * \param SubOrder remaining number of allowed vertices to add
4282 */
4283void molecule::SPFragmentGenerator(ofstream *out, struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
4284{
4285 atom *OtherWalker = NULL;
4286 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
4287 int NumCombinations;
4288 bool bit;
4289 int bits, TouchedIndex, SubSetDimension, SP, Added;
4290 int Removal;
4291 int SpaceLeft;
4292 int *TouchedList = (int *) Malloc(sizeof(int)*(SubOrder+1), "molecule::SPFragmentGenerator: *TouchedList");
4293 bond *Binder = NULL;
4294 bond **BondsList = NULL;
4295 KeySetTestPair TestKeySetInsert;
4296
4297 NumCombinations = 1 << SetDimension;
4298
4299 // Hier muessen von 1 bis NumberOfBondsPerAtom[Walker->nr] alle Kombinationen
4300 // von Endstuecken (aus den Bonds) hinzugefᅵᅵgt werden und fᅵᅵr verbleibende ANOVAOrder
4301 // rekursiv GraphCrawler in der nᅵᅵchsten Ebene aufgerufen werden
4302
4303 *out << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
4304 *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;
4305
4306 // initialised touched list (stores added atoms on this level)
4307 *out << Verbose(1+verbosity) << "Clearing touched list." << endl;
4308 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
4309 TouchedList[TouchedIndex] = -1;
4310 TouchedIndex = 0;
4311
4312 // create every possible combination of the endpieces
4313 *out << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
4314 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
4315 // count the set bit of i
4316 bits = 0;
4317 for (int j=SetDimension;j--;)
4318 bits += (i & (1 << j)) >> j;
4319
4320 *out << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
4321 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
4322 // --1-- add this set of the power set of bond partners to the snake stack
4323 Added = 0;
4324 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
4325 bit = ((i & (1 << j)) != 0); // mask the bit for the j-th bond
4326 if (bit) { // if bit is set, we add this bond partner
4327 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
4328 //*out << Verbose(1+verbosity) << "Current Bond is " << ListOfBondsPerAtom[Walker->nr][i] << ", checking on " << *OtherWalker << "." << endl;
4329 *out << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
4330 TestKeySetInsert = FragmentSearch->FragmentSet->insert(OtherWalker->nr);
4331 if (TestKeySetInsert.second) {
4332 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
4333 Added++;
4334 } else {
4335 *out << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
4336 }
4337 //FragmentSearch->UsedList[OtherWalker->nr][i] = true;
4338 //}
4339 } else {
4340 *out << Verbose(2+verbosity) << "Not adding." << endl;
4341 }
4342 }
4343
4344 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
4345 if (SpaceLeft > 0) {
4346 *out << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
4347 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
4348 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
4349 SP = RootDistance+1; // this is the next level
4350 // first count the members in the subset
4351 SubSetDimension = 0;
4352 Binder = FragmentSearch->BondsPerSPList[2*SP]; // start node for this level
4353 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) { // compare to end node of this level
4354 Binder = Binder->next;
4355 for (int k=TouchedIndex;k--;) {
4356 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
4357 SubSetDimension++;
4358 }
4359 }
4360 // then allocate and fill the list
4361 BondsList = (bond **) Malloc(sizeof(bond *)*SubSetDimension, "molecule::SPFragmentGenerator: **BondsList");
4362 SubSetDimension = 0;
4363 Binder = FragmentSearch->BondsPerSPList[2*SP];
4364 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) {
4365 Binder = Binder->next;
4366 for (int k=0;k<TouchedIndex;k++) {
4367 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
4368 BondsList[SubSetDimension++] = Binder;
4369 }
4370 }
4371 *out << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
4372 SPFragmentGenerator(out, FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
4373 Free((void **)&BondsList, "molecule::SPFragmentGenerator: **BondsList");
4374 }
4375 } else {
4376 // --2-- otherwise store the complete fragment
4377 *out << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
4378 // store fragment as a KeySet
4379 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
4380 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
4381 *out << (*runner) << " ";
4382 *out << endl;
4383 //if (!CheckForConnectedSubgraph(out, FragmentSearch->FragmentSet))
4384 //*out << Verbose(0) << "ERROR: The found fragment is not a connected subgraph!" << endl;
4385 InsertFragmentIntoGraph(out, FragmentSearch);
4386 //Removal = LookForRemovalCandidate(out, FragmentSearch->FragmentSet, FragmentSearch->ShortestPathList);
4387 //Removal = StoreFragmentFromStack(out, FragmentSearch->Root, FragmentSearch->Leaflet, FragmentSearch->FragmentStack, FragmentSearch->ShortestPathList, &FragmentSearch->FragmentCounter, FragmentSearch->configuration);
4388 }
4389
4390 // --3-- remove all added items in this level from snake stack
4391 *out << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
4392 for(int j=0;j<TouchedIndex;j++) {
4393 Removal = TouchedList[j];
4394 *out << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
4395 FragmentSearch->FragmentSet->erase(Removal);
4396 TouchedList[j] = -1;
4397 }
4398 *out << Verbose(2) << "Remaining local nr.s on snake stack are: ";
4399 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
4400 *out << (*runner) << " ";
4401 *out << endl;
4402 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
4403 } else {
4404 *out << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
4405 }
4406 }
4407 Free((void **)&TouchedList, "molecule::SPFragmentGenerator: *TouchedList");
4408 *out << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
4409};
4410
4411/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
4412 * \param *out output stream for debugging
4413 * \param *Fragment Keyset of fragment's vertices
4414 * \return true - connected, false - disconnected
4415 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
4416 */
4417bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment)
4418{
4419 atom *Walker = NULL, *Walker2 = NULL;
4420 bool BondStatus = false;
4421 int size;
4422
4423 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
4424 *out << Verbose(2) << "Disconnected atom: ";
4425
4426 // count number of atoms in graph
4427 size = 0;
4428 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
4429 size++;
4430 if (size > 1)
4431 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
4432 Walker = FindAtom(*runner);
4433 BondStatus = false;
4434 for(KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
4435 Walker2 = FindAtom(*runners);
4436 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
4437 if (ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker) == Walker2) {
4438 BondStatus = true;
4439 break;
4440 }
4441 if (BondStatus)
4442 break;
4443 }
4444 }
4445 if (!BondStatus) {
4446 *out << (*Walker) << endl;
4447 return false;
4448 }
4449 }
4450 else {
4451 *out << "none." << endl;
4452 return true;
4453 }
4454 *out << "none." << endl;
4455
4456 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
4457
4458 return true;
4459}
4460
4461/** 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.
4462 * -# initialises UniqueFragments structure
4463 * -# fills edge list via BFS
4464 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
4465 root distance, the edge set, its dimension and the current suborder
4466 * -# Free'ing structure
4467 * 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
4468 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
4469 * \param *out output stream for debugging
4470 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
4471 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
4472 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
4473 * \return number of inserted fragments
4474 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
4475 */
4476int molecule::PowerSetGenerator(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
4477{
4478 int SP, AtomKeyNr;
4479 atom *Walker = NULL, *OtherWalker = NULL, *Predecessor = NULL;
4480 bond *Binder = NULL;
4481 bond *CurrentEdge = NULL;
4482 bond **BondsList = NULL;
4483 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->nr;
4484 int Counter = FragmentSearch.FragmentCounter;
4485 int RemainingWalkers;
4486
4487 *out << endl;
4488 *out << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl;
4489
4490 // prepare Label and SP arrays of the BFS search
4491 FragmentSearch.ShortestPathList[FragmentSearch.Root->nr] = 0;
4492
4493 // prepare root level (SP = 0) and a loop bond denoting Root
4494 for (int i=1;i<Order;i++)
4495 FragmentSearch.BondsPerSPCount[i] = 0;
4496 FragmentSearch.BondsPerSPCount[0] = 1;
4497 Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
4498 add(Binder, FragmentSearch.BondsPerSPList[1]);
4499
4500 // do a BFS search to fill the SP lists and label the found vertices
4501 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into
4502 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning
4503 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth
4504 // (EdgeinSPLevel) of this tree ...
4505 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence
4506 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction.
4507 *out << endl;
4508 *out << Verbose(0) << "Starting BFS analysis ..." << endl;
4509 for (SP = 0; SP < (Order-1); SP++) {
4510 *out << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)";
4511 if (SP > 0) {
4512 *out << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl;
4513 FragmentSearch.BondsPerSPCount[SP] = 0;
4514 } else
4515 *out << "." << endl;
4516
4517 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
4518 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP]; /// start of this SP level's list
4519 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) { /// end of this SP level's list
4520 CurrentEdge = CurrentEdge->next;
4521 RemainingWalkers--;
4522 Walker = CurrentEdge->rightatom; // rightatom is always the one more distant
4523 Predecessor = CurrentEdge->leftatom; // ... and leftatom is predecessor
4524 AtomKeyNr = Walker->nr;
4525 *out << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl;
4526 // check for new sp level
4527 // go through all its bonds
4528 *out << Verbose(1) << "Going through all bonds of Walker." << endl;
4529 for (int i=0;i<NumberOfBondsPerAtom[AtomKeyNr];i++) {
4530 Binder = ListOfBondsPerAtom[AtomKeyNr][i];
4531 OtherWalker = Binder->GetOtherAtom(Walker);
4532 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end())
4533 #ifdef ADDHYDROGEN
4534 && (OtherWalker->type->Z != 1)
4535 #endif
4536 ) { // skip hydrogens and restrict to fragment
4537 *out << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *Binder << "." << endl;
4538 // set the label if not set (and push on root stack as well)
4539 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->nr > RootKeyNr)) { // only pass through those with label bigger than Root's
4540 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1;
4541 *out << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl;
4542 // add the bond in between to the SP list
4543 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
4544 add(Binder, FragmentSearch.BondsPerSPList[2*(SP+1)+1]);
4545 FragmentSearch.BondsPerSPCount[SP+1]++;
4546 *out << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl;
4547 } else {
4548 if (OtherWalker != Predecessor)
4549 *out << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->nr << " is smaller than that of Root " << RootKeyNr << "." << endl;
4550 else
4551 *out << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl;
4552 }
4553 } else *out << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
4554 }
4555 }
4556 }
4557
4558 // outputting all list for debugging
4559 *out << Verbose(0) << "Printing all found lists." << endl;
4560 for(int i=1;i<Order;i++) { // skip the root edge in the printing
4561 Binder = FragmentSearch.BondsPerSPList[2*i];
4562 *out << Verbose(1) << "Current SP level is " << i << "." << endl;
4563 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4564 Binder = Binder->next;
4565 *out << Verbose(2) << *Binder << endl;
4566 }
4567 }
4568
4569 // creating fragments with the found edge sets (may be done in reverse order, faster)
4570 SP = -1; // the Root <-> Root edge must be subtracted!
4571 for(int i=Order;i--;) { // sum up all found edges
4572 Binder = FragmentSearch.BondsPerSPList[2*i];
4573 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4574 Binder = Binder->next;
4575 SP ++;
4576 }
4577 }
4578 *out << Verbose(0) << "Total number of edges is " << SP << "." << endl;
4579 if (SP >= (Order-1)) {
4580 // start with root (push on fragment stack)
4581 *out << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->nr << "." << endl;
4582 FragmentSearch.FragmentSet->clear();
4583 *out << Verbose(0) << "Preparing subset for this root and calling generator." << endl;
4584 // prepare the subset and call the generator
4585 BondsList = (bond **) Malloc(sizeof(bond *)*FragmentSearch.BondsPerSPCount[0], "molecule::PowerSetGenerator: **BondsList");
4586 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond
4587
4588 SPFragmentGenerator(out, &FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
4589
4590 Free((void **)&BondsList, "molecule::PowerSetGenerator: **BondsList");
4591 } else {
4592 *out << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl;
4593 }
4594
4595 // as FragmentSearch structure is used only once, we don't have to clean it anymore
4596 // remove root from stack
4597 *out << Verbose(0) << "Removing root again from stack." << endl;
4598 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr);
4599
4600 // free'ing the bonds lists
4601 *out << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl;
4602 for(int i=Order;i--;) {
4603 *out << Verbose(1) << "Current SP level is " << i << ": ";
4604 Binder = FragmentSearch.BondsPerSPList[2*i];
4605 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4606 Binder = Binder->next;
4607 // *out << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local
4608 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1;
4609 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1;
4610 }
4611 // delete added bonds
4612 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]);
4613 // also start and end node
4614 *out << "cleaned." << endl;
4615 }
4616
4617 // return list
4618 *out << Verbose(0) << "End of PowerSetGenerator." << endl;
4619 return (FragmentSearch.FragmentCounter - Counter);
4620};
4621
4622/** Corrects the nuclei position if the fragment was created over the cell borders.
4623 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
4624 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
4625 * and re-add the bond. Looping on the distance check.
4626 * \param *out ofstream for debugging messages
4627 */
4628void molecule::ScanForPeriodicCorrection(ofstream *out)
4629{
4630 bond *Binder = NULL;
4631 bond *OtherBinder = NULL;
4632 atom *Walker = NULL;
4633 atom *OtherWalker = NULL;
4634 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
4635 enum Shading *ColorList = NULL;
4636 double tmp;
4637 Vector Translationvector;
4638 //class StackClass<atom *> *CompStack = NULL;
4639 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
4640 bool flag = true;
4641
4642 *out << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl;
4643
4644 ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::ScanForPeriodicCorrection: *ColorList");
4645 while (flag) {
4646 // remove bonds that are beyond bonddistance
4647 for(int i=NDIM;i--;)
4648 Translationvector.x[i] = 0.;
4649 // scan all bonds
4650 Binder = first;
4651 flag = false;
4652 while ((!flag) && (Binder->next != last)) {
4653 Binder = Binder->next;
4654 for (int i=NDIM;i--;) {
4655 tmp = fabs(Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]);
4656 //*out << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
4657 if (tmp > BondDistance) {
4658 OtherBinder = Binder->next; // note down binding partner for later re-insertion
4659 unlink(Binder); // unlink bond
4660 *out << Verbose(2) << "Correcting at bond " << *Binder << "." << endl;
4661 flag = true;
4662 break;
4663 }
4664 }
4665 }
4666 if (flag) {
4667 // create translation vector from their periodically modified distance
4668 for (int i=NDIM;i--;) {
4669 tmp = Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i];
4670 if (fabs(tmp) > BondDistance)
4671 Translationvector.x[i] = (tmp < 0) ? +1. : -1.;
4672 }
4673 Translationvector.MatrixMultiplication(matrix);
4674 //*out << Verbose(3) << "Translation vector is ";
4675 Translationvector.Output(out);
4676 *out << endl;
4677 // apply to all atoms of first component via BFS
4678 for (int i=AtomCount;i--;)
4679 ColorList[i] = white;
4680 AtomStack->Push(Binder->leftatom);
4681 while (!AtomStack->IsEmpty()) {
4682 Walker = AtomStack->PopFirst();
4683 //*out << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
4684 ColorList[Walker->nr] = black; // mark as explored
4685 Walker->x.AddVector(&Translationvector); // translate
4686 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through all binding partners
4687 if (ListOfBondsPerAtom[Walker->nr][i] != Binder) {
4688 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
4689 if (ColorList[OtherWalker->nr] == white) {
4690 AtomStack->Push(OtherWalker); // push if yet unexplored
4691 }
4692 }
4693 }
4694 }
4695 // re-add bond
4696 link(Binder, OtherBinder);
4697 } else {
4698 *out << Verbose(3) << "No corrections for this fragment." << endl;
4699 }
4700 //delete(CompStack);
4701 }
4702
4703 // free allocated space from ReturnFullMatrixforSymmetric()
4704 delete(AtomStack);
4705 Free((void **)&ColorList, "molecule::ScanForPeriodicCorrection: *ColorList");
4706 Free((void **)&matrix, "molecule::ScanForPeriodicCorrection: *matrix");
4707 *out << Verbose(2) << "End of ScanForPeriodicCorrection." << endl;
4708};
4709
4710/** Blows the 6-dimensional \a cell_size array up to a full NDIM by NDIM matrix.
4711 * \param *symm 6-dim array of unique symmetric matrix components
4712 * \return allocated NDIM*NDIM array with the symmetric matrix
4713 */
4714double * molecule::ReturnFullMatrixforSymmetric(double *symm)
4715{
4716 double *matrix = (double *) Malloc(sizeof(double)*NDIM*NDIM, "molecule::ReturnFullMatrixforSymmetric: *matrix");
4717 matrix[0] = symm[0];
4718 matrix[1] = symm[1];
4719 matrix[2] = symm[3];
4720 matrix[3] = symm[1];
4721 matrix[4] = symm[2];
4722 matrix[5] = symm[4];
4723 matrix[6] = symm[3];
4724 matrix[7] = symm[4];
4725 matrix[8] = symm[5];
4726 return matrix;
4727};
4728
4729bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
4730{
4731 //cout << "my check is used." << endl;
4732 if (SubgraphA.size() < SubgraphB.size()) {
4733 return true;
4734 } else {
4735 if (SubgraphA.size() > SubgraphB.size()) {
4736 return false;
4737 } else {
4738 KeySet::iterator IteratorA = SubgraphA.begin();
4739 KeySet::iterator IteratorB = SubgraphB.begin();
4740 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
4741 if ((*IteratorA) < (*IteratorB))
4742 return true;
4743 else if ((*IteratorA) > (*IteratorB)) {
4744 return false;
4745 } // else, go on to next index
4746 IteratorA++;
4747 IteratorB++;
4748 } // end of while loop
4749 }// end of check in case of equal sizes
4750 }
4751 return false; // if we reach this point, they are equal
4752};
4753
4754//bool operator < (KeySet SubgraphA, KeySet SubgraphB)
4755//{
4756// return KeyCompare(SubgraphA, SubgraphB);
4757//};
4758
4759/** Checking whether KeySet is not already present in Graph, if so just adds factor.
4760 * \param *out output stream for debugging
4761 * \param &set KeySet to insert
4762 * \param &graph Graph to insert into
4763 * \param *counter pointer to unique fragment count
4764 * \param factor energy factor for the fragment
4765 */
4766inline void InsertFragmentIntoGraph(ofstream *out, struct UniqueFragments *Fragment)
4767{
4768 GraphTestPair testGraphInsert;
4769
4770 testGraphInsert = Fragment->Leaflet->insert(GraphPair (*Fragment->FragmentSet,pair<int,double>(Fragment->FragmentCounter,Fragment->TEFactor))); // store fragment number and current factor
4771 if (testGraphInsert.second) {
4772 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " successfully inserted." << endl;
4773 Fragment->FragmentCounter++;
4774 } else {
4775 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
4776 ((*(testGraphInsert.first)).second).second += Fragment->TEFactor; // increase the "created" counter
4777 *out << Verbose(2) << "New factor is " << ((*(testGraphInsert.first)).second).second << "." << endl;
4778 }
4779};
4780//void inline InsertIntoGraph(ofstream *out, KeyStack &stack, Graph &graph, int *counter, double factor)
4781//{
4782// // copy stack contents to set and call overloaded function again
4783// KeySet set;
4784// for(KeyStack::iterator runner = stack.begin(); runner != stack.begin(); runner++)
4785// set.insert((*runner));
4786// InsertIntoGraph(out, set, graph, counter, factor);
4787//};
4788
4789/** Inserts each KeySet in \a graph2 into \a graph1.
4790 * \param *out output stream for debugging
4791 * \param graph1 first (dest) graph
4792 * \param graph2 second (source) graph
4793 * \param *counter keyset counter that gets increased
4794 */
4795inline void InsertGraphIntoGraph(ofstream *out, Graph &graph1, Graph &graph2, int *counter)
4796{
4797 GraphTestPair testGraphInsert;
4798
4799 for(Graph::iterator runner = graph2.begin(); runner != graph2.end(); runner++) {
4800 testGraphInsert = graph1.insert(GraphPair ((*runner).first,pair<int,double>((*counter)++,((*runner).second).second))); // store fragment number and current factor
4801 if (testGraphInsert.second) {
4802 *out << Verbose(2) << "KeySet " << (*counter)-1 << " successfully inserted." << endl;
4803 } else {
4804 *out << Verbose(2) << "KeySet " << (*counter)-1 << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
4805 ((*(testGraphInsert.first)).second).second += (*runner).second.second;
4806 *out << Verbose(2) << "New factor is " << (*(testGraphInsert.first)).second.second << "." << endl;
4807 }
4808 }
4809};
4810
4811
4812/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
4813 * -# constructs a complete keyset of the molecule
4814 * -# In a loop over all possible roots from the given rootstack
4815 * -# increases order of root site
4816 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
4817 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
4818as the restricted one and each site in the set as the root)
4819 * -# these are merged into a fragment list of keysets
4820 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
4821 * Important only is that we create all fragments, it is not important if we create them more than once
4822 * as these copies are filtered out via use of the hash table (KeySet).
4823 * \param *out output stream for debugging
4824 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
4825 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
4826 * \param *MinimumRingSize minimum ring size for each atom (molecule::Atomcount)
4827 * \return pointer to Graph list
4828 */
4829void molecule::FragmentBOSSANOVA(ofstream *out, Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize)
4830{
4831 Graph ***FragmentLowerOrdersList = NULL;
4832 int NumLevels, NumMolecules, TotalNumMolecules = 0, *NumMoleculesOfOrder = NULL;
4833 int counter = 0, Order;
4834 int UpgradeCount = RootStack.size();
4835 KeyStack FragmentRootStack;
4836 int RootKeyNr, RootNr;
4837 struct UniqueFragments FragmentSearch;
4838
4839 *out << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl;
4840
4841 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
4842 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
4843 NumMoleculesOfOrder = (int *) Malloc(sizeof(int)*UpgradeCount, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
4844 FragmentLowerOrdersList = (Graph ***) Malloc(sizeof(Graph **)*UpgradeCount, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
4845
4846 // initialise the fragments structure
4847 FragmentSearch.ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *ShortestPathList");
4848 FragmentSearch.FragmentCounter = 0;
4849 FragmentSearch.FragmentSet = new KeySet;
4850 FragmentSearch.Root = FindAtom(RootKeyNr);
4851 for (int i=AtomCount;i--;) {
4852 FragmentSearch.ShortestPathList[i] = -1;
4853 }
4854
4855 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
4856 atom *Walker = start;
4857 KeySet CompleteMolecule;
4858 while (Walker->next != end) {
4859 Walker = Walker->next;
4860 CompleteMolecule.insert(Walker->GetTrueFather()->nr);
4861 }
4862
4863 // 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
4864 // 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),
4865 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
4866 // 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)
4867 RootNr = 0; // counts through the roots in RootStack
4868 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
4869 RootKeyNr = RootStack.front();
4870 RootStack.pop_front();
4871 Walker = FindAtom(RootKeyNr);
4872 // check cyclic lengths
4873 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) {
4874 // *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;
4875 //} else
4876 {
4877 // increase adaptive order by one
4878 Walker->GetTrueFather()->AdaptiveOrder++;
4879 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
4880
4881 // initialise Order-dependent entries of UniqueFragments structure
4882 FragmentSearch.BondsPerSPList = (bond **) Malloc(sizeof(bond *)*Order*2, "molecule::PowerSetGenerator: ***BondsPerSPList");
4883 FragmentSearch.BondsPerSPCount = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *BondsPerSPCount");
4884 for (int i=Order;i--;) {
4885 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node
4886 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node
4887 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two
4888 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i];
4889 FragmentSearch.BondsPerSPCount[i] = 0;
4890 }
4891
4892 // allocate memory for all lower level orders in this 1D-array of ptrs
4893 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
4894 FragmentLowerOrdersList[RootNr] = (Graph **) Malloc(sizeof(Graph *)*NumLevels, "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
4895 for (int i=0;i<NumLevels;i++)
4896 FragmentLowerOrdersList[RootNr][i] = NULL;
4897
4898 // create top order where nothing is reduced
4899 *out << Verbose(0) << "==============================================================================================================" << endl;
4900 *out << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl; // , NumLevels is " << NumLevels << "
4901
4902 // Create list of Graphs of current Bond Order (i.e. F_{ij})
4903 FragmentLowerOrdersList[RootNr][0] = new Graph;
4904 FragmentSearch.TEFactor = 1.;
4905 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
4906 FragmentSearch.Root = Walker;
4907 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(out, Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
4908 *out << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
4909 if (NumMoleculesOfOrder[RootNr] != 0) {
4910 NumMolecules = 0;
4911
4912 // we don't have to dive into suborders! These keysets are all already created on lower orders!
4913 // this was all ancient stuff, when we still depended on the TEFactors (and for those the suborders were needed)
4914
4915// if ((NumLevels >> 1) > 0) {
4916// // create lower order fragments
4917// *out << Verbose(0) << "Creating list of unique fragments of lower Bond Order terms to be subtracted." << endl;
4918// Order = Walker->AdaptiveOrder;
4919// 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)
4920// // step down to next order at (virtual) boundary of powers of 2 in array
4921// while (source >= (1 << (Walker->AdaptiveOrder-Order))) // (int)pow(2,Walker->AdaptiveOrder-Order))
4922// Order--;
4923// *out << Verbose(0) << "Current Order is: " << Order << "." << endl;
4924// for (int SubOrder=Order-1;SubOrder>0;SubOrder--) {
4925// int dest = source + (1 << (Walker->AdaptiveOrder-(SubOrder+1)));
4926// *out << Verbose(0) << "--------------------------------------------------------------------------------------------------------------" << endl;
4927// *out << Verbose(0) << "Current SubOrder is: " << SubOrder << " with source " << source << " to destination " << dest << "." << endl;
4928//
4929// // every molecule is split into a list of again (Order - 1) molecules, while counting all molecules
4930// //*out << Verbose(1) << "Splitting the " << (*FragmentLowerOrdersList[RootNr][source]).size() << " molecules of the " << source << "th cell in the array." << endl;
4931// //NumMolecules = 0;
4932// FragmentLowerOrdersList[RootNr][dest] = new Graph;
4933// for(Graph::iterator runner = (*FragmentLowerOrdersList[RootNr][source]).begin();runner != (*FragmentLowerOrdersList[RootNr][source]).end(); runner++) {
4934// for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
4935// Graph TempFragmentList;
4936// FragmentSearch.TEFactor = -(*runner).second.second;
4937// FragmentSearch.Leaflet = &TempFragmentList; // set to insertion graph
4938// FragmentSearch.Root = FindAtom(*sprinter);
4939// NumMoleculesOfOrder[RootNr] += PowerSetGenerator(out, SubOrder, FragmentSearch, (*runner).first);
4940// // insert new keysets FragmentList into FragmentLowerOrdersList[Walker->AdaptiveOrder-1][dest]
4941// *out << Verbose(1) << "Merging resulting key sets with those present in destination " << dest << "." << endl;
4942// InsertGraphIntoGraph(out, *FragmentLowerOrdersList[RootNr][dest], TempFragmentList, &NumMolecules);
4943// }
4944// }
4945// *out << Verbose(1) << "Number of resulting molecules for SubOrder " << SubOrder << " is: " << NumMolecules << "." << endl;
4946// }
4947// }
4948// }
4949 } else {
4950 Walker->GetTrueFather()->MaxOrder = true;
4951// *out << Verbose(1) << "Hence, we don't dive into SubOrders ... " << endl;
4952 }
4953 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
4954 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
4955 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
4956// *out << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
4957 RootStack.push_back(RootKeyNr); // put back on stack
4958 RootNr++;
4959
4960 // free Order-dependent entries of UniqueFragments structure for next loop cycle
4961 Free((void **)&FragmentSearch.BondsPerSPCount, "molecule::PowerSetGenerator: *BondsPerSPCount");
4962 for (int i=Order;i--;) {
4963 delete(FragmentSearch.BondsPerSPList[2*i]);
4964 delete(FragmentSearch.BondsPerSPList[2*i+1]);
4965 }
4966 Free((void **)&FragmentSearch.BondsPerSPList, "molecule::PowerSetGenerator: ***BondsPerSPList");
4967 }
4968 }
4969 *out << Verbose(0) << "==============================================================================================================" << endl;
4970 *out << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl;
4971 *out << Verbose(0) << "==============================================================================================================" << endl;
4972
4973 // cleanup FragmentSearch structure
4974 Free((void **)&FragmentSearch.ShortestPathList, "molecule::PowerSetGenerator: *ShortestPathList");
4975 delete(FragmentSearch.FragmentSet);
4976
4977 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
4978 // 5433222211111111
4979 // 43221111
4980 // 3211
4981 // 21
4982 // 1
4983
4984 // Subsequently, we combine all into a single list (FragmentList)
4985
4986 *out << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl;
4987 if (FragmentList == NULL) {
4988 FragmentList = new Graph;
4989 counter = 0;
4990 } else {
4991 counter = FragmentList->size();
4992 }
4993 RootNr = 0;
4994 while (!RootStack.empty()) {
4995 RootKeyNr = RootStack.front();
4996 RootStack.pop_front();
4997 Walker = FindAtom(RootKeyNr);
4998 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
4999 for(int i=0;i<NumLevels;i++) {
5000 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
5001 InsertGraphIntoGraph(out, *FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
5002 delete(FragmentLowerOrdersList[RootNr][i]);
5003 }
5004 }
5005 Free((void **)&FragmentLowerOrdersList[RootNr], "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
5006 RootNr++;
5007 }
5008 Free((void **)&FragmentLowerOrdersList, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
5009 Free((void **)&NumMoleculesOfOrder, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
5010
5011 *out << Verbose(0) << "End of FragmentBOSSANOVA." << endl;
5012};
5013
5014/** Comparison function for GSL heapsort on distances in two molecules.
5015 * \param *a
5016 * \param *b
5017 * \return <0, \a *a less than \a *b, ==0 if equal, >0 \a *a greater than \a *b
5018 */
5019inline int CompareDoubles (const void * a, const void * b)
5020{
5021 if (*(double *)a > *(double *)b)
5022 return -1;
5023 else if (*(double *)a < *(double *)b)
5024 return 1;
5025 else
5026 return 0;
5027};
5028
5029/** Determines whether two molecules actually contain the same atoms and coordination.
5030 * \param *out output stream for debugging
5031 * \param *OtherMolecule the molecule to compare this one to
5032 * \param threshold upper limit of difference when comparing the coordination.
5033 * \return NULL - not equal, otherwise an allocated (molecule::AtomCount) permutation map of the atom numbers (which corresponds to which)
5034 */
5035int * molecule::IsEqualToWithinThreshold(ofstream *out, molecule *OtherMolecule, double threshold)
5036{
5037 int flag;
5038 double *Distances = NULL, *OtherDistances = NULL;
5039 Vector CenterOfGravity, OtherCenterOfGravity;
5040 size_t *PermMap = NULL, *OtherPermMap = NULL;
5041 int *PermutationMap = NULL;
5042 atom *Walker = NULL;
5043 bool result = true; // status of comparison
5044
5045 *out << Verbose(3) << "Begin of IsEqualToWithinThreshold." << endl;
5046 /// first count both their atoms and elements and update lists thereby ...
5047 //*out << Verbose(0) << "Counting atoms, updating list" << endl;
5048 CountAtoms(out);
5049 OtherMolecule->CountAtoms(out);
5050 CountElements();
5051 OtherMolecule->CountElements();
5052
5053 /// ... and compare:
5054 /// -# AtomCount
5055 if (result) {
5056 if (AtomCount != OtherMolecule->AtomCount) {
5057 *out << Verbose(4) << "AtomCounts don't match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
5058 result = false;
5059 } else *out << Verbose(4) << "AtomCounts match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
5060 }
5061 /// -# ElementCount
5062 if (result) {
5063 if (ElementCount != OtherMolecule->ElementCount) {
5064 *out << Verbose(4) << "ElementCount don't match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
5065 result = false;
5066 } else *out << Verbose(4) << "ElementCount match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
5067 }
5068 /// -# ElementsInMolecule
5069 if (result) {
5070 for (flag=MAX_ELEMENTS;flag--;) {
5071 //*out << Verbose(5) << "Element " << flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl;
5072 if (ElementsInMolecule[flag] != OtherMolecule->ElementsInMolecule[flag])
5073 break;
5074 }
5075 if (flag < MAX_ELEMENTS) {
5076 *out << Verbose(4) << "ElementsInMolecule don't match." << endl;
5077 result = false;
5078 } else *out << Verbose(4) << "ElementsInMolecule match." << endl;
5079 }
5080 /// then determine and compare center of gravity for each molecule ...
5081 if (result) {
5082 *out << Verbose(5) << "Calculating Centers of Gravity" << endl;
5083 DetermineCenter(CenterOfGravity);
5084 OtherMolecule->DetermineCenter(OtherCenterOfGravity);
5085 *out << Verbose(5) << "Center of Gravity: ";
5086 CenterOfGravity.Output(out);
5087 *out << endl << Verbose(5) << "Other Center of Gravity: ";
5088 OtherCenterOfGravity.Output(out);
5089 *out << endl;
5090 if (CenterOfGravity.Distance(&OtherCenterOfGravity) > threshold) {
5091 *out << Verbose(4) << "Centers of gravity don't match." << endl;
5092 result = false;
5093 }
5094 }
5095
5096 /// ... then make a list with the euclidian distance to this center for each atom of both molecules
5097 if (result) {
5098 *out << Verbose(5) << "Calculating distances" << endl;
5099 Distances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: Distances");
5100 OtherDistances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: OtherDistances");
5101 Walker = start;
5102 while (Walker->next != end) {
5103 Walker = Walker->next;
5104 Distances[Walker->nr] = CenterOfGravity.Distance(&Walker->x);
5105 }
5106 Walker = OtherMolecule->start;
5107 while (Walker->next != OtherMolecule->end) {
5108 Walker = Walker->next;
5109 OtherDistances[Walker->nr] = OtherCenterOfGravity.Distance(&Walker->x);
5110 }
5111
5112 /// ... sort each list (using heapsort (o(N log N)) from GSL)
5113 *out << Verbose(5) << "Sorting distances" << endl;
5114 PermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermMap");
5115 OtherPermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
5116 gsl_heapsort_index (PermMap, Distances, AtomCount, sizeof(double), CompareDoubles);
5117 gsl_heapsort_index (OtherPermMap, OtherDistances, AtomCount, sizeof(double), CompareDoubles);
5118 PermutationMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermutationMap");
5119 *out << Verbose(5) << "Combining Permutation Maps" << endl;
5120 for(int i=AtomCount;i--;)
5121 PermutationMap[PermMap[i]] = (int) OtherPermMap[i];
5122
5123 /// ... and compare them step by step, whether the difference is individiually(!) below \a threshold for all
5124 *out << Verbose(4) << "Comparing distances" << endl;
5125 flag = 0;
5126 for (int i=0;i<AtomCount;i++) {
5127 *out << Verbose(5) << "Distances: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " << threshold << endl;
5128 if (fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) > threshold)
5129 flag = 1;
5130 }
5131 Free((void **)&PermMap, "molecule::IsEqualToWithinThreshold: *PermMap");
5132 Free((void **)&OtherPermMap, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
5133
5134 /// free memory
5135 Free((void **)&Distances, "molecule::IsEqualToWithinThreshold: Distances");
5136 Free((void **)&OtherDistances, "molecule::IsEqualToWithinThreshold: OtherDistances");
5137 if (flag) { // if not equal
5138 Free((void **)&PermutationMap, "molecule::IsEqualToWithinThreshold: *PermutationMap");
5139 result = false;
5140 }
5141 }
5142 /// return pointer to map if all distances were below \a threshold
5143 *out << Verbose(3) << "End of IsEqualToWithinThreshold." << endl;
5144 if (result) {
5145 *out << Verbose(3) << "Result: Equal." << endl;
5146 return PermutationMap;
5147 } else {
5148 *out << Verbose(3) << "Result: Not equal." << endl;
5149 return NULL;
5150 }
5151};
5152
5153/** Returns an index map for two father-son-molecules.
5154 * The map tells which atom in this molecule corresponds to which one in the other molecul with their fathers.
5155 * \param *out output stream for debugging
5156 * \param *OtherMolecule corresponding molecule with fathers
5157 * \return allocated map of size molecule::AtomCount with map
5158 * \todo make this with a good sort O(n), not O(n^2)
5159 */
5160int * molecule::GetFatherSonAtomicMap(ofstream *out, molecule *OtherMolecule)
5161{
5162 atom *Walker = NULL, *OtherWalker = NULL;
5163 *out << Verbose(3) << "Begin of GetFatherAtomicMap." << endl;
5164 int *AtomicMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::GetAtomicMap: *AtomicMap"); //Calloc
5165 for (int i=AtomCount;i--;)
5166 AtomicMap[i] = -1;
5167 if (OtherMolecule == this) { // same molecule
5168 for (int i=AtomCount;i--;) // no need as -1 means already that there is trivial correspondence
5169 AtomicMap[i] = i;
5170 *out << Verbose(4) << "Map is trivial." << endl;
5171 } else {
5172 *out << Verbose(4) << "Map is ";
5173 Walker = start;
5174 while (Walker->next != end) {
5175 Walker = Walker->next;
5176 if (Walker->father == NULL) {
5177 AtomicMap[Walker->nr] = -2;
5178 } else {
5179 OtherWalker = OtherMolecule->start;
5180 while (OtherWalker->next != OtherMolecule->end) {
5181 OtherWalker = OtherWalker->next;
5182 //for (int i=0;i<AtomCount;i++) { // search atom
5183 //for (int j=0;j<OtherMolecule->AtomCount;j++) {
5184 //*out << Verbose(4) << "Comparing father " << Walker->father << " with the other one " << OtherWalker->father << "." << endl;
5185 if (Walker->father == OtherWalker)
5186 AtomicMap[Walker->nr] = OtherWalker->nr;
5187 }
5188 }
5189 *out << AtomicMap[Walker->nr] << "\t";
5190 }
5191 *out << endl;
5192 }
5193 *out << Verbose(3) << "End of GetFatherAtomicMap." << endl;
5194 return AtomicMap;
5195};
5196
5197/** Stores the temperature evaluated from velocities in molecule::Trajectories.
5198 * We simply use the formula equivaleting temperature and kinetic energy:
5199 * \f$k_B T = \sum_i m_i v_i^2\f$
5200 * \param *out output stream for debugging
5201 * \param startstep first MD step in molecule::Trajectories
5202 * \param endstep last plus one MD step in molecule::Trajectories
5203 * \param *output output stream of temperature file
5204 * \return file written (true), failure on writing file (false)
5205 */
5206bool molecule::OutputTemperatureFromTrajectories(ofstream *out, int startstep, int endstep, ofstream *output)
5207{
5208 double temperature;
5209 atom *Walker = NULL;
5210 // test stream
5211 if (output == NULL)
5212 return false;
5213 else
5214 *output << "# Step Temperature [K] Temperature [a.u.]" << endl;
5215 for (int step=startstep;step < endstep; step++) { // loop over all time steps
5216 temperature = 0.;
5217 Walker = start;
5218 while (Walker->next != end) {
5219 Walker = Walker->next;
5220 for (int i=NDIM;i--;)
5221 temperature += Walker->type->mass * Trajectories[Walker].U.at(step).x[i]* Trajectories[Walker].U.at(step).x[i];
5222 }
5223 *output << step << "\t" << temperature*AtomicEnergyToKelvin << "\t" << temperature << endl;
5224 }
5225 return true;
5226};
Note: See TracBrowser for help on using the repository browser.