source: src/moleculelist.cpp@ e05826

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 e05826 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
RevLine 
[e138de]1/** \file MoleculeListClass.cpp
2 *
3 * Function implementations for the class MoleculeListClass.
4 *
5 */
6
[49e1ae]7#include <cstring>
8
[cbc5fb]9#include "World.hpp"
[e138de]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"
[ea7176]22#include "Helpers/Assert.hpp"
[e138de]23
[920c70]24#include "Helpers/Assert.hpp"
25
[e138de]26/*********************************** Functions for class MoleculeListClass *************************/
27
28/** Constructor for MoleculeListClass.
29 */
[cbc5fb]30MoleculeListClass::MoleculeListClass(World *_world) :
31 world(_world)
[e138de]32{
33 // empty lists
34 ListOfMolecules.clear();
35 MaxIndex = 1;
36};
37
38/** Destructor for MoleculeListClass.
39 */
40MoleculeListClass::~MoleculeListClass()
41{
[bd6bfa]42 DoLog(4) && (Log() << Verbose(4) << "Clearing ListOfMolecules." << endl);
43 for(MoleculeList::iterator MolRunner = ListOfMolecules.begin(); MolRunner != ListOfMolecules.end(); ++MolRunner)
44 (*MolRunner)->signOff(this);
[e138de]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{
[2ba827]53 OBSERVE;
[e138de]54 mol->IndexNr = MaxIndex++;
55 ListOfMolecules.push_back(mol);
[520c8b]56 mol->signOn(this);
[e138de]57};
58
[bd6bfa]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
[e138de]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;
[ea7176]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()) {
[e138de]88 return -1;
89 } else {
[ea7176]90 if (mol1->getAtomCount() > mol2->getAtomCount())
[e138de]91 return +1;
92 else {
[ea7176]93 Count = mol1->getAtomCount();
[e138de]94 aList = new int[Count];
95 bList = new int[Count];
96
97 // fill the lists
98 Counter = 0;
99 aCounter = 0;
100 bCounter = 0;
[ea7176]101 molecule::const_iterator aiter = mol1->begin();
102 molecule::const_iterator biter = mol2->begin();
103 for (;(aiter != mol1->end()) && (biter != mol2->end());
[9879f6]104 ++aiter, ++biter) {
105 if ((*aiter)->GetTrueFather() == NULL)
[e138de]106 aList[Counter] = Count + (aCounter++);
107 else
[9879f6]108 aList[Counter] = (*aiter)->GetTrueFather()->nr;
109 if ((*biter)->GetTrueFather() == NULL)
[e138de]110 bList[Counter] = Count + (bCounter++);
111 else
[9879f6]112 bList[Counter] = (*biter)->GetTrueFather()->nr;
[e138de]113 Counter++;
114 }
115 // check if AtomCount was for real
116 flag = 0;
[ea7176]117 if ((aiter == mol1->end()) && (biter != mol2->end())) {
[e138de]118 flag = -1;
119 } else {
[ea7176]120 if ((aiter != mol1->end()) && (biter == mol2->end()))
[e138de]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 */
[24a5e0]152void MoleculeListClass::Enumerate(ostream *out)
[e138de]153{
[ead4e6]154 periodentafel *periode = World::getInstance().getPeriode();
155 std::map<atomicNumber_t,unsigned int> counts;
[e138de]156 double size=0;
157 Vector Origin;
158
159 // header
[835a0f]160 (*out) << "Index\tName\t\tAtoms\tFormula\tCenter\tSize" << endl;
161 (*out) << "-----------------------------------------------" << endl;
[e138de]162 if (ListOfMolecules.size() == 0)
[835a0f]163 (*out) << "\tNone" << endl;
[e138de]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.;
[9879f6]169 for (molecule::const_iterator iter = (*ListRunner)->begin(); iter != (*ListRunner)->end(); ++iter) {
[a7b761b]170 counts[(*iter)->type->getNumber()]++;
171 if ((*iter)->x.DistanceSquared(Origin) > size)
172 size = (*iter)->x.DistanceSquared(Origin);
[e138de]173 }
174 // output Index, Name, number of atoms, chemical formula
[ea7176]175 (*out) << ((*ListRunner)->ActiveFlag ? "*" : " ") << (*ListRunner)->IndexNr << "\t" << (*ListRunner)->name << "\t\t" << (*ListRunner)->getAtomCount() << "\t";
[ead4e6]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;
[e138de]181 }
182 // Center and size
[835a0f]183 (*out) << "\t" << (*ListRunner)->Center << "\t" << sqrt(size) << endl;
[e138de]184 }
185 }
186};
187
188/** Returns the molecule with the given index \a index.
189 * \param index index of the desired molecule
[1907a7]190 * \return pointer to molecule structure, NULL if not found
[e138de]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
[1907a7]203 * \return true - merge successful, false - merge failed (probably due to non-existant indices
[e138de]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
[9879f6]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));
[e138de]216 }
217
218 // remove src
219 ListOfMolecules.remove(srcmol);
[23b547]220 World::getInstance().destroyMolecule(srcmol);
[e138de]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
[9879f6]235 atom *Walker = NULL;
236 for (molecule::iterator iter = srcmol->begin(); iter != srcmol->end(); ++iter) {
237 Walker = mol->AddCopyAtom((*iter));
[e138de]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)) {
[58ed4a]319 DoeLog(1) && (eLog()<< Verbose(1) << "Either fixed or variable molecule is given as NULL." << endl);
[e138de]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) {
[58ed4a]327 DoeLog(1) && (eLog()<< Verbose(1) << "Could not tesselate the fixed molecule." << endl);
[e138de]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
[ea7176]334 atom ** CopyAtoms = new atom*[srcmol->getAtomCount()];
335 for(int i=0;i<srcmol->getAtomCount();i++)
[e138de]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;
[9879f6]340 for (molecule::const_iterator iter = srcmol->begin(); iter != srcmol->end(); ++iter) {
[a7b761b]341 DoLog(2) && (Log() << Verbose(2) << "INFO: Current Walker is " << **iter << "." << endl);
[9879f6]342 if (!TesselStruct->IsInnerPoint((*iter)->x, LCList)) {
343 CopyAtoms[(*iter)->nr] = (*iter)->clone();
344 mol->AddAtom(CopyAtoms[(*iter)->nr]);
[e138de]345 nr++;
346 } else {
347 // do nothing
348 }
349 }
[a7b761b]350 DoLog(1) && (Log() << Verbose(1) << nr << " of " << srcmol->getAtomCount() << " atoms have been merged.");
[e138de]351
352 // go through all bonds and add as well
[e08c46]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 }
[e138de]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{
[a67d19]368 DoLog(1) && (Log() << Verbose(1) << "MoleculeList: ");
[e138de]369 for (MoleculeList::iterator ListRunner = ListOfMolecules.begin(); ListRunner != ListOfMolecules.end(); ListRunner++)
[a67d19]370 DoLog(0) && (Log() << Verbose(0) << *ListRunner << "\t");
371 DoLog(0) && (Log() << Verbose(0) << endl);
[e138de]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
[a67d19]395 DoLog(1) && (Log() << Verbose(1) << "Saving hydrogen saturation correction ... ");
[e138de]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) {
[a67d19]405 DoLog(1) && (Log() << Verbose(1) << endl << "Unable to open " << line << ", is the directory correct?" << endl);
[e138de]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 }
[a67d19]422 DoLog(0) && (Log() << Verbose(0) << "I recognized " << a << " columns and " << b << " rows, ");
[e138de]423 input.close();
424
425 // 0b. allocate memory for constants
[920c70]426 FitConstant = new double**[3];
[e138de]427 for (int k = 0; k < 3; k++) {
[920c70]428 FitConstant[k] = new double*[a];
[e138de]429 for (int i = a; i--;) {
[920c70]430 FitConstant[k][i] = new double[b];
431 for (int j = b; j--;) {
432 FitConstant[k][i][j] = 0.;
433 }
[e138de]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) {
[58ed4a]446 DoeLog(0) && (eLog()<< Verbose(0) << endl << "Unable to open " << line << ", is the directory correct?" << endl);
[e359a8]447 performCriticalExit();
[e138de]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++) {
[a67d19]468 DoLog(0) && (Log() << Verbose(0) << "Constants " << k << ":" << endl);
[e138de]469 for (int j = 0; j < b; j++) {
470 for (int i = 0; i < a; i++) {
[a67d19]471 DoLog(0) && (Log() << Verbose(0) << FitConstant[k][i][j] << "\t");
[e138de]472 }
[a67d19]473 DoLog(0) && (Log() << Verbose(0) << endl);
[e138de]474 }
[a67d19]475 DoLog(0) && (Log() << Verbose(0) << endl);
[e138de]476 }
477
478 // 0d. allocate final correction matrix
[920c70]479 correction = new double*[a];
[e138de]480 for (int i = a; i--;)
[920c70]481 correction[i] = new double[b];
[e138de]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
[9879f6]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;
[e138de]496 // 3. take every other hydrogen that is the not the first and not bound to same bonding partner
[9879f6]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!)
[e138de]499 // 4. evaluate the morse potential for each matrix component and add up
[a7b761b]500 distance = (*runner)->x.distance((*iter)->x);
[9879f6]501 //Log() << Verbose(0) << "Fragment " << (*ListRunner)->name << ": " << *(*runner) << "<= " << distance << "=>" << *(*iter) << ":" << endl;
[e138de]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;
[920c70]529 delete[] (FragmentNumber);
[e138de]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 }
[920c70]540 for (int i = a; i--;)
541 delete[](correction[i]);
542 delete[](correction);
543
[e138de]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--;) {
[920c70]558 delete[](FitConstant[k][i]);
[e138de]559 }
[920c70]560 delete[](FitConstant[k]);
[e138de]561 }
[920c70]562 delete[](FitConstant);
[a67d19]563 DoLog(0) && (Log() << Verbose(0) << "done." << endl);
[e138de]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;
[ead4e6]579 periodentafel *periode=World::getInstance().getPeriode();
[e138de]580
581 // open file for the force factors
[a67d19]582 DoLog(1) && (Log() << Verbose(1) << "Saving force factors ... ");
[e138de]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++) {
[ead4e6]589 periodentafel::const_iterator elemIter;
590 for(elemIter=periode->begin();elemIter!=periode->end();++elemIter){
[a7b761b]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
[e138de]595 //Log() << Verbose(0) << "Walker is " << *Walker << " with true father " << *( Walker->GetTrueFather()) << ", it
[a7b761b]596 ForcesFile << SortIndex[(*atomIter)->GetTrueFather()->nr] << "\t";
[e138de]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();
[a67d19]607 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
[e138de]608 } else {
609 status = false;
[a67d19]610 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line.str() << "." << endl);
[e138de]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;
[b34306]635 double cell_size_backup[6];
[5f612ee]636 double * const cell_size = World::getInstance().getDomain();
[e138de]637
[b34306]638 // backup cell_size
639 for (int i=0;i<6;i++)
640 cell_size_backup[i] = cell_size[i];
[e138de]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);
[e359a8]647 else {
[58ed4a]648 DoeLog(0) && (eLog()<< Verbose(0) << "OutputConfigForListOfFragments: NULL default path obtained from config!" << endl);
[e359a8]649 performCriticalExit();
650 }
[e138de]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);
[a67d19]659 DoLog(2) && (Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as XYZ ...");
[e138de]660 if ((intermediateResult = (*ListRunner)->OutputXYZ(&outputFragment)))
[a67d19]661 DoLog(0) && (Log() << Verbose(0) << " done." << endl);
[e138de]662 else
[a67d19]663 DoLog(0) && (Log() << Verbose(0) << " failed." << endl);
[e138de]664 result = result && intermediateResult;
665 outputFragment.close();
666 outputFragment.clear();
667
668 // list atoms in fragment for debugging
[a67d19]669 DoLog(2) && (Log() << Verbose(2) << "Contained atoms: ");
[9879f6]670 for (molecule::const_iterator iter = (*ListRunner)->begin(); iter != (*ListRunner)->end(); ++iter) {
[a7b761b]671 DoLog(0) && (Log() << Verbose(0) << (*iter)->getName() << " ");
[e138de]672 }
[a67d19]673 DoLog(0) && (Log() << Verbose(0) << endl);
[e138de]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;
[0a4f7f]681 BoxDimension[k] = 2.5 * (configuration->GetIsAngstroem() ? 1. : 1. / AtomicLengthToAngstroem);
[8cbb97]682 cell_size[j] = BoxDimension[k] * 2.;
[e138de]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);
[a67d19]697 DoLog(2) && (Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as config ...");
[e138de]698 if ((intermediateResult = configuration->Save(FragmentName, (*ListRunner)->elemente, (*ListRunner))))
[a67d19]699 DoLog(0) && (Log() << Verbose(0) << " done." << endl);
[e138de]700 else
[a67d19]701 DoLog(0) && (Log() << Verbose(0) << " failed." << endl);
[e138de]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);
[a67d19]709 DoLog(2) && (Log() << Verbose(2) << "Saving bond fragment No. " << FragmentNumber << "/" << FragmentCounter - 1 << " as mpqc input ...");
[e138de]710 if ((intermediateResult = configuration->SaveMPQC(FragmentName, (*ListRunner))))
[a67d19]711 DoLog(2) && (Log() << Verbose(2) << " done." << endl);
[e138de]712 else
[a67d19]713 DoLog(0) && (Log() << Verbose(0) << " failed." << endl);
[e138de]714
715 result = result && intermediateResult;
716 //outputFragment.close();
717 //outputFragment.clear();
[920c70]718 delete[](FragmentNumber);
[e138de]719 }
[a67d19]720 DoLog(0) && (Log() << Verbose(0) << " done." << endl);
[e138de]721
722 // printing final number
[a67d19]723 DoLog(2) && (Log() << Verbose(2) << "Final number of fragments: " << FragmentCounter << "." << endl);
[e138de]724
[b34306]725 // restore cell_size
726 for (int i=0;i<6;i++)
727 cell_size[i] = cell_size_backup[i];
[e138de]728
729 return result;
730};
731
732/** Counts the number of molecules with the molecule::ActiveFlag set.
[1907a7]733 * \return number of molecules with ActiveFlag set to true.
[e138de]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
[244a84]745 * \param *periode periodentafel
[e138de]746 * \param *configuration config with BondGraph
747 */
[244a84]748void MoleculeListClass::DissectMoleculeIntoConnectedSubgraphs(const periodentafel * const periode, config * const configuration)
[e138de]749{
[bd6bfa]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);
[23b547]754 World::getInstance().destroyMolecule(*MolRunner);
[bd6bfa]755 }
[7fd416]756 // 0b. remove all bonds and construct a molecule with all atoms
[bd6bfa]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);
[244a84]763 }
764
[e138de]765 // 1. dissect the molecule into connected subgraphs
[b72091]766 if (!configuration->BG->ConstructBondGraph(mol)) {
[5f612ee]767 World::getInstance().destroyMolecule(mol);
[58ed4a]768 DoeLog(1) && (eLog()<< Verbose(1) << "There are no bonds." << endl);
[046783]769 return;
770 }
[e138de]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);
[046783]777 if ((Subgraphs == NULL) || (Subgraphs->next == NULL)) {
[5f612ee]778 World::getInstance().destroyMolecule(mol);
[58ed4a]779 DoeLog(1) && (eLog()<< Verbose(1) << "There are no atoms." << endl);
[046783]780 return;
781 }
[e138de]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();
[6a7f78c]789 char number[MAXSTRINGSIZE];
[920c70]790 molecule **molecules = new molecule *[MolCount];
[7fd416]791 MoleculeLeafClass *MolecularWalker = Subgraphs;
[e138de]792 for (int i=0;i<MolCount;i++) {
[7fd416]793 MolecularWalker = MolecularWalker->next;
[23b547]794 molecules[i] = World::getInstance().createMolecule();
[e138de]795 molecules[i]->ActiveFlag = true;
[6a7f78c]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 }
[a67d19]801 DoLog(1) && (Log() << Verbose(1) << "MolName is " << molecules[i]->name << endl);
[7fd416]802 for (molecule::iterator iter = MolecularWalker->Leaf->begin(); iter != MolecularWalker->Leaf->end(); ++iter) {
803 DoLog(1) && (Log() << Verbose(1) << **iter << endl);
804 }
[e138de]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;
[7fd416]810 map<int, atom *> AtomToFragmentMap;
811 MolecularWalker = Subgraphs;
[e138de]812 while (MolecularWalker->next != NULL) {
813 MolecularWalker = MolecularWalker->next;
[7fd416]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
[e138de]819 }
820 FragmentCounter++;
821 }
[7fd416]822 World::getInstance().destroyMolecule(mol);
[e138de]823
[6a7f78c]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
[e08c46]825 // TODO: check whether this is really not needed anymore
[e138de]826 // 4e. free Leafs
827 MolecularWalker = Subgraphs;
828 while (MolecularWalker->next != NULL) {
829 MolecularWalker = MolecularWalker->next;
830 delete(MolecularWalker->previous);
831 }
832 delete(MolecularWalker);
[920c70]833 delete[](molecules);
[a67d19]834 DoLog(1) && (Log() << Verbose(1) << "I scanned " << FragmentCounter << " molecules." << endl);
[e138de]835};
836
[568be7]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++) {
[9879f6]845 AtomNo += (*MolWalker)->size();
[568be7]846 }
847 return AtomNo;
848}
849
[477bb2]850/***********
851 * Methods Moved here from the menus
852 */
[568be7]853
[77675f]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
[477bb2]863void MoleculeListClass::createNewMolecule(periodentafel *periode) {
[2ba827]864 OBSERVE;
[477bb2]865 molecule *mol = NULL;
[23b547]866 mol = World::getInstance().createMolecule();
[477bb2]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;
[23b547]875 mol = World::getInstance().createMolecule();
[477bb2]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);
[8cbb97]883 World::getInstance().getDomain()[0] = center[0];
[5f612ee]884 World::getInstance().getDomain()[1] = 0;
[8cbb97]885 World::getInstance().getDomain()[2] = center[1];
[5f612ee]886 World::getInstance().getDomain()[3] = 0;
887 World::getInstance().getDomain()[4] = 0;
[8cbb97]888 World::getInstance().getDomain()[5] = center[2];
[477bb2]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);
[23b547]933 World::getInstance().destroyMolecule(mol);
[477bb2]934 break;
935 }
936};
937
[77675f]938
[e138de]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) {
[23b547]980 World::getInstance().destroyMolecule(Leaf);
[e138de]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
[a67d19]1025 DoLog(1) && (Log() << Verbose(1) << "Begin of FillBondStructureFromReference." << endl);
[e138de]1026 // fill ListOfLocalAtoms if NULL was given
[ea7176]1027 if (!FillListOfLocalAtoms(ListOfLocalAtoms, FragmentCounter, reference->getAtomCount(), FreeList)) {
[a67d19]1028 DoLog(1) && (Log() << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl);
[e138de]1029 return false;
1030 }
1031
1032 if (status) {
[a67d19]1033 DoLog(1) && (Log() << Verbose(1) << "Creating adjacency list for subgraph " << Leaf << "." << endl);
[e138de]1034 // remove every bond from the list
[e08c46]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));
[e138de]1039
[9879f6]1040 for(molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end(); ++iter) {
1041 Father = (*iter)->GetTrueFather();
[e138de]1042 AtomNo = Father->nr; // global id of the current walker
1043 for (BondList::const_iterator Runner = Father->ListOfBonds.begin(); Runner != Father->ListOfBonds.end(); (++Runner)) {
[9879f6]1044 OtherWalker = ListOfLocalAtoms[FragmentCounter][(*Runner)->GetOtherAtom((*iter)->GetTrueFather())->nr]; // local copy of current bond partner of walker
[e138de]1045 if (OtherWalker != NULL) {
[9879f6]1046 if (OtherWalker->nr > (*iter)->nr)
1047 Leaf->AddBond((*iter), OtherWalker, (*Runner)->BondDegree);
[e138de]1048 } else {
[a7b761b]1049 DoLog(1) && (Log() << Verbose(1) << "OtherWalker = ListOfLocalAtoms[" << FragmentCounter << "][" << (*Runner)->GetOtherAtom((*iter)->GetTrueFather())->nr << "] is NULL!" << endl);
[e138de]1050 status = false;
1051 }
1052 }
1053 }
1054 }
1055
1056 if ((FreeList) && (ListOfLocalAtoms != NULL)) {
1057 // free the index lookup list
[920c70]1058 delete[](ListOfLocalAtoms[FragmentCounter]);
[e138de]1059 if (FragmentCounter == 0) // first fragments frees the initial pointer to list
[920c70]1060 delete[](ListOfLocalAtoms);
[e138de]1061 }
[a67d19]1062 DoLog(1) && (Log() << Verbose(1) << "End of FillBondStructureFromReference." << endl);
[e138de]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{
[9879f6]1076 atom *Father = NULL;
[e138de]1077
1078 if (RootStack != NULL) {
1079 // find first root candidates
1080 if (&(RootStack[FragmentCounter]) != NULL) {
1081 RootStack[FragmentCounter].clear();
[9879f6]1082 for(molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end(); ++iter) {
1083 Father = (*iter)->GetTrueFather();
[e138de]1084 if (AtomMask[Father->nr]) // apply mask
1085#ifdef ADDHYDROGEN
[9879f6]1086 if ((*iter)->type->Z != 1) // skip hydrogen
[e138de]1087#endif
[9879f6]1088 RootStack[FragmentCounter].push_front((*iter)->nr);
[e138de]1089 }
1090 if (next != NULL)
1091 next->FillRootStackForSubgraphs(RootStack, AtomMask, ++FragmentCounter);
1092 } else {
[a67d19]1093 DoLog(1) && (Log() << Verbose(1) << "Rootstack[" << FragmentCounter << "] is NULL." << endl);
[e138de]1094 return false;
1095 }
1096 FragmentCounter--;
1097 return true;
1098 } else {
[a67d19]1099 DoLog(1) && (Log() << Verbose(1) << "Rootstack is NULL." << endl);
[e138de]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();
[920c70]1119 ASSERT(FragmentCounter < Counter, "FillListOfLocalAtoms: FragmenCounter greater than present fragments.");
1120 ListOfLocalAtoms = new atom**[Counter];
[e138de]1121 if (ListOfLocalAtoms == NULL) {
1122 FreeList = FreeList && false;
1123 status = false;
1124 }
[920c70]1125 for (int i=0;i<Counter;i++)
1126 ListOfLocalAtoms[i] = NULL;
[e138de]1127 }
1128
1129 if ((ListOfLocalAtoms != NULL) && (ListOfLocalAtoms[FragmentCounter] == NULL)) { // allocate and fill list of this fragment/subgraph
[9879f6]1130 status = status && Leaf->CreateFatherLookupTable(ListOfLocalAtoms[FragmentCounter], GlobalAtomCount);
[e138de]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
[a67d19]1152 DoLog(1) && (Log() << Verbose(1) << "Begin of AssignKeySetsToFragment." << endl);
[e138de]1153 // fill ListOfLocalAtoms if NULL was given
[ea7176]1154 if (!FillListOfLocalAtoms(ListOfLocalAtoms, FragmentCounter, reference->getAtomCount(), FreeList)) {
[a67d19]1155 DoLog(1) && (Log() << Verbose(1) << "Filling of ListOfLocalAtoms failed." << endl);
[e138de]1156 return false;
1157 }
1158
1159 // allocate fragment list
1160 if (FragmentList == NULL) {
1161 KeySetCounter = Count();
[920c70]1162 FragmentList = new Graph*[KeySetCounter];
1163 for (int i=0;i<KeySetCounter;i++)
1164 FragmentList[i] = NULL;
[e138de]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
[a67d19]1185 DoLog(1) && (Log() << Verbose(1) << "KeySetCounter is zero, deleting FragmentList." << endl);
[e138de]1186 delete (FragmentList[FragmentCounter]);
1187 } else
[a67d19]1188 DoLog(1) && (Log() << Verbose(1) << KeySetCounter << " keysets were assigned to subgraph " << FragmentCounter << "." << endl);
[e138de]1189 FragmentCounter++;
1190 if (next != NULL)
1191 next->AssignKeySetsToFragment(reference, KeySetList, ListOfLocalAtoms, FragmentList, FragmentCounter, FreeList);
1192 FragmentCounter--;
1193 } else
[a67d19]1194 DoLog(1) && (Log() << Verbose(1) << "KeySetList is NULL or empty." << endl);
[e138de]1195
1196 if ((FreeList) && (ListOfLocalAtoms != NULL)) {
1197 // free the index lookup list
[920c70]1198 delete[](ListOfLocalAtoms[FragmentCounter]);
[e138de]1199 if (FragmentCounter == 0) // first fragments frees the initial pointer to list
[920c70]1200 delete[](ListOfLocalAtoms);
[e138de]1201 }
[a67d19]1202 DoLog(1) && (Log() << Verbose(1) << "End of AssignKeySetsToFragment." << endl);
[e138de]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{
[a67d19]1215 DoLog(1) && (Log() << Verbose(1) << "Begin of TranslateIndicesToGlobalIDs." << endl);
[e138de]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 {
[a67d19]1226 DoLog(1) && (Log() << Verbose(1) << "FragmentList is NULL." << endl);
[e138de]1227 }
1228 if (next != NULL)
1229 next->TranslateIndicesToGlobalIDs(FragmentList, ++FragmentCounter, TotalNumberOfKeySets, TotalGraph);
1230 FragmentCounter--;
[a67d19]1231 DoLog(1) && (Log() << Verbose(1) << "End of TranslateIndicesToGlobalIDs." << endl);
[e138de]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.