source: src/moleculelist.cpp@ ac9b56

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 ac9b56 was 520c8b, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Moved method to rename molecules to a seperate Action

  • Property mode set to 100755
File size: 46.5 KB
Line 
1/** \file MoleculeListClass.cpp
2 *
3 * Function implementations for the class MoleculeListClass.
4 *
5 */
6
7#include <cstring>
8
9#include "atom.hpp"
10#include "bond.hpp"
11#include "boundary.hpp"
12#include "config.hpp"
13#include "element.hpp"
14#include "helpers.hpp"
15#include "linkedcell.hpp"
16#include "lists.hpp"
17#include "log.hpp"
18#include "molecule.hpp"
19#include "memoryallocator.hpp"
20#include "periodentafel.hpp"
21
22/*********************************** Functions for class MoleculeListClass *************************/
23
24/** Constructor for MoleculeListClass.
25 */
26MoleculeListClass::MoleculeListClass()
27{
28 // empty lists
29 ListOfMolecules.clear();
30 MaxIndex = 1;
31};
32
33/** Destructor for MoleculeListClass.
34 */
35MoleculeListClass::~MoleculeListClass()
36{
37 Log() << Verbose(3) << this << ": Freeing ListOfMolcules." << endl;
38 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
39 Log() << Verbose(4) << "ListOfMolecules: Freeing " << *ListRunner << "." << endl;
40 delete (*ListRunner);
41 }
42 Log() << Verbose(4) << "Freeing ListOfMolecules." << endl;
43 ListOfMolecules.clear(); // empty list
44};
45
46/** Insert a new molecule into the list and set its number.
47 * \param *mol molecule to add to list.
48 * \return true - add successful
49 */
50void MoleculeListClass::insert(molecule *mol)
51{
52 START_OBSERVER;
53 mol->IndexNr = MaxIndex++;
54 ListOfMolecules.push_back(mol);
55 mol->signOn(this);
56 FINISH_OBSERVER;
57};
58
59/** Compare whether two molecules are equal.
60 * \param *a molecule one
61 * \param *n molecule two
62 * \return lexical value (-1, 0, +1)
63 */
64int MolCompare(const void *a, const void *b)
65{
66 int *aList = NULL, *bList = NULL;
67 int Count, Counter, aCounter, bCounter;
68 int flag;
69 atom *aWalker = NULL;
70 atom *bWalker = NULL;
71
72 // sort each atom list and put the numbers into a list, then go through
73 //Log() << Verbose(0) << "Comparing fragment no. " << *(molecule **)a << " to " << *(molecule **)b << "." << endl;
74 if ((**(molecule **) a).AtomCount < (**(molecule **) b).AtomCount) {
75 return -1;
76 } else {
77 if ((**(molecule **) a).AtomCount > (**(molecule **) b).AtomCount)
78 return +1;
79 else {
80 Count = (**(molecule **) a).AtomCount;
81 aList = new int[Count];
82 bList = new int[Count];
83
84 // fill the lists
85 aWalker = (**(molecule **) a).start;
86 bWalker = (**(molecule **) b).start;
87 Counter = 0;
88 aCounter = 0;
89 bCounter = 0;
90 while ((aWalker->next != (**(molecule **) a).end) && (bWalker->next != (**(molecule **) b).end)) {
91 aWalker = aWalker->next;
92 bWalker = bWalker->next;
93 if (aWalker->GetTrueFather() == NULL)
94 aList[Counter] = Count + (aCounter++);
95 else
96 aList[Counter] = aWalker->GetTrueFather()->nr;
97 if (bWalker->GetTrueFather() == NULL)
98 bList[Counter] = Count + (bCounter++);
99 else
100 bList[Counter] = bWalker->GetTrueFather()->nr;
101 Counter++;
102 }
103 // check if AtomCount was for real
104 flag = 0;
105 if ((aWalker->next == (**(molecule **) a).end) && (bWalker->next != (**(molecule **) b).end)) {
106 flag = -1;
107 } else {
108 if ((aWalker->next != (**(molecule **) a).end) && (bWalker->next == (**(molecule **) b).end))
109 flag = 1;
110 }
111 if (flag == 0) {
112 // sort the lists
113 gsl_heapsort(aList, Count, sizeof(int), CompareDoubles);
114 gsl_heapsort(bList, Count, sizeof(int), CompareDoubles);
115 // compare the lists
116
117 flag = 0;
118 for (int i = 0; i < Count; i++) {
119 if (aList[i] < bList[i]) {
120 flag = -1;
121 } else {
122 if (aList[i] > bList[i])
123 flag = 1;
124 }
125 if (flag != 0)
126 break;
127 }
128 }
129 delete[] (aList);
130 delete[] (bList);
131 return flag;
132 }
133 }
134 return -1;
135};
136
137/** Output of a list of all molecules.
138 * \param *out output stream
139 */
140void MoleculeListClass::Enumerate(ofstream *out)
141{
142 element* Elemental = NULL;
143 atom *Walker = NULL;
144 int Counts[MAX_ELEMENTS];
145 double size=0;
146 Vector Origin;
147
148 // header
149 (*out) << "Index\tName\t\tAtoms\tFormula\tCenter\tSize" << endl;
150 (*out) << "-----------------------------------------------" << endl;
151 if (ListOfMolecules.size() == 0)
152 (*out) << "\tNone" << endl;
153 else {
154 Origin.Zero();
155 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
156 // reset element counts
157 for (int j = 0; j<MAX_ELEMENTS;j++)
158 Counts[j] = 0;
159 // count atoms per element and determine size of bounding sphere
160 size=0.;
161 Walker = (*ListRunner)->start;
162 while (Walker->next != (*ListRunner)->end) {
163 Walker = Walker->next;
164 Counts[Walker->type->Z]++;
165 if (Walker->x.DistanceSquared(&Origin) > size)
166 size = Walker->x.DistanceSquared(&Origin);
167 }
168 // output Index, Name, number of atoms, chemical formula
169 (*out) << ((*ListRunner)->ActiveFlag ? "*" : " ") << (*ListRunner)->IndexNr << "\t" << (*ListRunner)->name << "\t\t" << (*ListRunner)->AtomCount << "\t";
170 Elemental = (*ListRunner)->elemente->end;
171 while(Elemental->previous != (*ListRunner)->elemente->start) {
172 Elemental = Elemental->previous;
173 if (Counts[Elemental->Z] != 0)
174 (*out) << Elemental->symbol << Counts[Elemental->Z];
175 }
176 // Center and size
177 (*out) << "\t" << (*ListRunner)->Center << "\t" << sqrt(size) << endl;
178 }
179 }
180};
181
182/** Returns the molecule with the given index \a index.
183 * \param index index of the desired molecule
184 * \return pointer to molecule structure, NULL if not found
185 */
186molecule * MoleculeListClass::ReturnIndex(int index)
187{
188 for(MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
189 if ((*ListRunner)->IndexNr == index)
190 return (*ListRunner);
191 return NULL;
192};
193
194/** Simple merge of two molecules into one.
195 * \param *mol destination molecule
196 * \param *srcmol source molecule
197 * \return true - merge successful, false - merge failed (probably due to non-existant indices
198 */
199bool MoleculeListClass::SimpleMerge(molecule *mol, molecule *srcmol)
200{
201 if (srcmol == NULL)
202 return false;
203
204 // put all molecules of src into mol
205 atom *Walker = srcmol->start;
206 atom *NextAtom = Walker->next;
207 while (NextAtom != srcmol->end) {
208 Walker = NextAtom;
209 NextAtom = Walker->next;
210 srcmol->UnlinkAtom(Walker);
211 mol->AddAtom(Walker);
212 }
213
214 // remove src
215 ListOfMolecules.remove(srcmol);
216 delete(srcmol);
217 return true;
218};
219
220/** Simple add of one molecules into another.
221 * \param *mol destination molecule
222 * \param *srcmol source molecule
223 * \return true - merge successful, false - merge failed (probably due to non-existant indices
224 */
225bool MoleculeListClass::SimpleAdd(molecule *mol, molecule *srcmol)
226{
227 if (srcmol == NULL)
228 return false;
229
230 // put all molecules of src into mol
231 atom *Walker = srcmol->start;
232 atom *NextAtom = Walker->next;
233 while (NextAtom != srcmol->end) {
234 Walker = NextAtom;
235 NextAtom = Walker->next;
236 Walker = mol->AddCopyAtom(Walker);
237 Walker->father = Walker;
238 }
239
240 return true;
241};
242
243/** Simple merge of a given set of molecules into one.
244 * \param *mol destination molecule
245 * \param *src index of set of source molecule
246 * \param N number of source molecules
247 * \return true - merge successful, false - some merges failed (probably due to non-existant indices)
248 */
249bool MoleculeListClass::SimpleMultiMerge(molecule *mol, int *src, int N)
250{
251 bool status = true;
252 // check presence of all source molecules
253 for (int i=0;i<N;i++) {
254 molecule *srcmol = ReturnIndex(src[i]);
255 status = status && SimpleMerge(mol, srcmol);
256 }
257 return status;
258};
259
260/** Simple add of a given set of molecules into one.
261 * \param *mol destination molecule
262 * \param *src index of set of source molecule
263 * \param N number of source molecules
264 * \return true - merge successful, false - some merges failed (probably due to non-existant indices)
265 */
266bool MoleculeListClass::SimpleMultiAdd(molecule *mol, int *src, int N)
267{
268 bool status = true;
269 // check presence of all source molecules
270 for (int i=0;i<N;i++) {
271 molecule *srcmol = ReturnIndex(src[i]);
272 status = status && SimpleAdd(mol, srcmol);
273 }
274 return status;
275};
276
277/** Scatter merge of a given set of molecules into one.
278 * Scatter merge distributes the molecules in such a manner that they don't overlap.
279 * \param *mol destination molecule
280 * \param *src index of set of source molecule
281 * \param N number of source molecules
282 * \return true - merge successful, false - merge failed (probably due to non-existant indices
283 * \TODO find scatter center for each src molecule
284 */
285bool MoleculeListClass::ScatterMerge(molecule *mol, int *src, int N)
286{
287 // check presence of all source molecules
288 for (int i=0;i<N;i++) {
289 // get pointer to src molecule
290 molecule *srcmol = ReturnIndex(src[i]);
291 if (srcmol == NULL)
292 return false;
293 }
294 // adapt each Center
295 for (int i=0;i<N;i++) {
296 // get pointer to src molecule
297 molecule *srcmol = ReturnIndex(src[i]);
298 //srcmol->Center.Zero();
299 srcmol->Translate(&srcmol->Center);
300 }
301 // perform a simple multi merge
302 SimpleMultiMerge(mol, src, N);
303 return true;
304};
305
306/** Embedding merge of a given set of molecules into one.
307 * Embedding merge inserts one molecule into the other.
308 * \param *mol destination molecule (fixed one)
309 * \param *srcmol source molecule (variable one, where atoms are taken from)
310 * \return true - merge successful, false - merge failed (probably due to non-existant indices)
311 * \TODO linked cell dimensions for boundary points has to be as big as inner diameter!
312 */
313bool MoleculeListClass::EmbedMerge(molecule *mol, molecule *srcmol)
314{
315 LinkedCell *LCList = NULL;
316 Tesselation *TesselStruct = NULL;
317 if ((srcmol == NULL) || (mol == NULL)) {
318 eLog() << Verbose(1) << "Either fixed or variable molecule is given as NULL." << endl;
319 return false;
320 }
321
322 // calculate envelope for *mol
323 LCList = new LinkedCell(mol, 8.);
324 FindNonConvexBorder(mol, TesselStruct, (const LinkedCell *&)LCList, 4., NULL);
325 if (TesselStruct == NULL) {
326 eLog() << Verbose(1) << "Could not tesselate the fixed molecule." << endl;
327 return false;
328 }
329 delete(LCList);
330 LCList = new LinkedCell(TesselStruct, 8.); // re-create with boundary points only!
331
332 // prepare index list for bonds
333 srcmol->CountAtoms();
334 atom ** CopyAtoms = new atom*[srcmol->AtomCount];
335 for(int i=0;i<srcmol->AtomCount;i++)
336 CopyAtoms[i] = NULL;
337
338 // for each of the source atoms check whether we are in- or outside and add copy atom
339 atom *Walker = srcmol->start;
340 int nr=0;
341 while (Walker->next != srcmol->end) {
342 Walker = Walker->next;
343 Log() << Verbose(2) << "INFO: Current Walker is " << *Walker << "." << endl;
344 if (!TesselStruct->IsInnerPoint(Walker->x, LCList)) {
345 CopyAtoms[Walker->nr] = new atom(Walker);
346 mol->AddAtom(CopyAtoms[Walker->nr]);
347 nr++;
348 } else {
349 // do nothing
350 }
351 }
352 Log() << Verbose(1) << nr << " of " << srcmol->AtomCount << " atoms have been merged.";
353
354 // go through all bonds and add as well
355 bond *Binder = srcmol->first;
356 while(Binder->next != srcmol->last) {
357 Binder = Binder->next;
358 Log() << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
359 mol->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
360 }
361 delete(LCList);
362 return true;
363};
364
365/** Simple output of the pointers in ListOfMolecules.
366 * \param *out output stream
367 */
368void MoleculeListClass::Output(ofstream *out)
369{
370 Log() << Verbose(1) << "MoleculeList: ";
371 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
372 Log() << Verbose(0) << *ListRunner << "\t";
373 Log() << Verbose(0) << endl;
374};
375
376/** Calculates necessary hydrogen correction due to unwanted interaction between saturated ones.
377 * If for a pair of two hydrogen atoms a and b, at least is a saturated one, and a and b are not
378 * bonded to the same atom, then we add for this pair a correction term constructed from a Morse
379 * potential function fit to QM calculations with respecting to the interatomic hydrogen distance.
380 * \param *out output stream for debugging
381 * \param *path path to file
382 */
383bool MoleculeListClass::AddHydrogenCorrection(char *path)
384{
385 atom *Walker = NULL;
386 atom *Runner = NULL;
387 bond *Binder = NULL;
388 double ***FitConstant = NULL, **correction = NULL;
389 int a, b;
390 ofstream output;
391 ifstream input;
392 string line;
393 stringstream zeile;
394 double distance;
395 char ParsedLine[1023];
396 double tmp;
397 char *FragmentNumber = NULL;
398
399 Log() << Verbose(1) << "Saving hydrogen saturation correction ... ";
400 // 0. parse in fit constant files that should have the same dimension as the final energy files
401 // 0a. find dimension of matrices with constants
402 line = path;
403 line.append("/");
404 line += FRAGMENTPREFIX;
405 line += "1";
406 line += FITCONSTANTSUFFIX;
407 input.open(line.c_str());
408 if (input == NULL) {
409 Log() << Verbose(1) << endl << "Unable to open " << line << ", is the directory correct?" << endl;
410 return false;
411 }
412 a = 0;
413 b = -1; // we overcount by one
414 while (!input.eof()) {
415 input.getline(ParsedLine, 1023);
416 zeile.str(ParsedLine);
417 int i = 0;
418 while (!zeile.eof()) {
419 zeile >> distance;
420 i++;
421 }
422 if (i > a)
423 a = i;
424 b++;
425 }
426 Log() << Verbose(0) << "I recognized " << a << " columns and " << b << " rows, ";
427 input.close();
428
429 // 0b. allocate memory for constants
430 FitConstant = Calloc<double**>(3, "MoleculeListClass::AddHydrogenCorrection: ***FitConstant");
431 for (int k = 0; k < 3; k++) {
432 FitConstant[k] = Calloc<double*>(a, "MoleculeListClass::AddHydrogenCorrection: **FitConstant[]");
433 for (int i = a; i--;) {
434 FitConstant[k][i] = Calloc<double>(b, "MoleculeListClass::AddHydrogenCorrection: *FitConstant[][]");
435 }
436 }
437 // 0c. parse in constants
438 for (int i = 0; i < 3; i++) {
439 line = path;
440 line.append("/");
441 line += FRAGMENTPREFIX;
442 sprintf(ParsedLine, "%d", i + 1);
443 line += ParsedLine;
444 line += FITCONSTANTSUFFIX;
445 input.open(line.c_str());
446 if (input == NULL) {
447 eLog() << Verbose(0) << endl << "Unable to open " << line << ", is the directory correct?" << endl;
448 performCriticalExit();
449 return false;
450 }
451 int k = 0, l;
452 while ((!input.eof()) && (k < b)) {
453 input.getline(ParsedLine, 1023);
454 //Log() << Verbose(0) << "Current Line: " << ParsedLine << endl;
455 zeile.str(ParsedLine);
456 zeile.clear();
457 l = 0;
458 while ((!zeile.eof()) && (l < a)) {
459 zeile >> FitConstant[i][l][k];
460 //Log() << Verbose(0) << FitConstant[i][l][k] << "\t";
461 l++;
462 }
463 //Log() << Verbose(0) << endl;
464 k++;
465 }
466 input.close();
467 }
468 for (int k = 0; k < 3; k++) {
469 Log() << Verbose(0) << "Constants " << k << ":" << endl;
470 for (int j = 0; j < b; j++) {
471 for (int i = 0; i < a; i++) {
472 Log() << Verbose(0) << FitConstant[k][i][j] << "\t";
473 }
474 Log() << Verbose(0) << endl;
475 }
476 Log() << Verbose(0) << endl;
477 }
478
479 // 0d. allocate final correction matrix
480 correction = Calloc<double*>(a, "MoleculeListClass::AddHydrogenCorrection: **correction");
481 for (int i = a; i--;)
482 correction[i] = Calloc<double>(b, "MoleculeListClass::AddHydrogenCorrection: *correction[]");
483
484 // 1a. go through every molecule in the list
485 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
486 // 1b. zero final correction matrix
487 for (int k = a; k--;)
488 for (int j = b; j--;)
489 correction[k][j] = 0.;
490 // 2. take every hydrogen that is a saturated one
491 Walker = (*ListRunner)->start;
492 while (Walker->next != (*ListRunner)->end) {
493 Walker = Walker->next;
494 //Log() << Verbose(1) << "Walker: " << *Walker << " with first bond " << *(Walker->ListOfBonds.begin()) << "." << endl;
495 if ((Walker->type->Z == 1) && ((Walker->father == NULL)
496 || (Walker->father->type->Z != 1))) { // if it's a hydrogen
497 Runner = (*ListRunner)->start;
498 while (Runner->next != (*ListRunner)->end) {
499 Runner = Runner->next;
500 //Log() << Verbose(2) << "Runner: " << *Runner << " with first bond " << *(Walker->ListOfBonds.begin()) << "." << endl;
501 // 3. take every other hydrogen that is the not the first and not bound to same bonding partner
502 Binder = *(Runner->ListOfBonds.begin());
503 if ((Runner->type->Z == 1) && (Runner->nr > Walker->nr) && (Binder->GetOtherAtom(Runner) != Binder->GetOtherAtom(Walker))) { // (hydrogens have only one bonding partner!)
504 // 4. evaluate the morse potential for each matrix component and add up
505 distance = Runner->x.Distance(&Walker->x);
506 //Log() << Verbose(0) << "Fragment " << (*ListRunner)->name << ": " << *Runner << "<= " << distance << "=>" << *Walker << ":" << endl;
507 for (int k = 0; k < a; k++) {
508 for (int j = 0; j < b; j++) {
509 switch (k) {
510 case 1:
511 case 7:
512 case 11:
513 tmp = pow(FitConstant[0][k][j] * (1. - exp(-FitConstant[1][k][j] * (distance - FitConstant[2][k][j]))), 2);
514 break;
515 default:
516 tmp = FitConstant[0][k][j] * pow(distance, FitConstant[1][k][j]) + FitConstant[2][k][j];
517 };
518 correction[k][j] -= tmp; // ground state is actually lower (disturbed by additional interaction)
519 //Log() << Verbose(0) << tmp << "\t";
520 }
521 //Log() << Verbose(0) << endl;
522 }
523 //Log() << Verbose(0) << endl;
524 }
525 }
526 }
527 }
528 // 5. write final matrix to file
529 line = path;
530 line.append("/");
531 line += FRAGMENTPREFIX;
532 FragmentNumber = FixedDigitNumber(ListOfMolecules.size(), (*ListRunner)->IndexNr);
533 line += FragmentNumber;
534 delete (FragmentNumber);
535 line += HCORRECTIONSUFFIX;
536 output.open(line.c_str());
537 output << "Time\t\tTotal\t\tKinetic\t\tNonLocal\tCorrelation\tExchange\tPseudo\t\tHartree\t\t-Gauss\t\tEwald\t\tIonKin\t\tETotal" << endl;
538 for (int j = 0; j < b; j++) {
539 for (int i = 0; i < a; i++)
540 output << correction[i][j] << "\t";
541 output << endl;
542 }
543 output.close();
544 }
545 line = path;
546 line.append("/");
547 line += HCORRECTIONSUFFIX;
548 output.open(line.c_str());
549 output << "Time\t\tTotal\t\tKinetic\t\tNonLocal\tCorrelation\tExchange\tPseudo\t\tHartree\t\t-Gauss\t\tEwald\t\tIonKin\t\tETotal" << endl;
550 for (int j = 0; j < b; j++) {
551 for (int i = 0; i < a; i++)
552 output << 0 << "\t";
553 output << endl;
554 }
555 output.close();
556 // 6. free memory of parsed matrices
557 for (int k = 0; k < 3; k++) {
558 for (int i = a; i--;) {
559 Free(&FitConstant[k][i]);
560 }
561 Free(&FitConstant[k]);
562 }
563 Free(&FitConstant);
564 Log() << Verbose(0) << "done." << endl;
565 return true;
566};
567
568/** Store force indices, i.e. the connection between the nuclear index in the total molecule config and the respective atom in fragment config.
569 * \param *out output stream for debugging
570 * \param *path path to file
571 * \param *SortIndex Index to map from the BFS labeling to the sequence how of Ion_Type in the config
572 * \return true - file written successfully, false - writing failed
573 */
574bool MoleculeListClass::StoreForcesFile(char *path,
575 int *SortIndex)
576{
577 bool status = true;
578 ofstream ForcesFile;
579 stringstream line;
580 atom *Walker = NULL;
581 element *runner = NULL;
582
583 // open file for the force factors
584 Log() << Verbose(1) << "Saving force factors ... ";
585 line << path << "/" << FRAGMENTPREFIX << FORCESFILE;
586 ForcesFile.open(line.str().c_str(), ios::out);
587 if (ForcesFile != NULL) {
588 //Log() << Verbose(1) << "Final AtomicForcesList: ";
589 //output << prefix << "Forces" << endl;
590 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
591 runner = (*ListRunner)->elemente->start;
592 while (runner->next != (*ListRunner)->elemente->end) { // go through every element
593 runner = runner->next;
594 if ((*ListRunner)->ElementsInMolecule[runner->Z]) { // if this element got atoms
595 Walker = (*ListRunner)->start;
596 while (Walker->next != (*ListRunner)->end) { // go through every atom of this element
597 Walker = Walker->next;
598 if (Walker->type->Z == runner->Z) {
599 if ((Walker->GetTrueFather() != NULL) && (Walker->GetTrueFather() != Walker)) {// if there is a rea
600 //Log() << Verbose(0) << "Walker is " << *Walker << " with true father " << *( Walker->GetTrueFather()) << ", it
601 ForcesFile << SortIndex[Walker->GetTrueFather()->nr] << "\t";
602 } else
603 // otherwise a -1 to indicate an added saturation hydrogen
604 ForcesFile << "-1\t";
605 }
606 }
607 }
608 }
609 ForcesFile << endl;
610 }
611 ForcesFile.close();
612 Log() << Verbose(1) << "done." << endl;
613 } else {
614 status = false;
615 Log() << Verbose(1) << "failed to open file " << line.str() << "." << endl;
616 }
617 ForcesFile.close();
618
619 return status;
620};
621
622/** Writes a config file for each molecule in the given \a **FragmentList.
623 * \param *out output stream for debugging
624 * \param *configuration standard configuration to attach atoms in fragment molecule to.
625 * \param *SortIndex Index to map from the BFS labeling to the sequence how of Ion_Type in the config
626 * \param DoPeriodic true - call ScanForPeriodicCorrection, false - don't
627 * \param DoCentering true - call molecule::CenterEdge(), false - don't
628 * \return true - success (each file was written), false - something went wrong.
629 */
630bool MoleculeListClass::OutputConfigForListOfFragments(config *configuration, int *SortIndex)
631{
632 ofstream outputFragment;
633 char FragmentName[MAXSTRINGSIZE];
634 char PathBackup[MAXSTRINGSIZE];
635 bool result = true;
636 bool intermediateResult = true;
637 atom *Walker = NULL;
638 Vector BoxDimension;
639 char *FragmentNumber = NULL;
640 char *path = NULL;
641 int FragmentCounter = 0;
642 ofstream output;
643
644 // store the fragments as config and as xyz
645 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
646 // save default path as it is changed for each fragment
647 path = configuration->GetDefaultPath();
648 if (path != NULL)
649 strcpy(PathBackup, path);
650 else {
651 eLog() << Verbose(0) << "OutputConfigForListOfFragments: NULL default path obtained from config!" << endl;
652 performCriticalExit();
653 }
654
655 // correct periodic
656 (*ListRunner)->ScanForPeriodicCorrection();
657
658 // output xyz file
659 FragmentNumber = FixedDigitNumber(ListOfMolecules.size(), FragmentCounter++);
660 sprintf(FragmentName, "%s/%s%s.conf.xyz", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
661 outputFragment.open(FragmentName, ios::out);
662 Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as XYZ ...";
663 if ((intermediateResult = (*ListRunner)->OutputXYZ(&outputFragment)))
664 Log() << Verbose(0) << " done." << endl;
665 else
666 Log() << Verbose(0) << " failed." << endl;
667 result = result && intermediateResult;
668 outputFragment.close();
669 outputFragment.clear();
670
671 // list atoms in fragment for debugging
672 Log() << Verbose(2) << "Contained atoms: ";
673 Walker = (*ListRunner)->start;
674 while (Walker->next != (*ListRunner)->end) {
675 Walker = Walker->next;
676 Log() << Verbose(0) << Walker->Name << " ";
677 }
678 Log() << Verbose(0) << endl;
679
680 // center on edge
681 (*ListRunner)->CenterEdge(&BoxDimension);
682 (*ListRunner)->SetBoxDimension(&BoxDimension); // update Box of atoms by boundary
683 int j = -1;
684 for (int k = 0; k < NDIM; k++) {
685 j += k + 1;
686 BoxDimension.x[k] = 2.5 * (configuration->GetIsAngstroem() ? 1. : 1. / AtomicLengthToAngstroem);
687 (*ListRunner)->cell_size[j] += BoxDimension.x[k] * 2.;
688 }
689 (*ListRunner)->Translate(&BoxDimension);
690
691 // also calculate necessary orbitals
692 (*ListRunner)->CountElements(); // this is a bugfix, atoms should shoulds actually be added correctly to this fragment
693 (*ListRunner)->CalculateOrbitals(*configuration);
694
695 // change path in config
696 //strcpy(PathBackup, configuration->configpath);
697 sprintf(FragmentName, "%s/%s%s/", PathBackup, FRAGMENTPREFIX, FragmentNumber);
698 configuration->SetDefaultPath(FragmentName);
699
700 // and save as config
701 sprintf(FragmentName, "%s/%s%s.conf", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
702 Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as config ...";
703 if ((intermediateResult = configuration->Save(FragmentName, (*ListRunner)->elemente, (*ListRunner))))
704 Log() << Verbose(0) << " done." << endl;
705 else
706 Log() << Verbose(0) << " failed." << endl;
707 result = result && intermediateResult;
708
709 // restore old config
710 configuration->SetDefaultPath(PathBackup);
711
712 // and save as mpqc input file
713 sprintf(FragmentName, "%s/%s%s.conf", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
714 Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as mpqc input ...";
715 if ((intermediateResult = configuration->SaveMPQC(FragmentName, (*ListRunner))))
716 Log() << Verbose(2) << " done." << endl;
717 else
718 Log() << Verbose(0) << " failed." << endl;
719
720 result = result && intermediateResult;
721 //outputFragment.close();
722 //outputFragment.clear();
723 Free(&FragmentNumber);
724 }
725 Log() << Verbose(0) << " done." << endl;
726
727 // printing final number
728 Log() << Verbose(2) << "Final number of fragments: " << FragmentCounter << "." << endl;
729
730 return result;
731};
732
733/** Counts the number of molecules with the molecule::ActiveFlag set.
734 * \return number of molecules with ActiveFlag set to true.
735 */
736int MoleculeListClass::NumberOfActiveMolecules()
737{
738 int count = 0;
739 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
740 count += ((*ListRunner)->ActiveFlag ? 1 : 0);
741 return count;
742};
743
744/** Dissects given \a *mol into connected subgraphs and inserts them as new molecules but with old atoms into \a this.
745 * \param *out output stream for debugging
746 * \param *periode periodentafel
747 * \param *configuration config with BondGraph
748 */
749void MoleculeListClass::DissectMoleculeIntoConnectedSubgraphs(const periodentafel * const periode, config * const configuration)
750{
751 molecule *mol = new molecule(periode);
752 atom *Walker = NULL;
753 atom *Advancer = NULL;
754 bond *Binder = NULL;
755 bond *Stepper = NULL;
756 // 0. gather all atoms into single molecule
757 for (MoleculeList::iterator MolRunner = ListOfMolecules.begin(); !ListOfMolecules.empty(); MolRunner = ListOfMolecules.begin()) {
758 // shift all atoms to new molecule
759 Advancer = (*MolRunner)->start->next;
760 while (Advancer != (*MolRunner)->end) {
761 Walker = Advancer;
762 Advancer = Advancer->next;
763 Log() << Verbose(3) << "Re-linking " << *Walker << "..." << endl;
764 unlink(Walker);
765 Walker->father = Walker;
766 mol->AddAtom(Walker); // counting starts at 1
767 }
768 // remove all bonds
769 Stepper = (*MolRunner)->first->next;
770 while (Stepper != (*MolRunner)->last) {
771 Binder = Stepper;
772 Stepper = Stepper->next;
773 delete(Binder);
774 }
775 // remove the molecule
776 delete(*MolRunner);
777 ListOfMolecules.erase(MolRunner);
778 }
779
780 // 1. dissect the molecule into connected subgraphs
781 configuration->BG->ConstructBondGraph(mol);
782
783 // 2. scan for connected subgraphs
784 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
785 class StackClass<bond *> *BackEdgeStack = NULL;
786 Subgraphs = mol->DepthFirstSearchAnalysis(BackEdgeStack);
787 delete(BackEdgeStack);
788
789 // 3. dissect (the following construct is needed to have the atoms not in the order of the DFS, but in
790 // the original one as parsed in)
791 // TODO: Optimize this, when molecules just contain pointer list of global atoms!
792
793 // 4a. create array of molecules to fill
794 const int MolCount = Subgraphs->next->Count();
795 char number[MAXSTRINGSIZE];
796 molecule **molecules = Malloc<molecule *>(MolCount, "config::Load() - **molecules");
797 for (int i=0;i<MolCount;i++) {
798 molecules[i] = (molecule*) new molecule(mol->elemente);
799 molecules[i]->ActiveFlag = true;
800 strncpy(molecules[i]->name, mol->name, MAXSTRINGSIZE);
801 if (MolCount > 1) {
802 sprintf(number, "-%d", i+1);
803 strncat(molecules[i]->name, number, MAXSTRINGSIZE - strlen(mol->name) - 1);
804 }
805 cout << "MolName is " << molecules[i]->name << endl;
806 insert(molecules[i]);
807 }
808
809 // 4b. create and fill map of which atom is associated to which connected molecule (note, counting starts at 1)
810 int FragmentCounter = 0;
811 int *MolMap = Calloc<int>(mol->AtomCount, "config::Load() - *MolMap");
812 MoleculeLeafClass *MolecularWalker = Subgraphs;
813 Walker = NULL;
814 while (MolecularWalker->next != NULL) {
815 MolecularWalker = MolecularWalker->next;
816 Walker = MolecularWalker->Leaf->start;
817 while (Walker->next != MolecularWalker->Leaf->end) {
818 Walker = Walker->next;
819 MolMap[Walker->GetTrueFather()->nr] = FragmentCounter+1;
820 }
821 FragmentCounter++;
822 }
823
824 // 4c. relocate atoms to new molecules and remove from Leafs
825 Walker = NULL;
826 while (mol->start->next != mol->end) {
827 Walker = mol->start->next;
828 if ((Walker->nr <0) || (Walker->nr >= mol->AtomCount)) {
829 eLog() << Verbose(0) << "Index of atom " << *Walker << " is invalid!" << endl;
830 performCriticalExit();
831 }
832 FragmentCounter = MolMap[Walker->nr];
833 if (FragmentCounter != 0) {
834 Log() << Verbose(3) << "Re-linking " << *Walker << "..." << endl;
835 unlink(Walker);
836 molecules[FragmentCounter-1]->AddAtom(Walker); // counting starts at 1
837 } else {
838 eLog() << Verbose(0) << "Atom " << *Walker << " not associated to molecule!" << endl;
839 performCriticalExit();
840 }
841 }
842 // 4d. we don't need to redo bonds, as they are connected subgraphs and still maintain their ListOfBonds, but we have to remove them from first..last list
843 Binder = mol->first;
844 while (mol->first->next != mol->last) {
845 Binder = mol->first->next;
846 Walker = Binder->leftatom;
847 unlink(Binder);
848 link(Binder,molecules[MolMap[Walker->nr]-1]->last); // counting starts at 1
849 }
850 // 4e. free Leafs
851 MolecularWalker = Subgraphs;
852 while (MolecularWalker->next != NULL) {
853 MolecularWalker = MolecularWalker->next;
854 delete(MolecularWalker->previous);
855 }
856 delete(MolecularWalker);
857 Free(&MolMap);
858 Free(&molecules);
859 Log() << Verbose(1) << "I scanned " << FragmentCounter << " molecules." << endl;
860};
861
862/** Count all atoms in each molecule.
863 * \return number of atoms in the MoleculeListClass.
864 * TODO: the inner loop should be done by some (double molecule::CountAtom()) function
865 */
866int MoleculeListClass::CountAllAtoms() const
867{
868 atom *Walker = NULL;
869 int AtomNo = 0;
870 for (MoleculeList::const_iterator MolWalker = ListOfMolecules.begin(); MolWalker != ListOfMolecules.end(); MolWalker++) {
871 Walker = (*MolWalker)->start;
872 while (Walker->next != (*MolWalker)->end) {
873 Walker = Walker->next;
874 AtomNo++;
875 }
876 }
877 return AtomNo;
878}
879
880/***********
881 * Methods Moved here from the menus
882 */
883
884void MoleculeListClass::flipChosen() {
885 int j;
886 Log() << Verbose(0) << "Enter index of molecule: ";
887 cin >> j;
888 for(MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
889 if ((*ListRunner)->IndexNr == j)
890 (*ListRunner)->ActiveFlag = !(*ListRunner)->ActiveFlag;
891}
892
893void MoleculeListClass::createNewMolecule(periodentafel *periode) {
894 START_OBSERVER;
895 molecule *mol = NULL;
896 mol = new molecule(periode);
897 insert(mol);
898 FINISH_OBSERVER;
899};
900
901void MoleculeListClass::loadFromXYZ(periodentafel *periode){
902 molecule *mol = NULL;
903 Vector center;
904 char filename[MAXSTRINGSIZE];
905 Log() << Verbose(0) << "Format should be XYZ with: ShorthandOfElement\tX\tY\tZ" << endl;
906 mol = new molecule(periode);
907 do {
908 Log() << Verbose(0) << "Enter file name: ";
909 cin >> filename;
910 } while (!mol->AddXYZFile(filename));
911 mol->SetNameFromFilename(filename);
912 // center at set box dimensions
913 mol->CenterEdge(&center);
914 mol->cell_size[0] = center.x[0];
915 mol->cell_size[1] = 0;
916 mol->cell_size[2] = center.x[1];
917 mol->cell_size[3] = 0;
918 mol->cell_size[4] = 0;
919 mol->cell_size[5] = center.x[2];
920 insert(mol);
921}
922
923void MoleculeListClass::setMoleculeFilename() {
924 char filename[MAXSTRINGSIZE];
925 int nr;
926 molecule *mol = NULL;
927 do {
928 Log() << Verbose(0) << "Enter index of molecule: ";
929 cin >> nr;
930 mol = ReturnIndex(nr);
931 } while (mol == NULL);
932 Log() << Verbose(0) << "Enter name: ";
933 cin >> filename;
934 mol->SetNameFromFilename(filename);
935}
936
937void MoleculeListClass::parseXYZIntoMolecule(){
938 char filename[MAXSTRINGSIZE];
939 int nr;
940 molecule *mol = NULL;
941 mol = NULL;
942 do {
943 Log() << Verbose(0) << "Enter index of molecule: ";
944 cin >> nr;
945 mol = ReturnIndex(nr);
946 } while (mol == NULL);
947 Log() << Verbose(0) << "Format should be XYZ with: ShorthandOfElement\tX\tY\tZ" << endl;
948 do {
949 Log() << Verbose(0) << "Enter file name: ";
950 cin >> filename;
951 } while (!mol->AddXYZFile(filename));
952 mol->SetNameFromFilename(filename);
953};
954
955void MoleculeListClass::eraseMolecule(){
956 int nr;
957 molecule *mol = NULL;
958 Log() << Verbose(0) << "Enter index of molecule: ";
959 cin >> nr;
960 for(MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
961 if (nr == (*ListRunner)->IndexNr) {
962 mol = *ListRunner;
963 ListOfMolecules.erase(ListRunner);
964 delete(mol);
965 break;
966 }
967};
968
969
970/******************************************* Class MoleculeLeafClass ************************************************/
971
972/** Constructor for MoleculeLeafClass root leaf.
973 * \param *Up Leaf on upper level
974 * \param *PreviousLeaf NULL - We are the first leaf on this level, otherwise points to previous in list
975 */
976//MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *Up = NULL, MoleculeLeafClass *Previous = NULL)
977MoleculeLeafClass::MoleculeLeafClass(MoleculeLeafClass *PreviousLeaf = NULL)
978{
979 // if (Up != NULL)
980 // if (Up->DownLeaf == NULL) // are we the first down leaf for the upper leaf?
981 // Up->DownLeaf = this;
982 // UpLeaf = Up;
983 // DownLeaf = NULL;
984 Leaf = NULL;
985 previous = PreviousLeaf;
986 if (previous != NULL) {
987 MoleculeLeafClass *Walker = previous->next;
988 previous->next = this;
989 next = Walker;
990 } else {
991 next = NULL;
992 }
993};
994
995/** Destructor for MoleculeLeafClass.
996 */
997MoleculeLeafClass::~MoleculeLeafClass()
998{
999 // if (DownLeaf != NULL) {// drop leaves further down
1000 // MoleculeLeafClass *Walker = DownLeaf;
1001 // MoleculeLeafClass *Next;
1002 // do {
1003 // Next = Walker->NextLeaf;
1004 // delete(Walker);
1005 // Walker = Next;
1006 // } while (Walker != NULL);
1007 // // Last Walker sets DownLeaf automatically to NULL
1008 // }
1009 // remove the leaf itself
1010 if (Leaf != NULL) {
1011 delete (Leaf);
1012 Leaf = NULL;
1013 }
1014 // remove this Leaf from level list
1015 if (previous != NULL)
1016 previous->next = next;
1017 // } else { // we are first in list (connects to UpLeaf->DownLeaf)
1018 // if ((NextLeaf != NULL) && (NextLeaf->UpLeaf == NULL))
1019 // NextLeaf->UpLeaf = UpLeaf; // either null as we are top level or the upleaf of the first node
1020 // if (UpLeaf != NULL)
1021 // UpLeaf->DownLeaf = NextLeaf; // either null as we are only leaf or NextLeaf if we are just the first
1022 // }
1023 // UpLeaf = NULL;
1024 if (next != NULL) // are we last in list
1025 next->previous = previous;
1026 next = NULL;
1027 previous = NULL;
1028};
1029
1030/** Adds \a molecule leaf to the tree.
1031 * \param *ptr ptr to molecule to be added
1032 * \param *Previous previous MoleculeLeafClass referencing level and which on the level
1033 * \return true - success, false - something went wrong
1034 */
1035bool MoleculeLeafClass::AddLeaf(molecule *ptr, MoleculeLeafClass *Previous)
1036{
1037 return false;
1038};
1039
1040/** Fills the bond structure of this chain list subgraphs that are derived from a complete \a *reference molecule.
1041 * Calls this routine in each MoleculeLeafClass::next subgraph if it's not NULL.
1042 * \param *out output stream for debugging
1043 * \param *reference reference molecule with the bond structure to be copied
1044 * \param &FragmentCounter Counter needed to address \a **ListOfLocalAtoms
1045 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in \a *reference, may be NULL on start, then it is filled
1046 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
1047 * \return true - success, false - faoilure
1048 */
1049bool MoleculeLeafClass::FillBondStructureFromReference(const molecule * const reference, int &FragmentCounter, atom ***&ListOfLocalAtoms, bool FreeList)
1050{
1051 atom *Walker = NULL;
1052 atom *OtherWalker = NULL;
1053 atom *Father = NULL;
1054 bool status = true;
1055 int AtomNo;
1056
1057 Log() << Verbose(1) << "Begin of FillBondStructureFromReference." << endl;
1058 // fill ListOfLocalAtoms if NULL was given
1059 if (!FillListOfLocalAtoms(ListOfLocalAtoms, FragmentCounter, reference->AtomCount, FreeList)) {
1060 Log() << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl;
1061 return false;
1062 }
1063
1064 if (status) {
1065 Log() << Verbose(1) << "Creating adjacency list for subgraph " << Leaf << "." << endl;
1066 // remove every bond from the list
1067 bond *Binder = NULL;
1068 while (Leaf->last->previous != Leaf->first) {
1069 Binder = Leaf->last->previous;
1070 Binder->leftatom->UnregisterBond(Binder);
1071 Binder->rightatom->UnregisterBond(Binder);
1072 removewithoutcheck(Binder);
1073 }
1074
1075 Walker = Leaf->start;
1076 while (Walker->next != Leaf->end) {
1077 Walker = Walker->next;
1078 Father = Walker->GetTrueFather();
1079 AtomNo = Father->nr; // global id of the current walker
1080 for (BondList::const_iterator Runner = Father->ListOfBonds.begin(); Runner != Father->ListOfBonds.end(); (++Runner)) {
1081 OtherWalker = ListOfLocalAtoms[FragmentCounter][(*Runner)->GetOtherAtom(Walker->GetTrueFather())->nr]; // local copy of current bond partner of walker
1082 if (OtherWalker != NULL) {
1083 if (OtherWalker->nr > Walker->nr)
1084 Leaf->AddBond(Walker, OtherWalker, (*Runner)->BondDegree);
1085 } else {
1086 Log() << Verbose(1) << "OtherWalker = ListOfLocalAtoms[" << FragmentCounter << "][" << (*Runner)->GetOtherAtom(Walker->GetTrueFather())->nr << "] is NULL!" << endl;
1087 status = false;
1088 }
1089 }
1090 }
1091 }
1092
1093 if ((FreeList) && (ListOfLocalAtoms != NULL)) {
1094 // free the index lookup list
1095 Free(&ListOfLocalAtoms[FragmentCounter]);
1096 if (FragmentCounter == 0) // first fragments frees the initial pointer to list
1097 Free(&ListOfLocalAtoms);
1098 }
1099 Log() << Verbose(1) << "End of FillBondStructureFromReference." << endl;
1100 return status;
1101};
1102
1103/** Fills the root stack for sites to be used as root in fragmentation depending on order or adaptivity criteria
1104 * Again, as in \sa FillBondStructureFromReference steps recursively through each Leaf in this chain list of molecule's.
1105 * \param *out output stream for debugging
1106 * \param *&RootStack stack to be filled
1107 * \param *AtomMask defines true/false per global Atom::nr to mask in/out each nuclear site
1108 * \param &FragmentCounter counts through the fragments in this MoleculeLeafClass
1109 * \return true - stack is non-empty, fragmentation necessary, false - stack is empty, no more sites to update
1110 */
1111bool MoleculeLeafClass::FillRootStackForSubgraphs(KeyStack *&RootStack, bool *AtomMask, int &FragmentCounter)
1112{
1113 atom *Walker = NULL, *Father = NULL;
1114
1115 if (RootStack != NULL) {
1116 // find first root candidates
1117 if (&(RootStack[FragmentCounter]) != NULL) {
1118 RootStack[FragmentCounter].clear();
1119 Walker = Leaf->start;
1120 while (Walker->next != Leaf->end) { // go through all (non-hydrogen) atoms
1121 Walker = Walker->next;
1122 Father = Walker->GetTrueFather();
1123 if (AtomMask[Father->nr]) // apply mask
1124#ifdef ADDHYDROGEN
1125 if (Walker->type->Z != 1) // skip hydrogen
1126#endif
1127 RootStack[FragmentCounter].push_front(Walker->nr);
1128 }
1129 if (next != NULL)
1130 next->FillRootStackForSubgraphs(RootStack, AtomMask, ++FragmentCounter);
1131 } else {
1132 Log() << Verbose(1) << "Rootstack[" << FragmentCounter << "] is NULL." << endl;
1133 return false;
1134 }
1135 FragmentCounter--;
1136 return true;
1137 } else {
1138 Log() << Verbose(1) << "Rootstack is NULL." << endl;
1139 return false;
1140 }
1141};
1142
1143/** Fills a lookup list of father's Atom::nr -> atom for each subgraph.
1144 * \param *out output stream from debugging
1145 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
1146 * \param FragmentCounter counts the fragments as we move along the list
1147 * \param GlobalAtomCount number of atoms in the complete molecule
1148 * \param &FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
1149 * \return true - success, false - failure
1150 */
1151bool MoleculeLeafClass::FillListOfLocalAtoms(atom ***&ListOfLocalAtoms, const int FragmentCounter, const int GlobalAtomCount, bool &FreeList)
1152{
1153 bool status = true;
1154
1155 if (ListOfLocalAtoms == NULL) { // allocated initial pointer
1156 // allocate and set each field to NULL
1157 const int Counter = Count();
1158 ListOfLocalAtoms = Calloc<atom**>(Counter, "MoleculeLeafClass::FillListOfLocalAtoms - ***ListOfLocalAtoms");
1159 if (ListOfLocalAtoms == NULL) {
1160 FreeList = FreeList && false;
1161 status = false;
1162 }
1163 }
1164
1165 if ((ListOfLocalAtoms != NULL) && (ListOfLocalAtoms[FragmentCounter] == NULL)) { // allocate and fill list of this fragment/subgraph
1166 status = status && CreateFatherLookupTable(Leaf->start, Leaf->end, ListOfLocalAtoms[FragmentCounter], GlobalAtomCount);
1167 FreeList = FreeList && true;
1168 }
1169
1170 return status;
1171};
1172
1173/** The indices per keyset are compared to the respective father's Atom::nr in each subgraph and thus put into \a **&FragmentList.
1174 * \param *out output stream fro debugging
1175 * \param *reference reference molecule with the bond structure to be copied
1176 * \param *KeySetList list with all keysets
1177 * \param ***ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
1178 * \param **&FragmentList list to be allocated and returned
1179 * \param &FragmentCounter counts the fragments as we move along the list
1180 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
1181 * \retuen true - success, false - failure
1182 */
1183bool MoleculeLeafClass::AssignKeySetsToFragment(molecule *reference, Graph *KeySetList, atom ***&ListOfLocalAtoms, Graph **&FragmentList, int &FragmentCounter, bool FreeList)
1184{
1185 bool status = true;
1186 int KeySetCounter = 0;
1187
1188 Log() << Verbose(1) << "Begin of AssignKeySetsToFragment." << endl;
1189 // fill ListOfLocalAtoms if NULL was given
1190 if (!FillListOfLocalAtoms(ListOfLocalAtoms, FragmentCounter, reference->AtomCount, FreeList)) {
1191 Log() << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl;
1192 return false;
1193 }
1194
1195 // allocate fragment list
1196 if (FragmentList == NULL) {
1197 KeySetCounter = Count();
1198 FragmentList = Calloc<Graph*>(KeySetCounter, "MoleculeLeafClass::AssignKeySetsToFragment - **FragmentList");
1199 KeySetCounter = 0;
1200 }
1201
1202 if ((KeySetList != NULL) && (KeySetList->size() != 0)) { // if there are some scanned keysets at all
1203 // assign scanned keysets
1204 if (FragmentList[FragmentCounter] == NULL)
1205 FragmentList[FragmentCounter] = new Graph;
1206 KeySet *TempSet = new KeySet;
1207 for (Graph::iterator runner = KeySetList->begin(); runner != KeySetList->end(); runner++) { // key sets contain global numbers!
1208 if (ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*((*runner).first.begin()))->nr] != NULL) {// as we may assume that that bond structure is unchanged, we only test the first key in each set
1209 // translate keyset to local numbers
1210 for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
1211 TempSet->insert(ListOfLocalAtoms[FragmentCounter][reference->FindAtom(*sprinter)->nr]->nr);
1212 // insert into FragmentList
1213 FragmentList[FragmentCounter]->insert(GraphPair(*TempSet, pair<int, double> (KeySetCounter++, (*runner).second.second)));
1214 }
1215 TempSet->clear();
1216 }
1217 delete (TempSet);
1218 if (KeySetCounter == 0) {// if there are no keysets, delete the list
1219 Log() << Verbose(1) << "KeySetCounter is zero, deleting FragmentList." << endl;
1220 delete (FragmentList[FragmentCounter]);
1221 } else
1222 Log() << Verbose(1) << KeySetCounter << " keysets were assigned to subgraph " << FragmentCounter << "." << endl;
1223 FragmentCounter++;
1224 if (next != NULL)
1225 next->AssignKeySetsToFragment(reference, KeySetList, ListOfLocalAtoms, FragmentList, FragmentCounter, FreeList);
1226 FragmentCounter--;
1227 } else
1228 Log() << Verbose(1) << "KeySetList is NULL or empty." << endl;
1229
1230 if ((FreeList) && (ListOfLocalAtoms != NULL)) {
1231 // free the index lookup list
1232 Free(&ListOfLocalAtoms[FragmentCounter]);
1233 if (FragmentCounter == 0) // first fragments frees the initial pointer to list
1234 Free(&ListOfLocalAtoms);
1235 }
1236 Log() << Verbose(1) << "End of AssignKeySetsToFragment." << endl;
1237 return status;
1238};
1239
1240/** Translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
1241 * \param *out output stream for debugging
1242 * \param **FragmentList Graph with local numbers per fragment
1243 * \param &FragmentCounter counts the fragments as we move along the list
1244 * \param &TotalNumberOfKeySets global key set counter
1245 * \param &TotalGraph Graph to be filled with global numbers
1246 */
1247void MoleculeLeafClass::TranslateIndicesToGlobalIDs(Graph **FragmentList, int &FragmentCounter, int &TotalNumberOfKeySets, Graph &TotalGraph)
1248{
1249 Log() << Verbose(1) << "Begin of TranslateIndicesToGlobalIDs." << endl;
1250 KeySet *TempSet = new KeySet;
1251 if (FragmentList[FragmentCounter] != NULL) {
1252 for (Graph::iterator runner = FragmentList[FragmentCounter]->begin(); runner != FragmentList[FragmentCounter]->end(); runner++) {
1253 for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
1254 TempSet->insert((Leaf->FindAtom(*sprinter))->GetTrueFather()->nr);
1255 TotalGraph.insert(GraphPair(*TempSet, pair<int, double> (TotalNumberOfKeySets++, (*runner).second.second)));
1256 TempSet->clear();
1257 }
1258 delete (TempSet);
1259 } else {
1260 Log() << Verbose(1) << "FragmentList is NULL." << endl;
1261 }
1262 if (next != NULL)
1263 next->TranslateIndicesToGlobalIDs(FragmentList, ++FragmentCounter, TotalNumberOfKeySets, TotalGraph);
1264 FragmentCounter--;
1265 Log() << Verbose(1) << "End of TranslateIndicesToGlobalIDs." << endl;
1266};
1267
1268/** Simply counts the number of items in the list, from given MoleculeLeafClass.
1269 * \return number of items
1270 */
1271int MoleculeLeafClass::Count() const
1272{
1273 if (next != NULL)
1274 return next->Count() + 1;
1275 else
1276 return 1;
1277};
1278
Note: See TracBrowser for help on using the repository browser.