source: src/moleculelist.cpp@ cb2146

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 cb2146 was 24a5e0, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Added -Wall flag and fixed several small hickups

  • Property mode set to 100755
File size: 46.7 KB
Line 
1/** \file MoleculeListClass.cpp
2 *
3 * Function implementations for the class MoleculeListClass.
4 *
5 */
6
7#include <cstring>
8
9#include "World.hpp"
10#include "atom.hpp"
11#include "bond.hpp"
12#include "boundary.hpp"
13#include "config.hpp"
14#include "element.hpp"
15#include "helpers.hpp"
16#include "linkedcell.hpp"
17#include "lists.hpp"
18#include "log.hpp"
19#include "molecule.hpp"
20#include "memoryallocator.hpp"
21#include "periodentafel.hpp"
22
23/*********************************** Functions for class MoleculeListClass *************************/
24
25/** Constructor for MoleculeListClass.
26 */
27MoleculeListClass::MoleculeListClass(World *_world) :
28 world(_world)
29{
30 // empty lists
31 ListOfMolecules.clear();
32 MaxIndex = 1;
33};
34
35/** Destructor for MoleculeListClass.
36 */
37MoleculeListClass::~MoleculeListClass()
38{
39 Log() << Verbose(3) << this << ": Freeing ListOfMolcules." << endl;
40 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
41 Log() << Verbose(4) << "ListOfMolecules: Freeing " << *ListRunner << "." << endl;
42 world->destroyMolecule(*ListRunner);
43 }
44 Log() << Verbose(4) << "Freeing ListOfMolecules." << endl;
45 ListOfMolecules.clear(); // empty list
46};
47
48/** Insert a new molecule into the list and set its number.
49 * \param *mol molecule to add to list.
50 * \return true - add successful
51 */
52void MoleculeListClass::insert(molecule *mol)
53{
54 OBSERVE;
55 mol->IndexNr = MaxIndex++;
56 ListOfMolecules.push_back(mol);
57 mol->signOn(this);
58};
59
60/** Compare whether two molecules are equal.
61 * \param *a molecule one
62 * \param *n molecule two
63 * \return lexical value (-1, 0, +1)
64 */
65int MolCompare(const void *a, const void *b)
66{
67 int *aList = NULL, *bList = NULL;
68 int Count, Counter, aCounter, bCounter;
69 int flag;
70 atom *aWalker = NULL;
71 atom *bWalker = NULL;
72
73 // sort each atom list and put the numbers into a list, then go through
74 //Log() << Verbose(0) << "Comparing fragment no. " << *(molecule **)a << " to " << *(molecule **)b << "." << endl;
75 if ((**(molecule **) a).AtomCount < (**(molecule **) b).AtomCount) {
76 return -1;
77 } else {
78 if ((**(molecule **) a).AtomCount > (**(molecule **) b).AtomCount)
79 return +1;
80 else {
81 Count = (**(molecule **) a).AtomCount;
82 aList = new int[Count];
83 bList = new int[Count];
84
85 // fill the lists
86 aWalker = (**(molecule **) a).start;
87 bWalker = (**(molecule **) b).start;
88 Counter = 0;
89 aCounter = 0;
90 bCounter = 0;
91 while ((aWalker->next != (**(molecule **) a).end) && (bWalker->next != (**(molecule **) b).end)) {
92 aWalker = aWalker->next;
93 bWalker = bWalker->next;
94 if (aWalker->GetTrueFather() == NULL)
95 aList[Counter] = Count + (aCounter++);
96 else
97 aList[Counter] = aWalker->GetTrueFather()->nr;
98 if (bWalker->GetTrueFather() == NULL)
99 bList[Counter] = Count + (bCounter++);
100 else
101 bList[Counter] = bWalker->GetTrueFather()->nr;
102 Counter++;
103 }
104 // check if AtomCount was for real
105 flag = 0;
106 if ((aWalker->next == (**(molecule **) a).end) && (bWalker->next != (**(molecule **) b).end)) {
107 flag = -1;
108 } else {
109 if ((aWalker->next != (**(molecule **) a).end) && (bWalker->next == (**(molecule **) b).end))
110 flag = 1;
111 }
112 if (flag == 0) {
113 // sort the lists
114 gsl_heapsort(aList, Count, sizeof(int), CompareDoubles);
115 gsl_heapsort(bList, Count, sizeof(int), CompareDoubles);
116 // compare the lists
117
118 flag = 0;
119 for (int i = 0; i < Count; i++) {
120 if (aList[i] < bList[i]) {
121 flag = -1;
122 } else {
123 if (aList[i] > bList[i])
124 flag = 1;
125 }
126 if (flag != 0)
127 break;
128 }
129 }
130 delete[] (aList);
131 delete[] (bList);
132 return flag;
133 }
134 }
135 return -1;
136};
137
138/** Output of a list of all molecules.
139 * \param *out output stream
140 */
141void MoleculeListClass::Enumerate(ostream *out)
142{
143 element* Elemental = NULL;
144 atom *Walker = NULL;
145 int Counts[MAX_ELEMENTS];
146 double size=0;
147 Vector Origin;
148
149 // header
150 (*out) << "Index\tName\t\tAtoms\tFormula\tCenter\tSize" << endl;
151 (*out) << "-----------------------------------------------" << endl;
152 if (ListOfMolecules.size() == 0)
153 (*out) << "\tNone" << endl;
154 else {
155 Origin.Zero();
156 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
157 // reset element counts
158 for (int j = 0; j<MAX_ELEMENTS;j++)
159 Counts[j] = 0;
160 // count atoms per element and determine size of bounding sphere
161 size=0.;
162 Walker = (*ListRunner)->start;
163 while (Walker->next != (*ListRunner)->end) {
164 Walker = Walker->next;
165 Counts[Walker->type->Z]++;
166 if (Walker->x.DistanceSquared(&Origin) > size)
167 size = Walker->x.DistanceSquared(&Origin);
168 }
169 // output Index, Name, number of atoms, chemical formula
170 (*out) << ((*ListRunner)->ActiveFlag ? "*" : " ") << (*ListRunner)->IndexNr << "\t" << (*ListRunner)->name << "\t\t" << (*ListRunner)->AtomCount << "\t";
171 Elemental = (*ListRunner)->elemente->end;
172 while(Elemental->previous != (*ListRunner)->elemente->start) {
173 Elemental = Elemental->previous;
174 if (Counts[Elemental->Z] != 0)
175 (*out) << Elemental->symbol << Counts[Elemental->Z];
176 }
177 // Center and size
178 (*out) << "\t" << (*ListRunner)->Center << "\t" << sqrt(size) << endl;
179 }
180 }
181};
182
183/** Returns the molecule with the given index \a index.
184 * \param index index of the desired molecule
185 * \return pointer to molecule structure, NULL if not found
186 */
187molecule * MoleculeListClass::ReturnIndex(int index)
188{
189 for(MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
190 if ((*ListRunner)->IndexNr == index)
191 return (*ListRunner);
192 return NULL;
193};
194
195/** Simple merge of two molecules into one.
196 * \param *mol destination molecule
197 * \param *srcmol source molecule
198 * \return true - merge successful, false - merge failed (probably due to non-existant indices
199 */
200bool MoleculeListClass::SimpleMerge(molecule *mol, molecule *srcmol)
201{
202 if (srcmol == NULL)
203 return false;
204
205 // put all molecules of src into mol
206 atom *Walker = srcmol->start;
207 atom *NextAtom = Walker->next;
208 while (NextAtom != srcmol->end) {
209 Walker = NextAtom;
210 NextAtom = Walker->next;
211 srcmol->UnlinkAtom(Walker);
212 mol->AddAtom(Walker);
213 }
214
215 // remove src
216 ListOfMolecules.remove(srcmol);
217 World::get()->destroyMolecule(srcmol);
218 return true;
219};
220
221/** Simple add of one molecules into another.
222 * \param *mol destination molecule
223 * \param *srcmol source molecule
224 * \return true - merge successful, false - merge failed (probably due to non-existant indices
225 */
226bool MoleculeListClass::SimpleAdd(molecule *mol, molecule *srcmol)
227{
228 if (srcmol == NULL)
229 return false;
230
231 // put all molecules of src into mol
232 atom *Walker = srcmol->start;
233 atom *NextAtom = Walker->next;
234 while (NextAtom != srcmol->end) {
235 Walker = NextAtom;
236 NextAtom = Walker->next;
237 Walker = mol->AddCopyAtom(Walker);
238 Walker->father = Walker;
239 }
240
241 return true;
242};
243
244/** Simple merge of a given set of molecules into one.
245 * \param *mol destination molecule
246 * \param *src index of set of source molecule
247 * \param N number of source molecules
248 * \return true - merge successful, false - some merges failed (probably due to non-existant indices)
249 */
250bool MoleculeListClass::SimpleMultiMerge(molecule *mol, int *src, int N)
251{
252 bool status = true;
253 // check presence of all source molecules
254 for (int i=0;i<N;i++) {
255 molecule *srcmol = ReturnIndex(src[i]);
256 status = status && SimpleMerge(mol, srcmol);
257 }
258 return status;
259};
260
261/** Simple add of a given set of molecules into one.
262 * \param *mol destination molecule
263 * \param *src index of set of source molecule
264 * \param N number of source molecules
265 * \return true - merge successful, false - some merges failed (probably due to non-existant indices)
266 */
267bool MoleculeListClass::SimpleMultiAdd(molecule *mol, int *src, int N)
268{
269 bool status = true;
270 // check presence of all source molecules
271 for (int i=0;i<N;i++) {
272 molecule *srcmol = ReturnIndex(src[i]);
273 status = status && SimpleAdd(mol, srcmol);
274 }
275 return status;
276};
277
278/** Scatter merge of a given set of molecules into one.
279 * Scatter merge distributes the molecules in such a manner that they don't overlap.
280 * \param *mol destination molecule
281 * \param *src index of set of source molecule
282 * \param N number of source molecules
283 * \return true - merge successful, false - merge failed (probably due to non-existant indices
284 * \TODO find scatter center for each src molecule
285 */
286bool MoleculeListClass::ScatterMerge(molecule *mol, int *src, int N)
287{
288 // check presence of all source molecules
289 for (int i=0;i<N;i++) {
290 // get pointer to src molecule
291 molecule *srcmol = ReturnIndex(src[i]);
292 if (srcmol == NULL)
293 return false;
294 }
295 // adapt each Center
296 for (int i=0;i<N;i++) {
297 // get pointer to src molecule
298 molecule *srcmol = ReturnIndex(src[i]);
299 //srcmol->Center.Zero();
300 srcmol->Translate(&srcmol->Center);
301 }
302 // perform a simple multi merge
303 SimpleMultiMerge(mol, src, N);
304 return true;
305};
306
307/** Embedding merge of a given set of molecules into one.
308 * Embedding merge inserts one molecule into the other.
309 * \param *mol destination molecule (fixed one)
310 * \param *srcmol source molecule (variable one, where atoms are taken from)
311 * \return true - merge successful, false - merge failed (probably due to non-existant indices)
312 * \TODO linked cell dimensions for boundary points has to be as big as inner diameter!
313 */
314bool MoleculeListClass::EmbedMerge(molecule *mol, molecule *srcmol)
315{
316 LinkedCell *LCList = NULL;
317 Tesselation *TesselStruct = NULL;
318 if ((srcmol == NULL) || (mol == NULL)) {
319 eLog() << Verbose(1) << "Either fixed or variable molecule is given as NULL." << endl;
320 return false;
321 }
322
323 // calculate envelope for *mol
324 LCList = new LinkedCell(mol, 8.);
325 FindNonConvexBorder(mol, TesselStruct, (const LinkedCell *&)LCList, 4., NULL);
326 if (TesselStruct == NULL) {
327 eLog() << Verbose(1) << "Could not tesselate the fixed molecule." << endl;
328 return false;
329 }
330 delete(LCList);
331 LCList = new LinkedCell(TesselStruct, 8.); // re-create with boundary points only!
332
333 // prepare index list for bonds
334 srcmol->CountAtoms();
335 atom ** CopyAtoms = new atom*[srcmol->AtomCount];
336 for(int i=0;i<srcmol->AtomCount;i++)
337 CopyAtoms[i] = NULL;
338
339 // for each of the source atoms check whether we are in- or outside and add copy atom
340 atom *Walker = srcmol->start;
341 int nr=0;
342 while (Walker->next != srcmol->end) {
343 Walker = Walker->next;
344 Log() << Verbose(2) << "INFO: Current Walker is " << *Walker << "." << endl;
345 if (!TesselStruct->IsInnerPoint(Walker->x, LCList)) {
346 CopyAtoms[Walker->nr] = Walker->clone();
347 mol->AddAtom(CopyAtoms[Walker->nr]);
348 nr++;
349 } else {
350 // do nothing
351 }
352 }
353 Log() << Verbose(1) << nr << " of " << srcmol->AtomCount << " atoms have been merged.";
354
355 // go through all bonds and add as well
356 bond *Binder = srcmol->first;
357 while(Binder->next != srcmol->last) {
358 Binder = Binder->next;
359 Log() << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
360 mol->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
361 }
362 delete(LCList);
363 return true;
364};
365
366/** Simple output of the pointers in ListOfMolecules.
367 * \param *out output stream
368 */
369void MoleculeListClass::Output(ofstream *out)
370{
371 Log() << Verbose(1) << "MoleculeList: ";
372 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
373 Log() << Verbose(0) << *ListRunner << "\t";
374 Log() << Verbose(0) << endl;
375};
376
377/** Calculates necessary hydrogen correction due to unwanted interaction between saturated ones.
378 * If for a pair of two hydrogen atoms a and b, at least is a saturated one, and a and b are not
379 * bonded to the same atom, then we add for this pair a correction term constructed from a Morse
380 * potential function fit to QM calculations with respecting to the interatomic hydrogen distance.
381 * \param *out output stream for debugging
382 * \param *path path to file
383 */
384bool MoleculeListClass::AddHydrogenCorrection(char *path)
385{
386 atom *Walker = NULL;
387 atom *Runner = NULL;
388 bond *Binder = NULL;
389 double ***FitConstant = NULL, **correction = NULL;
390 int a, b;
391 ofstream output;
392 ifstream input;
393 string line;
394 stringstream zeile;
395 double distance;
396 char ParsedLine[1023];
397 double tmp;
398 char *FragmentNumber = NULL;
399
400 Log() << Verbose(1) << "Saving hydrogen saturation correction ... ";
401 // 0. parse in fit constant files that should have the same dimension as the final energy files
402 // 0a. find dimension of matrices with constants
403 line = path;
404 line.append("/");
405 line += FRAGMENTPREFIX;
406 line += "1";
407 line += FITCONSTANTSUFFIX;
408 input.open(line.c_str());
409 if (input == NULL) {
410 Log() << Verbose(1) << endl << "Unable to open " << line << ", is the directory correct?" << endl;
411 return false;
412 }
413 a = 0;
414 b = -1; // we overcount by one
415 while (!input.eof()) {
416 input.getline(ParsedLine, 1023);
417 zeile.str(ParsedLine);
418 int i = 0;
419 while (!zeile.eof()) {
420 zeile >> distance;
421 i++;
422 }
423 if (i > a)
424 a = i;
425 b++;
426 }
427 Log() << Verbose(0) << "I recognized " << a << " columns and " << b << " rows, ";
428 input.close();
429
430 // 0b. allocate memory for constants
431 FitConstant = Calloc<double**>(3, "MoleculeListClass::AddHydrogenCorrection: ***FitConstant");
432 for (int k = 0; k < 3; k++) {
433 FitConstant[k] = Calloc<double*>(a, "MoleculeListClass::AddHydrogenCorrection: **FitConstant[]");
434 for (int i = a; i--;) {
435 FitConstant[k][i] = Calloc<double>(b, "MoleculeListClass::AddHydrogenCorrection: *FitConstant[][]");
436 }
437 }
438 // 0c. parse in constants
439 for (int i = 0; i < 3; i++) {
440 line = path;
441 line.append("/");
442 line += FRAGMENTPREFIX;
443 sprintf(ParsedLine, "%d", i + 1);
444 line += ParsedLine;
445 line += FITCONSTANTSUFFIX;
446 input.open(line.c_str());
447 if (input == NULL) {
448 eLog() << Verbose(0) << endl << "Unable to open " << line << ", is the directory correct?" << endl;
449 performCriticalExit();
450 return false;
451 }
452 int k = 0, l;
453 while ((!input.eof()) && (k < b)) {
454 input.getline(ParsedLine, 1023);
455 //Log() << Verbose(0) << "Current Line: " << ParsedLine << endl;
456 zeile.str(ParsedLine);
457 zeile.clear();
458 l = 0;
459 while ((!zeile.eof()) && (l < a)) {
460 zeile >> FitConstant[i][l][k];
461 //Log() << Verbose(0) << FitConstant[i][l][k] << "\t";
462 l++;
463 }
464 //Log() << Verbose(0) << endl;
465 k++;
466 }
467 input.close();
468 }
469 for (int k = 0; k < 3; k++) {
470 Log() << Verbose(0) << "Constants " << k << ":" << endl;
471 for (int j = 0; j < b; j++) {
472 for (int i = 0; i < a; i++) {
473 Log() << Verbose(0) << FitConstant[k][i][j] << "\t";
474 }
475 Log() << Verbose(0) << endl;
476 }
477 Log() << Verbose(0) << endl;
478 }
479
480 // 0d. allocate final correction matrix
481 correction = Calloc<double*>(a, "MoleculeListClass::AddHydrogenCorrection: **correction");
482 for (int i = a; i--;)
483 correction[i] = Calloc<double>(b, "MoleculeListClass::AddHydrogenCorrection: *correction[]");
484
485 // 1a. go through every molecule in the list
486 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
487 // 1b. zero final correction matrix
488 for (int k = a; k--;)
489 for (int j = b; j--;)
490 correction[k][j] = 0.;
491 // 2. take every hydrogen that is a saturated one
492 Walker = (*ListRunner)->start;
493 while (Walker->next != (*ListRunner)->end) {
494 Walker = Walker->next;
495 //Log() << Verbose(1) << "Walker: " << *Walker << " with first bond " << *(Walker->ListOfBonds.begin()) << "." << endl;
496 if ((Walker->type->Z == 1) && ((Walker->father == NULL)
497 || (Walker->father->type->Z != 1))) { // if it's a hydrogen
498 Runner = (*ListRunner)->start;
499 while (Runner->next != (*ListRunner)->end) {
500 Runner = Runner->next;
501 //Log() << Verbose(2) << "Runner: " << *Runner << " with first bond " << *(Walker->ListOfBonds.begin()) << "." << endl;
502 // 3. take every other hydrogen that is the not the first and not bound to same bonding partner
503 Binder = *(Runner->ListOfBonds.begin());
504 if ((Runner->type->Z == 1) && (Runner->nr > Walker->nr) && (Binder->GetOtherAtom(Runner) != Binder->GetOtherAtom(Walker))) { // (hydrogens have only one bonding partner!)
505 // 4. evaluate the morse potential for each matrix component and add up
506 distance = Runner->x.Distance(&Walker->x);
507 //Log() << Verbose(0) << "Fragment " << (*ListRunner)->name << ": " << *Runner << "<= " << distance << "=>" << *Walker << ":" << endl;
508 for (int k = 0; k < a; k++) {
509 for (int j = 0; j < b; j++) {
510 switch (k) {
511 case 1:
512 case 7:
513 case 11:
514 tmp = pow(FitConstant[0][k][j] * (1. - exp(-FitConstant[1][k][j] * (distance - FitConstant[2][k][j]))), 2);
515 break;
516 default:
517 tmp = FitConstant[0][k][j] * pow(distance, FitConstant[1][k][j]) + FitConstant[2][k][j];
518 };
519 correction[k][j] -= tmp; // ground state is actually lower (disturbed by additional interaction)
520 //Log() << Verbose(0) << tmp << "\t";
521 }
522 //Log() << Verbose(0) << endl;
523 }
524 //Log() << Verbose(0) << endl;
525 }
526 }
527 }
528 }
529 // 5. write final matrix to file
530 line = path;
531 line.append("/");
532 line += FRAGMENTPREFIX;
533 FragmentNumber = FixedDigitNumber(ListOfMolecules.size(), (*ListRunner)->IndexNr);
534 line += FragmentNumber;
535 delete (FragmentNumber);
536 line += HCORRECTIONSUFFIX;
537 output.open(line.c_str());
538 output << "Time\t\tTotal\t\tKinetic\t\tNonLocal\tCorrelation\tExchange\tPseudo\t\tHartree\t\t-Gauss\t\tEwald\t\tIonKin\t\tETotal" << endl;
539 for (int j = 0; j < b; j++) {
540 for (int i = 0; i < a; i++)
541 output << correction[i][j] << "\t";
542 output << endl;
543 }
544 output.close();
545 }
546 line = path;
547 line.append("/");
548 line += HCORRECTIONSUFFIX;
549 output.open(line.c_str());
550 output << "Time\t\tTotal\t\tKinetic\t\tNonLocal\tCorrelation\tExchange\tPseudo\t\tHartree\t\t-Gauss\t\tEwald\t\tIonKin\t\tETotal" << endl;
551 for (int j = 0; j < b; j++) {
552 for (int i = 0; i < a; i++)
553 output << 0 << "\t";
554 output << endl;
555 }
556 output.close();
557 // 6. free memory of parsed matrices
558 for (int k = 0; k < 3; k++) {
559 for (int i = a; i--;) {
560 Free(&FitConstant[k][i]);
561 }
562 Free(&FitConstant[k]);
563 }
564 Free(&FitConstant);
565 Log() << Verbose(0) << "done." << endl;
566 return true;
567};
568
569/** Store force indices, i.e. the connection between the nuclear index in the total molecule config and the respective atom in fragment config.
570 * \param *out output stream for debugging
571 * \param *path path to file
572 * \param *SortIndex Index to map from the BFS labeling to the sequence how of Ion_Type in the config
573 * \return true - file written successfully, false - writing failed
574 */
575bool MoleculeListClass::StoreForcesFile(char *path,
576 int *SortIndex)
577{
578 bool status = true;
579 ofstream ForcesFile;
580 stringstream line;
581 atom *Walker = NULL;
582 element *runner = NULL;
583
584 // open file for the force factors
585 Log() << Verbose(1) << "Saving force factors ... ";
586 line << path << "/" << FRAGMENTPREFIX << FORCESFILE;
587 ForcesFile.open(line.str().c_str(), ios::out);
588 if (ForcesFile != NULL) {
589 //Log() << Verbose(1) << "Final AtomicForcesList: ";
590 //output << prefix << "Forces" << endl;
591 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
592 runner = (*ListRunner)->elemente->start;
593 while (runner->next != (*ListRunner)->elemente->end) { // go through every element
594 runner = runner->next;
595 if ((*ListRunner)->ElementsInMolecule[runner->Z]) { // if this element got atoms
596 Walker = (*ListRunner)->start;
597 while (Walker->next != (*ListRunner)->end) { // go through every atom of this element
598 Walker = Walker->next;
599 if (Walker->type->Z == runner->Z) {
600 if ((Walker->GetTrueFather() != NULL) && (Walker->GetTrueFather() != Walker)) {// if there is a rea
601 //Log() << Verbose(0) << "Walker is " << *Walker << " with true father " << *( Walker->GetTrueFather()) << ", it
602 ForcesFile << SortIndex[Walker->GetTrueFather()->nr] << "\t";
603 } else
604 // otherwise a -1 to indicate an added saturation hydrogen
605 ForcesFile << "-1\t";
606 }
607 }
608 }
609 }
610 ForcesFile << endl;
611 }
612 ForcesFile.close();
613 Log() << Verbose(1) << "done." << endl;
614 } else {
615 status = false;
616 Log() << Verbose(1) << "failed to open file " << line.str() << "." << endl;
617 }
618 ForcesFile.close();
619
620 return status;
621};
622
623/** Writes a config file for each molecule in the given \a **FragmentList.
624 * \param *out output stream for debugging
625 * \param *configuration standard configuration to attach atoms in fragment molecule to.
626 * \param *SortIndex Index to map from the BFS labeling to the sequence how of Ion_Type in the config
627 * \param DoPeriodic true - call ScanForPeriodicCorrection, false - don't
628 * \param DoCentering true - call molecule::CenterEdge(), false - don't
629 * \return true - success (each file was written), false - something went wrong.
630 */
631bool MoleculeListClass::OutputConfigForListOfFragments(config *configuration, int *SortIndex)
632{
633 ofstream outputFragment;
634 char FragmentName[MAXSTRINGSIZE];
635 char PathBackup[MAXSTRINGSIZE];
636 bool result = true;
637 bool intermediateResult = true;
638 atom *Walker = NULL;
639 Vector BoxDimension;
640 char *FragmentNumber = NULL;
641 char *path = NULL;
642 int FragmentCounter = 0;
643 ofstream output;
644
645 // store the fragments as config and as xyz
646 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++) {
647 // save default path as it is changed for each fragment
648 path = configuration->GetDefaultPath();
649 if (path != NULL)
650 strcpy(PathBackup, path);
651 else {
652 eLog() << Verbose(0) << "OutputConfigForListOfFragments: NULL default path obtained from config!" << endl;
653 performCriticalExit();
654 }
655
656 // correct periodic
657 (*ListRunner)->ScanForPeriodicCorrection();
658
659 // output xyz file
660 FragmentNumber = FixedDigitNumber(ListOfMolecules.size(), FragmentCounter++);
661 sprintf(FragmentName, "%s/%s%s.conf.xyz", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
662 outputFragment.open(FragmentName, ios::out);
663 Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as XYZ ...";
664 if ((intermediateResult = (*ListRunner)->OutputXYZ(&outputFragment)))
665 Log() << Verbose(0) << " done." << endl;
666 else
667 Log() << Verbose(0) << " failed." << endl;
668 result = result && intermediateResult;
669 outputFragment.close();
670 outputFragment.clear();
671
672 // list atoms in fragment for debugging
673 Log() << Verbose(2) << "Contained atoms: ";
674 Walker = (*ListRunner)->start;
675 while (Walker->next != (*ListRunner)->end) {
676 Walker = Walker->next;
677 Log() << Verbose(0) << Walker->Name << " ";
678 }
679 Log() << Verbose(0) << endl;
680
681 // center on edge
682 (*ListRunner)->CenterEdge(&BoxDimension);
683 (*ListRunner)->SetBoxDimension(&BoxDimension); // update Box of atoms by boundary
684 int j = -1;
685 for (int k = 0; k < NDIM; k++) {
686 j += k + 1;
687 BoxDimension.x[k] = 2.5 * (configuration->GetIsAngstroem() ? 1. : 1. / AtomicLengthToAngstroem);
688 (*ListRunner)->cell_size[j] += BoxDimension.x[k] * 2.;
689 }
690 (*ListRunner)->Translate(&BoxDimension);
691
692 // also calculate necessary orbitals
693 (*ListRunner)->CountElements(); // this is a bugfix, atoms should shoulds actually be added correctly to this fragment
694 (*ListRunner)->CalculateOrbitals(*configuration);
695
696 // change path in config
697 //strcpy(PathBackup, configuration->configpath);
698 sprintf(FragmentName, "%s/%s%s/", PathBackup, FRAGMENTPREFIX, FragmentNumber);
699 configuration->SetDefaultPath(FragmentName);
700
701 // and save as config
702 sprintf(FragmentName, "%s/%s%s.conf", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
703 Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as config ...";
704 if ((intermediateResult = configuration->Save(FragmentName, (*ListRunner)->elemente, (*ListRunner))))
705 Log() << Verbose(0) << " done." << endl;
706 else
707 Log() << Verbose(0) << " failed." << endl;
708 result = result && intermediateResult;
709
710 // restore old config
711 configuration->SetDefaultPath(PathBackup);
712
713 // and save as mpqc input file
714 sprintf(FragmentName, "%s/%s%s.conf", configuration->configpath, FRAGMENTPREFIX, FragmentNumber);
715 Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as mpqc input ...";
716 if ((intermediateResult = configuration->SaveMPQC(FragmentName, (*ListRunner))))
717 Log() << Verbose(2) << " done." << endl;
718 else
719 Log() << Verbose(0) << " failed." << endl;
720
721 result = result && intermediateResult;
722 //outputFragment.close();
723 //outputFragment.clear();
724 Free(&FragmentNumber);
725 }
726 Log() << Verbose(0) << " done." << endl;
727
728 // printing final number
729 Log() << Verbose(2) << "Final number of fragments: " << FragmentCounter << "." << endl;
730
731 return result;
732};
733
734/** Counts the number of molecules with the molecule::ActiveFlag set.
735 * \return number of molecules with ActiveFlag set to true.
736 */
737int MoleculeListClass::NumberOfActiveMolecules()
738{
739 int count = 0;
740 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
741 count += ((*ListRunner)->ActiveFlag ? 1 : 0);
742 return count;
743};
744
745/** Dissects given \a *mol into connected subgraphs and inserts them as new molecules but with old atoms into \a this.
746 * \param *out output stream for debugging
747 * \param *periode periodentafel
748 * \param *configuration config with BondGraph
749 */
750void MoleculeListClass::DissectMoleculeIntoConnectedSubgraphs(const periodentafel * const periode, config * const configuration)
751{
752 molecule *mol = World::get()->createMolecule();
753 atom *Walker = NULL;
754 atom *Advancer = NULL;
755 bond *Binder = NULL;
756 bond *Stepper = NULL;
757 // 0. gather all atoms into single molecule
758 for (MoleculeList::iterator MolRunner = ListOfMolecules.begin(); !ListOfMolecules.empty(); MolRunner = ListOfMolecules.begin()) {
759 // shift all atoms to new molecule
760 Advancer = (*MolRunner)->start->next;
761 while (Advancer != (*MolRunner)->end) {
762 Walker = Advancer;
763 Advancer = Advancer->next;
764 Log() << Verbose(3) << "Re-linking " << *Walker << "..." << endl;
765 unlink(Walker);
766 Walker->father = Walker;
767 mol->AddAtom(Walker); // counting starts at 1
768 }
769 // remove all bonds
770 Stepper = (*MolRunner)->first->next;
771 while (Stepper != (*MolRunner)->last) {
772 Binder = Stepper;
773 Stepper = Stepper->next;
774 delete(Binder);
775 }
776 // remove the molecule
777 World::get()->destroyMolecule(*MolRunner);
778 ListOfMolecules.erase(MolRunner);
779 }
780
781 // 1. dissect the molecule into connected subgraphs
782 configuration->BG->ConstructBondGraph(mol);
783
784 // 2. scan for connected subgraphs
785 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
786 class StackClass<bond *> *BackEdgeStack = NULL;
787 Subgraphs = mol->DepthFirstSearchAnalysis(BackEdgeStack);
788 delete(BackEdgeStack);
789
790 // 3. dissect (the following construct is needed to have the atoms not in the order of the DFS, but in
791 // the original one as parsed in)
792 // TODO: Optimize this, when molecules just contain pointer list of global atoms!
793
794 // 4a. create array of molecules to fill
795 const int MolCount = Subgraphs->next->Count();
796 char number[MAXSTRINGSIZE];
797 molecule **molecules = Malloc<molecule *>(MolCount, "config::Load() - **molecules");
798 for (int i=0;i<MolCount;i++) {
799 molecules[i] = World::get()->createMolecule();
800 molecules[i]->ActiveFlag = true;
801 strncpy(molecules[i]->name, mol->name, MAXSTRINGSIZE);
802 if (MolCount > 1) {
803 sprintf(number, "-%d", i+1);
804 strncat(molecules[i]->name, number, MAXSTRINGSIZE - strlen(mol->name) - 1);
805 }
806 cout << "MolName is " << molecules[i]->name << endl;
807 insert(molecules[i]);
808 }
809
810 // 4b. create and fill map of which atom is associated to which connected molecule (note, counting starts at 1)
811 int FragmentCounter = 0;
812 int *MolMap = Calloc<int>(mol->AtomCount, "config::Load() - *MolMap");
813 MoleculeLeafClass *MolecularWalker = Subgraphs;
814 Walker = NULL;
815 while (MolecularWalker->next != NULL) {
816 MolecularWalker = MolecularWalker->next;
817 Walker = MolecularWalker->Leaf->start;
818 while (Walker->next != MolecularWalker->Leaf->end) {
819 Walker = Walker->next;
820 MolMap[Walker->GetTrueFather()->nr] = FragmentCounter+1;
821 }
822 FragmentCounter++;
823 }
824
825 // 4c. relocate atoms to new molecules and remove from Leafs
826 Walker = NULL;
827 while (mol->start->next != mol->end) {
828 Walker = mol->start->next;
829 if ((Walker->nr <0) || (Walker->nr >= mol->AtomCount)) {
830 eLog() << Verbose(0) << "Index of atom " << *Walker << " is invalid!" << endl;
831 performCriticalExit();
832 }
833 FragmentCounter = MolMap[Walker->nr];
834 if (FragmentCounter != 0) {
835 Log() << Verbose(3) << "Re-linking " << *Walker << "..." << endl;
836 unlink(Walker);
837 molecules[FragmentCounter-1]->AddAtom(Walker); // counting starts at 1
838 } else {
839 eLog() << Verbose(0) << "Atom " << *Walker << " not associated to molecule!" << endl;
840 performCriticalExit();
841 }
842 }
843 // 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
844 Binder = mol->first;
845 while (mol->first->next != mol->last) {
846 Binder = mol->first->next;
847 Walker = Binder->leftatom;
848 unlink(Binder);
849 link(Binder,molecules[MolMap[Walker->nr]-1]->last); // counting starts at 1
850 }
851 // 4e. free Leafs
852 MolecularWalker = Subgraphs;
853 while (MolecularWalker->next != NULL) {
854 MolecularWalker = MolecularWalker->next;
855 delete(MolecularWalker->previous);
856 }
857 delete(MolecularWalker);
858 Free(&MolMap);
859 Free(&molecules);
860 Log() << Verbose(1) << "I scanned " << FragmentCounter << " molecules." << endl;
861};
862
863/** Count all atoms in each molecule.
864 * \return number of atoms in the MoleculeListClass.
865 * TODO: the inner loop should be done by some (double molecule::CountAtom()) function
866 */
867int MoleculeListClass::CountAllAtoms() const
868{
869 atom *Walker = NULL;
870 int AtomNo = 0;
871 for (MoleculeList::const_iterator MolWalker = ListOfMolecules.begin(); MolWalker != ListOfMolecules.end(); MolWalker++) {
872 Walker = (*MolWalker)->start;
873 while (Walker->next != (*MolWalker)->end) {
874 Walker = Walker->next;
875 AtomNo++;
876 }
877 }
878 return AtomNo;
879}
880
881/***********
882 * Methods Moved here from the menus
883 */
884
885void MoleculeListClass::flipChosen() {
886 int j;
887 Log() << Verbose(0) << "Enter index of molecule: ";
888 cin >> j;
889 for(MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
890 if ((*ListRunner)->IndexNr == j)
891 (*ListRunner)->ActiveFlag = !(*ListRunner)->ActiveFlag;
892}
893
894void MoleculeListClass::createNewMolecule(periodentafel *periode) {
895 OBSERVE;
896 molecule *mol = NULL;
897 mol = World::get()->createMolecule();
898 insert(mol);
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 = World::get()->createMolecule();
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 World::get()->destroyMolecule(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 World::get()->destroyMolecule(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.