source: src/moleculelist.cpp@ ea7176

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

FIX: Made AtomCount a Cacheable so that the number of atoms in a molecule will always be correct

All unittests working.
All Complete testcases fail.

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