source: src/moleculelist.cpp@ 6cd16b

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

Huge change: Log() << Verbose(.) --> DoLog(.) && (Log() << Verbose(.) << ...);

Most of the files are affected, but this is necessary as if DoLog() says verbosity is not enough, all the stream operators won"t get executed which saves substantial amount of computation time.

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

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