source: src/moleculelist.cpp@ 920c70

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

Removed all Malloc/Calloc/ReAlloc (&Free) and replaced by new and delete/delete[].

Due to the new MemDebug framework there is no need (or even unnecessary/unwanted competition between it and) for the MemoryAllocator and ..UsageObserver anymore.
They can however still be used with c codes such as pcp and alikes.

In Molecuilder lots of glibc corruptions arose and the C-like syntax make it generally harder to get allocation and deallocation straight.

Signed-off-by: Frederik Heber <heber@…>

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