source: src/moleculelist.cpp@ 36eb4e

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 36eb4e was 568be7, checked in by Frederik Heber <heber@…>, 16 years ago

Added config::SavePDB() and config::SaveMPQC().

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