source: src/moleculelist.cpp@ e30ce8

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

FIX: CorrelationToSurface() was broken.

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