source: src/moleculelist.cpp@ 390248

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 390248 was 390248, checked in by Frederik Heber <heber@…>, 16 years ago

BIG change: Hcorrection included and bugfix of analyzer (wrt forces)

  • Hcorrection is supplied via molecuilder which gives correction values if hydrogen atoms are to close and thus already feel each other's influence. This correction energy matrix is also parsed ans subtracted from the approximated energy matrix generated from the fragments. This impacts both on joiner, analyzer and molecuilder
  • Forces were not working which had multiple causes:
    • first, we stepped back down to absolute errors which rather gives a feel about convergence (1e-6 is simply small and neglegible)
    • there may have been bugs where (either in Force or in ForceFragments) adding up took place, this is cleaned up
    • more routines have been abstracted from analyzer into datacreator functions
      • the order of ions had changed, re-run with current molecuilder, calculation and subsequent joining/analyzing brought correct results finally
  • plots were bad still due to wrong axes (two more functions finding max/min values), use of wrong columns in plot file
  • Property mode set to 100644
File size: 30.5 KB
Line 
1/** \file MoleculeListClass.cpp
2 *
3 * Function implementations for the class MoleculeListClass.
4 *
5 */
6
7#include "molecules.hpp"
8
9/*********************************** Functions for class MoleculeListClass *************************/
10
11/** Constructor for MoleculeListClass.
12 */
13MoleculeListClass::MoleculeListClass()
14{
15};
16
17/** constructor for MoleculeListClass.
18 * \param NumMolecules number of molecules to allocate for
19 * \param NumAtoms number of atoms to allocate for
20 */
21MoleculeListClass::MoleculeListClass(int NumMolecules, int NumAtoms)
22{
23 ListOfMolecules = (molecule **) Malloc(sizeof(molecule *)*NumMolecules, "MoleculeListClass:MoleculeListClass: **ListOfMolecules");
24 for (int i=NumMolecules;i--;)
25 ListOfMolecules[i] = NULL;
26 NumberOfMolecules = NumMolecules;
27 NumberOfTopAtoms = NumAtoms;
28};
29
30
31/** Destructor for MoleculeListClass.
32 */
33MoleculeListClass::~MoleculeListClass()
34{
35 cout << Verbose(3) << this << ": Freeing ListOfMolcules." << endl;
36 for (int i=NumberOfMolecules;i--;) {
37 if (ListOfMolecules[i] != NULL) { // if NULL don't free
38 cout << Verbose(4) << "ListOfMolecules: Freeing " << ListOfMolecules[i] << "." << endl;
39 delete(ListOfMolecules[i]);
40 ListOfMolecules[i] = NULL;
41 }
42 }
43 cout << Verbose(4) << "Freeing ListOfMolecules." << endl;
44 Free((void **)&ListOfMolecules, "MoleculeListClass:MoleculeListClass: **ListOfMolecules");
45};
46
47/** Compare whether two molecules are equal.
48 * \param *a molecule one
49 * \param *n molecule two
50 * \return lexical value (-1, 0, +1)
51 */
52int MolCompare(const void *a, const void *b)
53{
54 int *aList = NULL, *bList = NULL;
55 int Count, Counter, aCounter, bCounter;
56 int flag;
57 atom *aWalker = NULL;
58 atom *bWalker = NULL;
59
60 // sort each atom list and put the numbers into a list, then go through
61 //cout << "Comparing fragment no. " << *(molecule **)a << " to " << *(molecule **)b << "." << endl;
62 if ( (**(molecule **)a).AtomCount < (**(molecule **)b).AtomCount ) {
63 return -1;
64 } else { if ((**(molecule **)a).AtomCount > (**(molecule **)b).AtomCount)
65 return +1;
66 else {
67 Count = (**(molecule **)a).AtomCount;
68 aList = new int[Count];
69 bList = new int[Count];
70
71 // fill the lists
72 aWalker = (**(molecule **)a).start;
73 bWalker = (**(molecule **)b).start;
74 Counter = 0;
75 aCounter = 0;
76 bCounter = 0;
77 while ((aWalker->next != (**(molecule **)a).end) && (bWalker->next != (**(molecule **)b).end)) {
78 aWalker = aWalker->next;
79 bWalker = bWalker->next;
80 if (aWalker->GetTrueFather() == NULL)
81 aList[Counter] = Count + (aCounter++);
82 else
83 aList[Counter] = aWalker->GetTrueFather()->nr;
84 if (bWalker->GetTrueFather() == NULL)
85 bList[Counter] = Count + (bCounter++);
86 else
87 bList[Counter] = bWalker->GetTrueFather()->nr;
88 Counter++;
89 }
90 // check if AtomCount was for real
91 flag = 0;
92 if ((aWalker->next == (**(molecule **)a).end) && (bWalker->next != (**(molecule **)b).end)) {
93 flag = -1;
94 } else {
95 if ((aWalker->next != (**(molecule **)a).end) && (bWalker->next == (**(molecule **)b).end))
96 flag = 1;
97 }
98 if (flag == 0) {
99 // sort the lists
100 gsl_heapsort(aList,Count, sizeof(int), CompareDoubles);
101 gsl_heapsort(bList,Count, sizeof(int), CompareDoubles);
102 // compare the lists
103
104 flag = 0;
105 for(int i=0;i<Count;i++) {
106 if (aList[i] < bList[i]) {
107 flag = -1;
108 } else {
109 if (aList[i] > bList[i])
110 flag = 1;
111 }
112 if (flag != 0)
113 break;
114 }
115 }
116 delete[](aList);
117 delete[](bList);
118 return flag;
119 }
120 }
121 return -1;
122};
123
124/** Simple output of the pointers in ListOfMolecules.
125 * \param *out output stream
126 */
127void MoleculeListClass::Output(ofstream *out)
128{
129 *out<< Verbose(1) << "MoleculeList: ";
130 for (int i=0;i<NumberOfMolecules;i++)
131 *out << ListOfMolecules[i] << "\t";
132 *out << endl;
133};
134
135/** Calculates necessary hydrogen correction due to unwanted interaction between saturated ones.
136 * If for a pair of two hydrogen atoms a and b, at least is a saturated one, and a and b are not
137 * bonded to the same atom, then we add for this pair a correction term constructed from a Morse
138 * potential function fit to QM calculations with respecting to the interatomic hydrogen distance.
139 * \param *out output stream for debugging
140 * \param *path path to file
141 */
142bool MoleculeListClass::AddHydrogenCorrection(ofstream *out, char *path)
143{
144 atom *Walker = NULL;
145 atom *Runner = NULL;
146 double ***FitConstant = NULL, **correction = NULL;
147 int a,b;
148 ofstream output;
149 ifstream input;
150 string line;
151 stringstream zeile;
152 double distance;
153 char ParsedLine[1023];
154 double tmp;
155 char *FragmentNumber = NULL;
156
157 cout << Verbose(1) << "Saving hydrogen saturation correction ... ";
158 // 0. parse in fit constant files that should have the same dimension as the final energy files
159 // 0a. find dimension of matrices with constants
160 line = path;
161 line.append("/");
162 line += FRAGMENTPREFIX;
163 line += "1";
164 line += FITCONSTANTSUFFIX;
165 input.open(line.c_str());
166 if (input == NULL) {
167 cerr << endl << "Unable to open " << line << ", is the directory correct?" << endl;
168 return false;
169 }
170 a=0;
171 b=-1; // we overcount by one
172 while (!input.eof()) {
173 input.getline(ParsedLine, 1023);
174 zeile.str(ParsedLine);
175 int i=0;
176 while (!zeile.eof()) {
177 zeile >> distance;
178 i++;
179 }
180 if (i > a)
181 a = i;
182 b++;
183 }
184 cout << "I recognized " << a << " columns and " << b << " rows, ";
185 input.close();
186
187 // 0b. allocate memory for constants
188 FitConstant = (double ***) Malloc(sizeof(double **)*3, "MoleculeListClass::AddHydrogenCorrection: ***FitConstant");
189 for (int k=0;k<3;k++) {
190 FitConstant[k] = (double **) Malloc(sizeof(double *)*a, "MoleculeListClass::AddHydrogenCorrection: **FitConstant[]");
191 for (int i=a;i--;) {
192 FitConstant[k][i] = (double *) Malloc(sizeof(double)*b, "MoleculeListClass::AddHydrogenCorrection: *FitConstant[][]");
193 }
194 }
195 // 0c. parse in constants
196 for (int i=0;i<3;i++) {
197 line = path;
198 line.append("/");
199 line += FRAGMENTPREFIX;
200 sprintf(ParsedLine, "%d", i+1);
201 line += ParsedLine;
202 line += FITCONSTANTSUFFIX;
203 input.open(line.c_str());
204 if (input == NULL) {
205 cerr << endl << "Unable to open " << line << ", is the directory correct?" << endl;
206 return false;
207 }
208 int k = 0,l;
209 while ((!input.eof()) && (k < b)) {
210 input.getline(ParsedLine, 1023);
211 //cout << "Current Line: " << ParsedLine << endl;
212 zeile.str(ParsedLine);
213 zeile.clear();
214 l = 0;
215 while ((!zeile.eof()) && (l < a)) {
216 zeile >> FitConstant[i][l][k];
217 //cout << FitConstant[i][l][k] << "\t";
218 l++;
219 }
220 //cout << endl;
221 k++;
222 }
223 input.close();
224 }
225 for(int k=0;k<3;k++) {
226 cout << "Constants " << k << ":" << endl;
227 for (int j=0;j<b;j++) {
228 for (int i=0;i<a;i++) {
229 cout << FitConstant[k][i][j] << "\t";
230 }
231 cout << endl;
232 }
233 cout << endl;
234 }
235
236 // 0d. allocate final correction matrix
237 correction = (double **) Malloc(sizeof(double *)*a, "MoleculeListClass::AddHydrogenCorrection: **correction");
238 for (int i=a;i--;)
239 correction[i] = (double *) Malloc(sizeof(double)*b, "MoleculeListClass::AddHydrogenCorrection: *correction[]");
240
241 // 1a. go through every molecule in the list
242 for(int i=NumberOfMolecules;i--;) {
243 // 1b. zero final correction matrix
244 for (int k=a;k--;)
245 for (int j=b;j--;)
246 correction[k][j] = 0.;
247 // 2. take every hydrogen that is a saturated one
248 Walker = ListOfMolecules[i]->start;
249 while (Walker->next != ListOfMolecules[i]->end) {
250 Walker = Walker->next;
251 //cout << Verbose(1) << "Walker: " << *Walker << " with first bond " << *ListOfMolecules[i]->ListOfBondsPerAtom[Walker->nr][0] << "." << endl;
252 if ((Walker->type->Z == 1) && ((Walker->father == NULL) || (Walker->father->type->Z != 1))) { // if it's a hydrogen
253 Runner = ListOfMolecules[i]->start;
254 while (Runner->next != ListOfMolecules[i]->end) {
255 Runner = Runner->next;
256 //cout << Verbose(2) << "Runner: " << *Runner << " with first bond " << *ListOfMolecules[i]->ListOfBondsPerAtom[Runner->nr][0] << "." << endl;
257 // 3. take every other hydrogen that is the not the first and not bound to same bonding partner
258 if ((Runner->type->Z == 1) && (Runner->nr > Walker->nr) && (ListOfMolecules[i]->ListOfBondsPerAtom[Runner->nr][0]->GetOtherAtom(Runner) != ListOfMolecules[i]->ListOfBondsPerAtom[Walker->nr][0]->GetOtherAtom(Walker))) { // (hydrogens have only one bonding partner!)
259 // 4. evaluate the morse potential for each matrix component and add up
260 distance = sqrt(Runner->x.Distance(&Walker->x));
261 //cout << "Fragment " << i << ": " << *Runner << "<= " << distance << "=>" << *Walker << ":" << endl;
262 for(int k=0;k<a;k++) {
263 for (int j=0;j<b;j++) {
264 switch(k) {
265 case 1:
266 case 7:
267 case 11:
268 tmp = pow(FitConstant[0][k][j] * ( 1. - exp(-FitConstant[1][k][j] * (distance - FitConstant[2][k][j]) ) ),2);
269 break;
270 default:
271 tmp = FitConstant[0][k][j] * pow( distance, FitConstant[1][k][j]) + FitConstant[2][k][j];
272 };
273 correction[k][j] -= tmp; // ground state is actually lower (disturbed by additional interaction)
274 //cout << tmp << "\t";
275 }
276 //cout << endl;
277 }
278 //cout << endl;
279 }
280 }
281 }
282 }
283 // 5. write final matrix to file
284 line = path;
285 line.append("/");
286 line += FRAGMENTPREFIX;
287 FragmentNumber = FixedDigitNumber(NumberOfMolecules, i);
288 line += FragmentNumber;
289 delete(FragmentNumber);
290 line += HCORRECTIONSUFFIX;
291 output.open(line.c_str());
292 output << "Time\t\tTotal\t\tKinetic\t\tNonLocal\tCorrelation\tExchange\tPseudo\t\tHartree\t\t-Gauss\t\tEwald\t\tIonKin\t\tETotal" << endl;
293 for (int j=0;j<b;j++) {
294 for(int i=0;i<a;i++)
295 output << correction[i][j] << "\t";
296 output << endl;
297 }
298 output.close();
299 }
300 line = path;
301 line.append("/");
302 line += HCORRECTIONSUFFIX;
303 output.open(line.c_str());
304 output << "Time\t\tTotal\t\tKinetic\t\tNonLocal\tCorrelation\tExchange\tPseudo\t\tHartree\t\t-Gauss\t\tEwald\t\tIonKin\t\tETotal" << endl;
305 for (int j=0;j<b;j++) {
306 for(int i=0;i<a;i++)
307 output << 0 << "\t";
308 output << endl;
309 }
310 output.close();
311 // 6. free memory of parsed matrices
312 FitConstant = (double ***) Malloc(sizeof(double **)*a, "MoleculeListClass::AddHydrogenCorrection: ***FitConstant");
313 for (int k=0;k<3;k++) {
314 FitConstant[k] = (double **) Malloc(sizeof(double *)*a, "MoleculeListClass::AddHydrogenCorrection: **FitConstant[]");
315 for (int i=a;i--;) {
316 FitConstant[k][i] = (double *) Malloc(sizeof(double)*b, "MoleculeListClass::AddHydrogenCorrection: *FitConstant[][]");
317 }
318 }
319 cout << "done." << endl;
320 return true;
321};
322
323/** Store force indices, i.e. the connection between the nuclear index in the total molecule config and the respective atom in fragment config.
324 * \param *out output stream for debugging
325 * \param *path path to file
326 * \param *SortIndex Index to map from the BFS labeling to the sequence how of Ion_Type in the config
327 * \return true - file written successfully, false - writing failed
328 */
329bool MoleculeListClass::StoreForcesFile(ofstream *out, char *path, int *SortIndex)
330{
331 bool status = true;
332 ofstream ForcesFile;
333 stringstream line;
334 atom *Walker = NULL;
335 element *runner = NULL;
336
337 // open file for the force factors
338 *out << Verbose(1) << "Saving force factors ... ";
339 line << path << "/" << FRAGMENTPREFIX << FORCESFILE;
340 ForcesFile.open(line.str().c_str(), ios::out);
341 if (ForcesFile != NULL) {
342 //cout << Verbose(1) << "Final AtomicForcesList: ";
343 //output << prefix << "Forces" << endl;
344 for(int j=0;j<NumberOfMolecules;j++) {
345 //if (TEList[j] != 0) {
346 runner = ListOfMolecules[j]->elemente->start;
347 while (runner->next != ListOfMolecules[j]->elemente->end) { // go through every element
348 runner = runner->next;
349 if (ListOfMolecules[j]->ElementsInMolecule[runner->Z]) { // if this element got atoms
350 Walker = ListOfMolecules[j]->start;
351 while (Walker->next != ListOfMolecules[j]->end) { // go through every atom of this element
352 Walker = Walker->next;
353 if (Walker->type->Z == runner->Z) {
354 if ((Walker->GetTrueFather() != NULL) && (Walker->GetTrueFather() != Walker)) {// if there is a rea
355 //cout << "Walker is " << *Walker << " with true father " << *( Walker->GetTrueFather()) << ", it
356 ForcesFile << SortIndex[Walker->GetTrueFather()->nr] << "\t";
357 } else // otherwise a -1 to indicate an added saturation hydrogen
358 ForcesFile << "-1\t";
359 }
360 }
361 }
362 }
363 ForcesFile << endl;
364 }
365 ForcesFile.close();
366 *out << Verbose(1) << "done." << endl;
367 } else {
368 status = false;
369 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
370 }
371 ForcesFile.close();
372
373 return status;
374};
375
376/** Writes a config file for each molecule in the given \a **FragmentList.
377 * \param *out output stream for debugging
378 * \param *configuration standard configuration to attach atoms in fragment molecule to.
379 * \param *SortIndex Index to map from the BFS labeling to the sequence how of Ion_Type in the config
380 * \return true - success (each file was written), false - something went wrong.
381 */
382bool MoleculeListClass::OutputConfigForListOfFragments(ofstream *out, config *configuration, int *SortIndex)
383{
384 ofstream outputFragment;
385 char FragmentName[MAXSTRINGSIZE];
386 char PathBackup[MAXSTRINGSIZE];
387 bool result = true;
388 bool intermediateResult = true;
389 atom *Walker = NULL;
390 vector BoxDimension;
391 char *FragmentNumber = NULL;
392 char *path = NULL;
393 int FragmentCounter = 0;
394 ofstream output;
395
396 // store the fragments as config and as xyz
397 for(int i=0;i<NumberOfMolecules;i++) {
398 // save default path as it is changed for each fragment
399 path = configuration->GetDefaultPath();
400 if (path != NULL)
401 strcpy(PathBackup, path);
402 else
403 cerr << "OutputConfigForListOfFragments: NULL default path obtained from config!" << endl;
404
405 // correct periodic
406 ListOfMolecules[i]->ScanForPeriodicCorrection(out);
407
408 // output xyz file
409 FragmentNumber = FixedDigitNumber(NumberOfMolecules, FragmentCounter++);
410 sprintf(FragmentName, "%s/%s%s.conf.xyz", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
411 outputFragment.open(FragmentName, ios::out);
412 *out << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter-1 << " as XYZ ...";
413 if ((intermediateResult = ListOfMolecules[i]->OutputXYZ(&outputFragment)))
414 *out << " done." << endl;
415 else
416 *out << " failed." << endl;
417 result = result && intermediateResult;
418 outputFragment.close();
419 outputFragment.clear();
420
421 *out << Verbose(2) << "Contained atoms: ";
422 Walker = ListOfMolecules[i]->start;
423 while (Walker->next != ListOfMolecules[i]->end) {
424 Walker = Walker->next;
425 *out << Walker->Name << " ";
426 }
427 *out << endl;
428 // prepare output of config file
429 sprintf(FragmentName, "%s/%s%s.conf", PathBackup, FRAGMENTPREFIX, FragmentNumber);
430 outputFragment.open(FragmentName, ios::out);
431 //strcpy(PathBackup, configuration->configpath);
432 sprintf(FragmentName, "%s/%s%s/", PathBackup, FRAGMENTPREFIX, FragmentNumber);
433
434 // center on edge
435 ListOfMolecules[i]->CenterEdge(out, &BoxDimension);
436 ListOfMolecules[i]->SetBoxDimension(&BoxDimension); // update Box of atoms by boundary
437 int j = -1;
438 for (int k=0;k<NDIM;k++) {
439 j += k+1;
440 BoxDimension.x[k] = 2.5* (configuration->GetIsAngstroem() ? 1. : 1./AtomicLengthToAngstroem);
441 ListOfMolecules[i]->cell_size[j] += BoxDimension.x[k]*2.;
442 }
443 ListOfMolecules[i]->Translate(&BoxDimension);
444
445 // also calculate necessary orbitals
446 ListOfMolecules[i]->CountElements(); // this is a bugfix, atoms should should actually be added correctly to this fragment
447 ListOfMolecules[i]->CalculateOrbitals(*configuration);
448
449 // change path in config
450 configuration->SetDefaultPath(FragmentName);
451 *out << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter-1 << " as config ...";
452 if ((intermediateResult = configuration->Save(&outputFragment, ListOfMolecules[i]->elemente, ListOfMolecules[i])))
453 *out << " done." << endl;
454 else
455 *out << " failed." << endl;
456 // restore old config
457 configuration->SetDefaultPath(PathBackup);
458
459 result = result && intermediateResult;
460 outputFragment.close();
461 outputFragment.clear();
462 delete(FragmentNumber);
463 //Free((void **)&FragmentNumber, "MoleculeListClass::OutputConfigForListOfFragments: *FragmentNumber");
464 }
465 cout << " done." << endl;
466
467 // printing final number
468 *out << "Final number of fragments: " << FragmentCounter << "." << endl;
469
470 return result;
471};
472
473/******************************************* Class MoleculeLeafClass ************************************************/
474
475/** Constructor for MoleculeLeafClass root leaf.
476 * \param *Up Leaf on upper level
477 * \param *PreviousLeaf NULL - We are the first leaf on this level, otherwise points to previous in list
478 */
479//MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *Up = NULL, MoleculeLeafClass *Previous = NULL)
480MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *PreviousLeaf = NULL)
481{
482// if (Up != NULL)
483// if (Up->DownLeaf == NULL) // are we the first down leaf for the upper leaf?
484// Up->DownLeaf = this;
485// UpLeaf = Up;
486// DownLeaf = NULL;
487 Leaf = NULL;
488 previous = PreviousLeaf;
489 if (previous != NULL) {
490 MoleculeLeafClass *Walker = previous->next;
491 previous->next = this;
492 next = Walker;
493 } else {
494 next = NULL;
495 }
496};
497
498/** Destructor for MoleculeLeafClass.
499 */
500MoleculeLeafClass::~MoleculeLeafClass()
501{
502// if (DownLeaf != NULL) {// drop leaves further down
503// MoleculeLeafClass *Walker = DownLeaf;
504// MoleculeLeafClass *Next;
505// do {
506// Next = Walker->NextLeaf;
507// delete(Walker);
508// Walker = Next;
509// } while (Walker != NULL);
510// // Last Walker sets DownLeaf automatically to NULL
511// }
512 // remove the leaf itself
513 if (Leaf != NULL) {
514 delete(Leaf);
515 Leaf = NULL;
516 }
517 // remove this Leaf from level list
518 if (previous != NULL)
519 previous->next = next;
520// } else { // we are first in list (connects to UpLeaf->DownLeaf)
521// if ((NextLeaf != NULL) && (NextLeaf->UpLeaf == NULL))
522// NextLeaf->UpLeaf = UpLeaf; // either null as we are top level or the upleaf of the first node
523// if (UpLeaf != NULL)
524// UpLeaf->DownLeaf = NextLeaf; // either null as we are only leaf or NextLeaf if we are just the first
525// }
526// UpLeaf = NULL;
527 if (next != NULL) // are we last in list
528 next->previous = previous;
529 next = NULL;
530 previous = NULL;
531};
532
533/** Adds \a molecule leaf to the tree.
534 * \param *ptr ptr to molecule to be added
535 * \param *Previous previous MoleculeLeafClass referencing level and which on the level
536 * \return true - success, false - something went wrong
537 */
538bool MoleculeLeafClass::AddLeaf(molecule *ptr, MoleculeLeafClass *Previous)
539{
540 return false;
541};
542
543/** Fills the bond structure of this chain list subgraphs that are derived from a complete \a *reference molecule.
544 * Calls this routine in each MoleculeLeafClass::next subgraph if it's not NULL.
545 * \param *out output stream for debugging
546 * \param *reference reference molecule with the bond structure to be copied
547 * \param &FragmentCounter Counter needed to address \a **ListOfLocalAtoms
548 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in \a *reference, may be NULL on start, then it is filled
549 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
550 * \return true - success, false - faoilure
551 */
552bool MoleculeLeafClass::FillBondStructureFromReference(ofstream *out, molecule *reference, int &FragmentCounter, atom ***&ListOfLocalAtoms, bool FreeList)
553{
554 atom *Walker = NULL, *OtherWalker = NULL;
555 bond *Binder = NULL;
556 bool status = true;
557 int AtomNo;
558
559 // fill ListOfLocalAtoms if NULL was given
560 if (!FillListOfLocalAtoms(out, ListOfLocalAtoms, FragmentCounter, reference->AtomCount, FreeList)) {
561 *out << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl;
562 return false;
563 }
564
565 if (status) {
566 *out << Verbose(1) << "Creating adjacency list for subgraph " << this << "." << endl;
567 Walker = Leaf->start;
568 while (Walker->next != Leaf->end) {
569 Walker = Walker->next;
570 AtomNo = Walker->father->nr; // global id of the current walker
571 for(int i=0;i<reference->NumberOfBondsPerAtom[AtomNo];i++) { // go through father's bonds and copy them all
572 Binder = reference->ListOfBondsPerAtom[AtomNo][i];
573 OtherWalker = ListOfLocalAtoms[FragmentCounter][Binder->GetOtherAtom(Walker->father)->nr]; // local copy of current bond partner of walker
574 if (OtherWalker != NULL) {
575 if (OtherWalker->nr > Walker->nr)
576 Leaf->AddBond(Walker, OtherWalker, Binder->BondDegree);
577 } else {
578 *out << Verbose(1) << "OtherWalker = ListOfLocalAtoms[" << FragmentCounter << "][" << Binder->GetOtherAtom(Walker->father)->nr << "] is NULL!" << endl;
579 status = false;
580 }
581 }
582 }
583 Leaf->CreateListOfBondsPerAtom(out);
584 FragmentCounter++;
585 if (next != NULL)
586 status = next->FillBondStructureFromReference(out, reference, FragmentCounter, ListOfLocalAtoms);
587 }
588
589 if (FreeList) {
590 // free the index lookup list
591 Free((void **)&ListOfLocalAtoms[FragmentCounter], "MoleculeLeafClass::FillBondStructureFromReference - **ListOfLocalAtoms[]");
592 if (ListOfLocalAtoms[FragmentCounter] == NULL)
593 Free((void **)&ListOfLocalAtoms, "MoleculeLeafClass::FillBondStructureFromReference - ***ListOfLocalAtoms");
594 }
595 FragmentCounter--;
596 return status;
597};
598
599/** Fills the root stack for sites to be used as root in fragmentation depending on order or adaptivity criteria
600 * Again, as in \sa FillBondStructureFromReference steps recursively through each Leaf in this chain list of molecule's.
601 * \param *out output stream for debugging
602 * \param *&RootStack stack to be filled
603 * \param *AtomMask defines true/false per global Atom::nr to mask in/out each nuclear site
604 * \param &FragmentCounter counts through the fragments in this MoleculeLeafClass
605 * \return true - stack is non-empty, fragmentation necessary, false - stack is empty, no more sites to update
606 */
607bool MoleculeLeafClass::FillRootStackForSubgraphs(ofstream *out, KeyStack *&RootStack, bool *AtomMask, int &FragmentCounter)
608{
609 atom *Walker = NULL, *Father = NULL;
610
611 if (RootStack != NULL) {
612 // find first root candidates
613 if (&(RootStack[FragmentCounter]) != NULL) {
614 RootStack[FragmentCounter].clear();
615 Walker = Leaf->start;
616 while (Walker->next != Leaf->end) { // go through all (non-hydrogen) atoms
617 Walker = Walker->next;
618 Father = Walker->GetTrueFather();
619 if (AtomMask[Father->nr]) // apply mask
620 #ifdef ADDHYDROGEN
621 if (Walker->type->Z != 1) // skip hydrogen
622 #endif
623 RootStack[FragmentCounter].push_front(Walker->nr);
624 }
625 if (next != NULL)
626 next->FillRootStackForSubgraphs(out, RootStack, AtomMask, ++FragmentCounter);
627 } else {
628 *out << Verbose(1) << "Rootstack[" << FragmentCounter << "] is NULL." << endl;
629 return false;
630 }
631 FragmentCounter--;
632 return true;
633 } else {
634 *out << Verbose(1) << "Rootstack is NULL." << endl;
635 return false;
636 }
637};
638
639/** Fills a lookup list of father's Atom::nr -> atom for each subgraph.
640 * \param *out output stream fro debugging
641 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
642 * \param &FragmentCounter counts the fragments as we move along the list
643 * \param GlobalAtomCount number of atoms in the complete molecule
644 * \param &FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
645 * \return true - succes, false - failure
646 */
647bool MoleculeLeafClass::FillListOfLocalAtoms(ofstream *out, atom ***&ListOfLocalAtoms, int &FragmentCounter, int GlobalAtomCount, bool &FreeList)
648{
649 bool status = true;
650
651 int Counter = Count();
652 if (ListOfLocalAtoms == NULL) { // allocated initial pointer
653 // allocate and set each field to NULL
654 ListOfLocalAtoms = (atom ***) Malloc(sizeof(atom **)*Counter, "MoleculeLeafClass::FillBondStructureFromReference - ***ListOfLocalAtoms");
655 if (ListOfLocalAtoms != NULL) {
656 for (int i=Counter;i--;)
657 ListOfLocalAtoms[i] = NULL;
658 FreeList = FreeList && true;
659 } else
660 status = false;
661 }
662
663 if ((ListOfLocalAtoms != NULL) && (ListOfLocalAtoms[FragmentCounter] == NULL)) { // allocate and fill list of this fragment/subgraph
664 status = status && CreateFatherLookupTable(out, Leaf->start, Leaf->end, ListOfLocalAtoms[FragmentCounter], GlobalAtomCount);
665 FreeList = FreeList && true;
666 }
667
668 return status;
669};
670
671/** The indices per keyset are compared to the respective father's Atom::nr in each subgraph and thus put into \a **&FragmentList.
672 * \param *out output stream fro debugging
673 * \param *reference reference molecule with the bond structure to be copied
674 * \param *KeySetList list with all keysets
675 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
676 * \param **&FragmentList list to be allocated and returned
677 * \param &FragmentCounter counts the fragments as we move along the list
678 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
679 * \retuen true - success, false - failure
680 */
681bool MoleculeLeafClass::AssignKeySetsToFragment(ofstream *out, molecule *reference, Graph *KeySetList, atom ***&ListOfLocalAtoms, Graph **&FragmentList, int &FragmentCounter, bool FreeList)
682{
683 bool status = true;
684 int KeySetCounter = 0;
685
686 // fill ListOfLocalAtoms if NULL was given
687 if (!FillListOfLocalAtoms(out, ListOfLocalAtoms, FragmentCounter, reference->AtomCount, FreeList)) {
688 *out << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl;
689 return false;
690 }
691
692 // allocate fragment list
693 if (FragmentList == NULL) {
694 KeySetCounter = Count();
695 FragmentList = (Graph **) Malloc(sizeof(Graph *)*KeySetCounter, "MoleculeLeafClass::AssignKeySetsToFragment - **FragmentList");
696 for(int i=KeySetCounter;i--;)
697 FragmentList[i] = NULL;
698 KeySetCounter = 0;
699 }
700
701 if ((KeySetList != NULL) && (KeySetList->size() != 0)) { // if there are some scanned keysets at all
702 // assign scanned keysets
703 if (FragmentList[FragmentCounter] == NULL)
704 FragmentList[FragmentCounter] = new Graph;
705 KeySet *TempSet = new KeySet;
706 for(Graph::iterator runner = KeySetList->begin();runner != KeySetList->end(); runner++) { // key sets contain global numbers!
707 if ( ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*((*runner).first.begin()))->nr]->nr != -1) {// as we may assume that that bond structure is unchanged, we only test the first key in each set
708 // translate keyset to local numbers
709 for(KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
710 TempSet->insert(ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*sprinter)->nr]->nr);
711 // insert into FragmentList
712 FragmentList[FragmentCounter]->insert(GraphPair (*TempSet, pair<int,double>(KeySetCounter++, (*runner).second.second)));
713 }
714 TempSet->clear();
715 }
716 delete(TempSet);
717 if (KeySetCounter == 0) {// if there are no keysets, delete the list
718 *out << Verbose(1) << "KeySetCounter is zero, deleting FragmentList." << endl;
719 delete(FragmentList[FragmentCounter]);
720 } else
721 *out << Verbose(1) << KeySetCounter << " keysets were assigned to subgraph " << FragmentCounter << "." << endl;
722 FragmentCounter++;
723 if (next != NULL)
724 next->AssignKeySetsToFragment(out, reference, KeySetList, ListOfLocalAtoms, FragmentList, FragmentCounter, FreeList);
725 FragmentCounter--;
726 } else
727 *out << Verbose(1) << "KeySetList is NULL or empty." << endl;
728
729 return status;
730};
731
732/** Translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
733 * \param *out output stream for debugging
734 * \param **FragmentList Graph with local numbers per fragment
735 * \param &FragmentCounter counts the fragments as we move along the list
736 * \param &TotalNumberOfKeySets global key set counter
737 * \param &TotalGraph Graph to be filled with global numbers
738 */
739void MoleculeLeafClass::TranslateIndicesToGlobalIDs(ofstream *out, Graph **FragmentList, int &FragmentCounter, int &TotalNumberOfKeySets, Graph &TotalGraph)
740{
741 KeySet *TempSet = new KeySet;
742 if (FragmentList[FragmentCounter] != NULL) {
743 for(Graph::iterator runner = FragmentList[FragmentCounter]->begin(); runner != FragmentList[FragmentCounter]->end(); runner++) {
744 for(KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
745 TempSet->insert((Leaf->FindAtom(*sprinter))->GetTrueFather()->nr);
746 TotalGraph.insert(GraphPair(*TempSet, pair<int,double>(TotalNumberOfKeySets++, (*runner).second.second)));
747 TempSet->clear();
748 }
749 delete(TempSet);
750 } else {
751 *out << Verbose(1) << "FragmentList is NULL." << endl;
752 }
753 if (next != NULL)
754 next->TranslateIndicesToGlobalIDs(out, FragmentList, ++FragmentCounter, TotalNumberOfKeySets, TotalGraph);
755 FragmentCounter--;
756};
757
758/** Simply counts the number of items in the list, from given MoleculeLeafClass.
759 * \return number of items
760 */
761int MoleculeLeafClass::Count() const
762{
763 if (next != NULL)
764 return next->Count()+1;
765 else
766 return 1;
767};
Note: See TracBrowser for help on using the repository browser.