source: src/moleculelist.cpp@ f2bb0f

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 f2bb0f was 9879f6, checked in by Frederik Heber <heber@…>, 15 years ago

Huge Refactoring due to class molecule now being an STL container.

  • molecule::start and molecule::end were dropped. Hence, the usual construct Walker = start while (Walker->next != end) {

Walker = walker->next
...

}
was changed to
for (molecule::iterator iter = begin(); iter != end(); ++iter) {

...

}
and (*iter) used instead of Walker.

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