source: src/moleculelist.cpp@ 906822

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

FIX: Atoms were stored not in the sequence they were loaded.

  1. The main problem is molecule::atomSet which is a set<atom *>, i.e. atoms are sorted by their appearance in memory. As memory need not be allocated sequentially, this gives rise to extreme arbitririty which is not desired. Instead the atoms should be stored in the sequence they were loaded/created. The solution is as follows:
  • config::SaveAll()
  • molecule::atomSet is now a list<atom *>
  • molecule::atomIds is a new set<atomId_t> (atomIdSet) which controls that (global) ids remain unique in the no more Atomset's set (but list)
  • molecule::erase() erases also in atomIds
  • molecule::insert() checks whether id is present by atomIds
  • molecule::find() as std::list does not have a find, we just go through the list until the object is found (or not), this may be speeded up by another internal list.
  • molecule::InternalPointer made lots of confusion as virtual function GoToFirst() is const, hence begin() (needed therein) returns const_iterator, which then cannot be simply re-cast into an iterator: We make it a pointer, reinterpret_cast the pointer and reference it back. Although InternalPointer is mutable, the compiler cannot use the non-const function begin() (it cannot be made const, as overloading is not allowed). (this is noted in the code also extensively.)
  • molecule::containsAtom() does not use count but the new find, as it returns only boolean anyway.
  • rewrote MoleculeListClass::SimpleMerge() to get rid of the extra iterator, as we remove all atoms in the end anyway.
  • FIX: MoleculeListClass::SimpleMultiMerge() - the created mol was not inserted into the moleculelist in the end, although it is the only one to remain.
  1. All other databases had missing headers with respect to those stored in elements_db.cpp. Hence, valence of hydrogen was not parsed and this caused several failures in CalculateOrbitals() (Psi numbers and MaxMinSetp in pcp conf file).
  1. Subsequenytly, various test cases (12, 21, 30, 31, 36-38, 39) were broken. This had two reasons:
  • Seemingly, CalculateOrbitals() was broken before hence MaxMinStep (pcp config) and MaxPsiDouble/PsiMaxNn[Up|Down] were always 0. (10-21,30-31,39)
  • As the order is now correct, fixes from commits c9217161ec2a5d5db508557fe98a32068461f45b and 22a6da8380911571debebd69444d2615450bbbd8 were obselete and have been reverted (order of the Ion?_Type...): Molecules/6 (30), Molecules/7 (31), Filling/1 (39)
  • Due to different ordering, Tesselation/3 (38) had completely different .dat file (though same tesselation)
  • r3d had small differences, mostly order or epsilon (0 not being 0 but ..-e16), hence diffing was deactivated, as r3d is deprecated anyway (since vmd can render triangles as well and better).

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

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