source: src/molecule_fragmentation.cpp@ ce5f05

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

Moved Shading and EdgeType from defs.hpp to bond.hpp, getColor from molecule to class bond.

  • Property mode set to 100644
File size: 83.2 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * molecule_fragmentation.cpp
10 *
11 * Created on: Oct 5, 2009
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include <cstring>
23
24#include "World.hpp"
25#include "atom.hpp"
26#include "bond.hpp"
27#include "bondgraph.hpp"
28#include "config.hpp"
29#include "element.hpp"
30#include "Helpers/helpers.hpp"
31#include "CodePatterns/Verbose.hpp"
32#include "CodePatterns/Log.hpp"
33#include "molecule.hpp"
34#include "periodentafel.hpp"
35#include "World.hpp"
36#include "LinearAlgebra/RealSpaceMatrix.hpp"
37#include "Box.hpp"
38
39/************************************* Functions for class molecule *********************************/
40
41
42/** Estimates by educated guessing (using upper limit) the expected number of fragments.
43 * The upper limit is
44 * \f[
45 * n = N \cdot C^k
46 * \f]
47 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
48 * \param *out output stream for debugging
49 * \param order bond order k
50 * \return number n of fragments
51 */
52int molecule::GuesstimateFragmentCount(int order)
53{
54 size_t c = 0;
55 int FragmentCount;
56 // get maximum bond degree
57 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
58 const BondList& ListOfBonds = (*iter)->getListOfBonds();
59 c = (ListOfBonds.size() > c) ? ListOfBonds.size() : c;
60 }
61 FragmentCount = NoNonHydrogen*(1 << (c*order));
62 DoLog(1) && (Log() << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl);
63 return FragmentCount;
64};
65
66/** Scans a single line for number and puts them into \a KeySet.
67 * \param *out output stream for debugging
68 * \param *buffer buffer to scan
69 * \param &CurrentSet filled KeySet on return
70 * \return true - at least one valid atom id parsed, false - CurrentSet is empty
71 */
72bool ScanBufferIntoKeySet(char *buffer, KeySet &CurrentSet)
73{
74 stringstream line;
75 int AtomNr;
76 int status = 0;
77
78 line.str(buffer);
79 while (!line.eof()) {
80 line >> AtomNr;
81 if (AtomNr >= 0) {
82 CurrentSet.insert(AtomNr); // insert at end, hence in same order as in file!
83 status++;
84 } // else it's "-1" or else and thus must not be added
85 }
86 DoLog(1) && (Log() << Verbose(1) << "The scanned KeySet is ");
87 for(KeySet::iterator runner = CurrentSet.begin(); runner != CurrentSet.end(); runner++) {
88 DoLog(0) && (Log() << Verbose(0) << (*runner) << "\t");
89 }
90 DoLog(0) && (Log() << Verbose(0) << endl);
91 return (status != 0);
92};
93
94/** Parses the KeySet file and fills \a *FragmentList from the known molecule structure.
95 * Does two-pass scanning:
96 * -# Scans the keyset file and initialises a temporary graph
97 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
98 * Finally, the temporary graph is inserted into the given \a FragmentList for return.
99 * \param &path path to file
100 * \param *FragmentList empty, filled on return
101 * \return true - parsing successfully, false - failure on parsing (FragmentList will be NULL)
102 */
103bool ParseKeySetFile(std::string &path, Graph *&FragmentList)
104{
105 bool status = true;
106 ifstream InputFile;
107 stringstream line;
108 GraphTestPair testGraphInsert;
109 int NumberOfFragments = 0;
110 string filename;
111
112 if (FragmentList == NULL) { // check list pointer
113 FragmentList = new Graph;
114 }
115
116 // 1st pass: open file and read
117 DoLog(1) && (Log() << Verbose(1) << "Parsing the KeySet file ... " << endl);
118 filename = path + KEYSETFILE;
119 InputFile.open(filename.c_str());
120 if (InputFile.good()) {
121 // each line represents a new fragment
122 char buffer[MAXSTRINGSIZE];
123 // 1. parse keysets and insert into temp. graph
124 while (!InputFile.eof()) {
125 InputFile.getline(buffer, MAXSTRINGSIZE);
126 KeySet CurrentSet;
127 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(buffer, CurrentSet))) { // if at least one valid atom was added, write config
128 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1))); // store fragment number and current factor
129 if (!testGraphInsert.second) {
130 DoeLog(0) && (eLog()<< Verbose(0) << "KeySet file must be corrupt as there are two equal key sets therein!" << endl);
131 performCriticalExit();
132 }
133 }
134 }
135 // 2. Free and done
136 InputFile.close();
137 InputFile.clear();
138 DoLog(1) && (Log() << Verbose(1) << "\t ... done." << endl);
139 } else {
140 DoLog(1) && (Log() << Verbose(1) << "\t ... File " << filename << " not found." << endl);
141 status = false;
142 }
143
144 return status;
145};
146
147/** Parses the TE factors file and fills \a *FragmentList from the known molecule structure.
148 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
149 * \param *out output stream for debugging
150 * \param *path path to file
151 * \param *FragmentList graph whose nodes's TE factors are set on return
152 * \return true - parsing successfully, false - failure on parsing
153 */
154bool ParseTEFactorsFile(char *path, Graph *FragmentList)
155{
156 bool status = true;
157 ifstream InputFile;
158 stringstream line;
159 GraphTestPair testGraphInsert;
160 int NumberOfFragments = 0;
161 double TEFactor;
162 char filename[MAXSTRINGSIZE];
163
164 if (FragmentList == NULL) { // check list pointer
165 FragmentList = new Graph;
166 }
167
168 // 2nd pass: open TEFactors file and read
169 DoLog(1) && (Log() << Verbose(1) << "Parsing the TEFactors file ... " << endl);
170 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, TEFACTORSFILE);
171 InputFile.open(filename);
172 if (InputFile != NULL) {
173 // 3. add found TEFactors to each keyset
174 NumberOfFragments = 0;
175 for(Graph::iterator runner = FragmentList->begin();runner != FragmentList->end(); runner++) {
176 if (!InputFile.eof()) {
177 InputFile >> TEFactor;
178 (*runner).second.second = TEFactor;
179 DoLog(2) && (Log() << Verbose(2) << "Setting " << ++NumberOfFragments << " fragment's TEFactor to " << (*runner).second.second << "." << endl);
180 } else {
181 status = false;
182 break;
183 }
184 }
185 // 4. Free and done
186 InputFile.close();
187 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
188 } else {
189 DoLog(1) && (Log() << Verbose(1) << "File " << filename << " not found." << endl);
190 status = false;
191 }
192
193 return status;
194};
195
196/** Stores key sets to file.
197 * \param KeySetList Graph with Keysets
198 * \param &path path to file
199 * \return true - file written successfully, false - writing failed
200 */
201bool StoreKeySetFile(Graph &KeySetList, std::string &path)
202{
203 bool status = true;
204 string line = path + KEYSETFILE;
205 ofstream output(line.c_str());
206
207 // open KeySet file
208 DoLog(1) && (Log() << Verbose(1) << "Saving key sets of the total graph ... ");
209 if(output.good()) {
210 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) {
211 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
212 if (sprinter != (*runner).first.begin())
213 output << "\t";
214 output << *sprinter;
215 }
216 output << endl;
217 }
218 DoLog(0) && (Log() << Verbose(0) << "done." << endl);
219 } else {
220 DoeLog(0) && (eLog()<< Verbose(0) << "Unable to open " << line << " for writing keysets!" << endl);
221 performCriticalExit();
222 status = false;
223 }
224 output.close();
225 output.clear();
226
227 return status;
228};
229
230
231/** Stores TEFactors to file.
232 * \param *out output stream for debugging
233 * \param KeySetList Graph with factors
234 * \param *path path to file
235 * \return true - file written successfully, false - writing failed
236 */
237bool StoreTEFactorsFile(Graph &KeySetList, char *path)
238{
239 ofstream output;
240 bool status = true;
241 string line;
242
243 // open TEFactors file
244 line = path;
245 line.append("/");
246 line += FRAGMENTPREFIX;
247 line += TEFACTORSFILE;
248 output.open(line.c_str(), ios::out);
249 DoLog(1) && (Log() << Verbose(1) << "Saving TEFactors of the total graph ... ");
250 if(output != NULL) {
251 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++)
252 output << (*runner).second.second << endl;
253 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
254 } else {
255 DoLog(1) && (Log() << Verbose(1) << "failed to open " << line << "." << endl);
256 status = false;
257 }
258 output.close();
259
260 return status;
261};
262
263/** For a given graph, sorts KeySets into a (index, keyset) map.
264 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
265 * \return map from index to keyset
266 */
267map<int,KeySet> * GraphToIndexedKeySet(Graph *GlobalKeySetList)
268{
269 map<int,KeySet> *IndexKeySetList = new map<int,KeySet>;
270 for(Graph::iterator runner = GlobalKeySetList->begin(); runner != GlobalKeySetList->end(); runner++) {
271 IndexKeySetList->insert( pair<int,KeySet>(runner->second.first,runner->first) );
272 }
273 return IndexKeySetList;
274};
275
276/** Inserts a (\a No, \a value) pair into the list, overwriting present one.
277 * Note if values are equal, No will decided on which is first
278 * \param *out output stream for debugging
279 * \param &AdaptiveCriteriaList list to insert into
280 * \param &IndexedKeySetList list to find key set for a given index \a No
281 * \param FragOrder current bond order of fragment
282 * \param No index of keyset
283 * \param value energy value
284 */
285void InsertIntoAdaptiveCriteriaList(map<int, pair<double,int> > *AdaptiveCriteriaList, map<int,KeySet> &IndexKeySetList, int FragOrder, int No, double Value)
286{
287 map<int,KeySet>::iterator marker = IndexKeySetList.find(No); // find keyset to Frag No.
288 if (marker != IndexKeySetList.end()) { // if found
289 Value *= 1 + MYEPSILON*(*((*marker).second.begin())); // in case of equal energies this makes them not equal without changing anything actually
290 // as the smallest number in each set has always been the root (we use global id to keep the doubles away), seek smallest and insert into AtomMask
291 pair <map<int, pair<double,int> >::iterator, bool> InsertedElement = AdaptiveCriteriaList->insert( make_pair(*((*marker).second.begin()), pair<double,int>( fabs(Value), FragOrder) ));
292 map<int, pair<double,int> >::iterator PresentItem = InsertedElement.first;
293 if (!InsertedElement.second) { // this root is already present
294 if ((*PresentItem).second.second < FragOrder) // if order there is lower, update entry with higher-order term
295 //if ((*PresentItem).second.first < (*runner).first) // as higher-order terms are not always better, we skip this part (which would always include this site into adaptive increase)
296 { // if value is smaller, update value and order
297 (*PresentItem).second.first = fabs(Value);
298 (*PresentItem).second.second = FragOrder;
299 DoLog(2) && (Log() << Verbose(2) << "Updated element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl);
300 } else {
301 DoLog(2) && (Log() << Verbose(2) << "Did not update element " << (*PresentItem).first << " as " << FragOrder << " is less than or equal to " << (*PresentItem).second.second << "." << endl);
302 }
303 } else {
304 DoLog(2) && (Log() << Verbose(2) << "Inserted element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl);
305 }
306 } else {
307 DoLog(1) && (Log() << Verbose(1) << "No Fragment under No. " << No << "found." << endl);
308 }
309};
310
311/** Counts lines in file.
312 * Note we are scanning lines from current position, not from beginning.
313 * \param InputFile file to be scanned.
314 */
315int CountLinesinFile(ifstream &InputFile)
316{
317 char *buffer = new char[MAXSTRINGSIZE];
318 int lines=0;
319
320 int PositionMarker = InputFile.tellg(); // not needed as Inputfile is copied, given by value, not by ref
321 // count the number of lines, i.e. the number of fragments
322 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
323 InputFile.getline(buffer, MAXSTRINGSIZE);
324 while(!InputFile.eof()) {
325 InputFile.getline(buffer, MAXSTRINGSIZE);
326 lines++;
327 }
328 InputFile.seekg(PositionMarker, ios::beg);
329 delete[](buffer);
330 return lines;
331};
332
333
334/** Scans the adaptive order file and insert (index, value) into map.
335 * \param &path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
336 * \param &IndexedKeySetList list to find key set for a given index \a No
337 * \return adaptive criteria list from file
338 */
339map<int, pair<double,int> > * ScanAdaptiveFileIntoMap(std::string &path, map<int,KeySet> &IndexKeySetList)
340{
341 map<int, pair<double,int> > *AdaptiveCriteriaList = new map<int, pair<double,int> >;
342 int No = 0, FragOrder = 0;
343 double Value = 0.;
344 char buffer[MAXSTRINGSIZE];
345 string filename = path + ENERGYPERFRAGMENT;
346 ifstream InputFile(filename.c_str());
347
348 if (InputFile.fail()) {
349 DoeLog(1) && (eLog() << Verbose(1) << "Cannot find file " << filename << "." << endl);
350 return AdaptiveCriteriaList;
351 }
352
353 if (CountLinesinFile(InputFile) > 0) {
354 // each line represents a fragment root (Atom::Nr) id and its energy contribution
355 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
356 InputFile.getline(buffer, MAXSTRINGSIZE);
357 while(!InputFile.eof()) {
358 InputFile.getline(buffer, MAXSTRINGSIZE);
359 if (strlen(buffer) > 2) {
360 //Log() << Verbose(2) << "Scanning: " << buffer << endl;
361 stringstream line(buffer);
362 line >> FragOrder;
363 line >> ws >> No;
364 line >> ws >> Value; // skip time entry
365 line >> ws >> Value;
366 No -= 1; // indices start at 1 in file, not 0
367 //Log() << Verbose(2) << " - yields (" << No << "," << Value << ", " << FragOrder << ")" << endl;
368
369 // clean the list of those entries that have been superceded by higher order terms already
370 InsertIntoAdaptiveCriteriaList(AdaptiveCriteriaList, IndexKeySetList, FragOrder, No, Value);
371 }
372 }
373 // close and done
374 InputFile.close();
375 InputFile.clear();
376 }
377
378 return AdaptiveCriteriaList;
379};
380
381/** Maps adaptive criteria list back onto (Value, (Root Nr., Order))
382 * (i.e. sorted by value to pick the highest ones)
383 * \param *out output stream for debugging
384 * \param &AdaptiveCriteriaList list to insert into
385 * \param *mol molecule with atoms
386 * \return remapped list
387 */
388map<double, pair<int,int> > * ReMapAdaptiveCriteriaListToValue(map<int, pair<double,int> > *AdaptiveCriteriaList, molecule *mol)
389{
390 atom *Walker = NULL;
391 map<double, pair<int,int> > *FinalRootCandidates = new map<double, pair<int,int> > ;
392 DoLog(1) && (Log() << Verbose(1) << "Root candidate list is: " << endl);
393 for(map<int, pair<double,int> >::iterator runner = AdaptiveCriteriaList->begin(); runner != AdaptiveCriteriaList->end(); runner++) {
394 Walker = mol->FindAtom((*runner).first);
395 if (Walker != NULL) {
396 //if ((*runner).second.second >= Walker->AdaptiveOrder) { // only insert if this is an "active" root site for the current order
397 if (!Walker->MaxOrder) {
398 DoLog(2) && (Log() << Verbose(2) << "(" << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "])" << endl);
399 FinalRootCandidates->insert( make_pair( (*runner).second.first, pair<int,int>((*runner).first, (*runner).second.second) ) );
400 } else {
401 DoLog(2) && (Log() << Verbose(2) << "Excluding (" << *Walker << ", " << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "]), as it has reached its maximum order." << endl);
402 }
403 } else {
404 DoeLog(0) && (eLog()<< Verbose(0) << "Atom No. " << (*runner).second.first << " was not found in this molecule." << endl);
405 performCriticalExit();
406 }
407 }
408 return FinalRootCandidates;
409};
410
411/** Marks all candidate sites for update if below adaptive threshold.
412 * Picks a given number of highest values and set *AtomMask to true.
413 * \param *out output stream for debugging
414 * \param *AtomMask defines true/false per global Atom::Nr to mask in/out each nuclear site, used to activate given number of site to increment order adaptively
415 * \param FinalRootCandidates list candidates to check
416 * \param Order desired order
417 * \param *mol molecule with atoms
418 * \return true - if update is necessary, false - not
419 */
420bool MarkUpdateCandidates(bool *AtomMask, map<double, pair<int,int> > &FinalRootCandidates, int Order, molecule *mol)
421{
422 atom *Walker = NULL;
423 int No = -1;
424 bool status = false;
425 for(map<double, pair<int,int> >::iterator runner = FinalRootCandidates.upper_bound(pow(10.,Order)); runner != FinalRootCandidates.end(); runner++) {
426 No = (*runner).second.first;
427 Walker = mol->FindAtom(No);
428 //if (Walker->AdaptiveOrder < MinimumRingSize[Walker->getNr()]) {
429 DoLog(2) && (Log() << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", setting entry " << No << " of Atom mask to true." << endl);
430 AtomMask[No] = true;
431 status = true;
432 //} else
433 //Log() << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", however MinimumRingSize of " << MinimumRingSize[Walker->getNr()] << " does not allow further adaptive increase." << endl;
434 }
435 return status;
436};
437
438/** print atom mask for debugging.
439 * \param *out output stream for debugging
440 * \param *AtomMask defines true/false per global Atom::Nr to mask in/out each nuclear site, used to activate given number of site to increment order adaptively
441 * \param AtomCount number of entries in \a *AtomMask
442 */
443void PrintAtomMask(bool *AtomMask, int AtomCount)
444{
445 DoLog(2) && (Log() << Verbose(2) << " ");
446 for(int i=0;i<AtomCount;i++)
447 DoLog(0) && (Log() << Verbose(0) << (i % 10));
448 DoLog(0) && (Log() << Verbose(0) << endl);
449 DoLog(2) && (Log() << Verbose(2) << "Atom mask is: ");
450 for(int i=0;i<AtomCount;i++)
451 DoLog(0) && (Log() << Verbose(0) << (AtomMask[i] ? "t" : "f"));
452 DoLog(0) && (Log() << Verbose(0) << endl);
453};
454
455/** Checks whether the OrderAtSite is still below \a Order at some site.
456 * \param *AtomMask defines true/false per global Atom::Nr to mask in/out each nuclear site, used to activate given number of site to increment order adaptively
457 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
458 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
459 * \param *MinimumRingSize array of max. possible order to avoid loops
460 * \param path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
461 * \return true - needs further fragmentation, false - does not need fragmentation
462 */
463bool molecule::CheckOrderAtSite(bool *AtomMask, Graph *GlobalKeySetList, int Order, int *MinimumRingSize, std::string path)
464{
465 bool status = false;
466
467 // initialize mask list
468 for(int i=getAtomCount();i--;)
469 AtomMask[i] = false;
470
471 if (Order < 0) { // adaptive increase of BondOrder per site
472 if (AtomMask[getAtomCount()] == true) // break after one step
473 return false;
474
475 // transmorph graph keyset list into indexed KeySetList
476 if (GlobalKeySetList == NULL) {
477 DoeLog(1) && (eLog()<< Verbose(1) << "Given global key set list (graph) is NULL!" << endl);
478 return false;
479 }
480 map<int,KeySet> *IndexKeySetList = GraphToIndexedKeySet(GlobalKeySetList);
481
482 // parse the EnergyPerFragment file
483 map<int, pair<double,int> > *AdaptiveCriteriaList = ScanAdaptiveFileIntoMap(path, *IndexKeySetList); // (Root No., (Value, Order)) !
484 if (AdaptiveCriteriaList->empty()) {
485 DoeLog(2) && (eLog()<< Verbose(2) << "Unable to parse file, incrementing all." << endl);
486 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
487 #ifdef ADDHYDROGEN
488 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
489 #endif
490 {
491 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
492 status = true;
493 }
494 }
495 }
496 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
497 map<double, pair<int,int> > *FinalRootCandidates = ReMapAdaptiveCriteriaListToValue(AdaptiveCriteriaList, this);
498
499 // pick the ones still below threshold and mark as to be adaptively updated
500 MarkUpdateCandidates(AtomMask, *FinalRootCandidates, Order, this);
501
502 delete[](IndexKeySetList);
503 delete[](AdaptiveCriteriaList);
504 delete[](FinalRootCandidates);
505 } else { // global increase of Bond Order
506 for(molecule::const_iterator iter = begin(); iter != end(); ++iter) {
507 #ifdef ADDHYDROGEN
508 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
509 #endif
510 {
511 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
512 if ((Order != 0) && ((*iter)->AdaptiveOrder < Order)) // && ((*iter)->AdaptiveOrder < MinimumRingSize[(*iter)->getNr()]))
513 status = true;
514 }
515 }
516 if ((!Order) && (!AtomMask[getAtomCount()])) // single stepping, just check
517 status = true;
518
519 if (!status) {
520 if (Order == 0)
521 DoLog(1) && (Log() << Verbose(1) << "Single stepping done." << endl);
522 else
523 DoLog(1) && (Log() << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl);
524 }
525 }
526
527 PrintAtomMask(AtomMask, getAtomCount()); // for debugging
528
529 return status;
530};
531
532/** Create a SortIndex to map from atomic labels to the sequence in which the atoms are given in the config file.
533 * \param *out output stream for debugging
534 * \param *&SortIndex Mapping array of size molecule::AtomCount
535 * \return true - success, false - failure of SortIndex alloc
536 */
537bool molecule::CreateMappingLabelsToConfigSequence(int *&SortIndex)
538{
539 if (SortIndex != NULL) {
540 DoLog(1) && (Log() << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl);
541 return false;
542 }
543 SortIndex = new int[getAtomCount()];
544 for(int i=getAtomCount();i--;)
545 SortIndex[i] = -1;
546
547 int AtomNo = 0;
548 for(internal_iterator iter=atoms.begin();iter!=atoms.end();++iter){
549 ASSERT(SortIndex[(*iter)->getNr()]==-1,"Same SortIndex set twice");
550 SortIndex[(*iter)->getNr()] = AtomNo++;
551 }
552
553 return true;
554};
555
556
557
558/** Creates a lookup table for true father's Atom::Nr -> atom ptr.
559 * \param *start begin of list (STL iterator, i.e. first item)
560 * \paran *end end of list (STL iterator, i.e. one past last item)
561 * \param **Lookuptable pointer to return allocated lookup table (should be NULL on start)
562 * \param count optional predetermined size for table (otherwise we set the count to highest true father id)
563 * \return true - success, false - failure
564 */
565bool molecule::CreateFatherLookupTable(atom **&LookupTable, int count)
566{
567 bool status = true;
568 int AtomNo;
569
570 if (LookupTable != NULL) {
571 Log() << Verbose(0) << "Pointer for Lookup table is not NULL! Aborting ..." <<endl;
572 return false;
573 }
574
575 // count them
576 if (count == 0) {
577 for (molecule::iterator iter = begin(); iter != end(); ++iter) { // create a lookup table (Atom::Nr -> atom) used as a marker table lateron
578 count = (count < (*iter)->GetTrueFather()->getNr()) ? (*iter)->GetTrueFather()->getNr() : count;
579 }
580 }
581 if (count <= 0) {
582 Log() << Verbose(0) << "Count of lookup list is 0 or less." << endl;
583 return false;
584 }
585
586 // allocate and fill
587 LookupTable = new atom *[count];
588 if (LookupTable == NULL) {
589 eLog() << Verbose(0) << "LookupTable memory allocation failed!" << endl;
590 performCriticalExit();
591 status = false;
592 } else {
593 for (int i=0;i<count;i++)
594 LookupTable[i] = NULL;
595 for (molecule::iterator iter = begin(); iter != end(); ++iter) {
596 AtomNo = (*iter)->GetTrueFather()->getNr();
597 if ((AtomNo >= 0) && (AtomNo < count)) {
598 //*out << "Setting LookupTable[" << AtomNo << "] to " << *(*iter) << endl;
599 LookupTable[AtomNo] = (*iter);
600 } else {
601 Log() << Verbose(0) << "Walker " << *(*iter) << " exceeded range of nuclear ids [0, " << count << ")." << endl;
602 status = false;
603 break;
604 }
605 }
606 }
607
608 return status;
609};
610
611/** Performs a many-body bond order analysis for a given bond order.
612 * -# parses adjacency, keysets and orderatsite files
613 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
614 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
615y contribution", and that's why this consciously not done in the following loop)
616 * -# in a loop over all subgraphs
617 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
618 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
619 * -# combines the generated molecule lists from all subgraphs
620 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
621 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
622 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
623 * subgraph in the MoleculeListClass.
624 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
625 * \param &prefix path and prefix of the bond order configs to be written
626 * \return 1 - continue, 2 - stop (no fragmentation occured)
627 */
628int molecule::FragmentMolecule(int Order, std::string &prefix)
629{
630 MoleculeListClass *BondFragments = NULL;
631 int *MinimumRingSize = new int[getAtomCount()];
632 int FragmentCounter;
633 MoleculeLeafClass *MolecularWalker = NULL;
634 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
635 fstream File;
636 bool FragmentationToDo = true;
637 std::deque<bond *> *BackEdgeStack = NULL, *LocalBackEdgeStack = NULL;
638 bool CheckOrder = false;
639 Graph **FragmentList = NULL;
640 Graph *ParsedFragmentList = NULL;
641 Graph TotalGraph; // graph with all keysets however local numbers
642 int TotalNumberOfKeySets = 0;
643 atom **ListOfAtoms = NULL;
644 atom ***ListOfLocalAtoms = NULL;
645 bool *AtomMask = NULL;
646
647 DoLog(0) && (Log() << Verbose(0) << endl);
648#ifdef ADDHYDROGEN
649 DoLog(0) && (Log() << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl);
650#else
651 DoLog(0) && (Log() << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl);
652#endif
653
654 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
655
656 // ===== 1. Check whether bond structure is same as stored in files ====
657
658 // create lookup table for Atom::Nr
659 FragmentationToDo = FragmentationToDo && CreateFatherLookupTable(ListOfAtoms, getAtomCount());
660
661 // === compare it with adjacency file ===
662 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(prefix, ListOfAtoms);
663 delete[](ListOfAtoms);
664
665 // === reset bond degree and perform CorrectBondDegree ===
666 for(World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
667 iter != World::getInstance().moleculeEnd();
668 ++iter) {
669 // reset bond degree to 1
670 for (molecule::iterator atomiter = (*iter)->begin();
671 atomiter != (*iter)->end();
672 ++atomiter) {
673 const BondList& ListOfBonds = (*atomiter)->getListOfBonds();
674 for (BondList::const_iterator bonditer = ListOfBonds.begin();
675 bonditer != ListOfBonds.end();
676 ++bonditer) {
677 (*bonditer)->BondDegree = 1;
678 }
679 }
680 // correct bond degree
681 (*iter)->CorrectBondDegree();
682 }
683
684 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
685 Subgraphs = DepthFirstSearchAnalysis(BackEdgeStack);
686
687 // analysis of the cycles (print rings, get minimum cycle length) for each subgraph
688 for(int i=getAtomCount();i--;)
689 MinimumRingSize[i] = getAtomCount();
690 MolecularWalker = Subgraphs;
691 const int LeafCount = Subgraphs->next->Count();
692 FragmentCounter = 0;
693 while (MolecularWalker->next != NULL) {
694 MolecularWalker = MolecularWalker->next;
695 // fill the bond structure of the individually stored subgraphs
696 ListOfAtoms = NULL;
697 MolecularWalker->FillBondStructureFromReference(this, ListOfAtoms, false); // we want to keep the created ListOfLocalAtoms
698 DoLog(0) && (Log() << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
699 LocalBackEdgeStack = new std::deque<bond *>; // (MolecularWalker->Leaf->BondCount);
700// // check the list of local atoms for debugging
701// Log() << Verbose(0) << "ListOfLocalAtoms for this subgraph is:" << endl;
702// for (int i=0;i<getAtomCount();i++)
703// if (ListOfLocalAtoms[FragmentCounter][i] == NULL)
704// Log() << Verbose(0) << "\tNULL";
705// else
706// Log() << Verbose(0) << "\t" << ListOfLocalAtoms[FragmentCounter][i]->Name;
707 DoLog(0) && (Log() << Verbose(0) << "Gathering local back edges for subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
708 MolecularWalker->Leaf->PickLocalBackEdges(ListOfAtoms, BackEdgeStack, LocalBackEdgeStack);
709 DoLog(0) && (Log() << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
710 MolecularWalker->Leaf->CyclicStructureAnalysis(LocalBackEdgeStack, MinimumRingSize);
711 DoLog(0) && (Log() << Verbose(0) << "Done with Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
712 delete(LocalBackEdgeStack);
713 delete(ListOfAtoms);
714 FragmentCounter++;
715 }
716 delete(BackEdgeStack);
717
718 // ===== 3. if structure still valid, parse key set file and others =====
719 FragmentationToDo = FragmentationToDo && ParseKeySetFile(prefix, ParsedFragmentList);
720
721 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
722 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(prefix);
723
724 // =================================== Begin of FRAGMENTATION ===============================
725 // ===== 6a. assign each keyset to its respective subgraph =====
726 ListOfLocalAtoms = new atom **[LeafCount];
727 for (int i=0;i<LeafCount;i++)
728 ListOfLocalAtoms[i] = NULL;
729 FragmentCounter = 0;
730 Subgraphs->next->AssignKeySetsToFragment(this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, FragmentCounter, true);
731 delete[](ListOfLocalAtoms);
732
733 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
734 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
735 AtomMask = new bool[getAtomCount()+1];
736 AtomMask[getAtomCount()] = false;
737 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
738 while ((CheckOrder = CheckOrderAtSite(AtomMask, ParsedFragmentList, Order, MinimumRingSize, prefix))) {
739 FragmentationToDo = FragmentationToDo || CheckOrder;
740 AtomMask[getAtomCount()] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
741 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
742 Subgraphs->next->FillRootStackForSubgraphs(RootStack, AtomMask, (FragmentCounter = 0));
743
744 // ===== 7. fill the bond fragment list =====
745 FragmentCounter = 0;
746 MolecularWalker = Subgraphs;
747 while (MolecularWalker->next != NULL) {
748 MolecularWalker = MolecularWalker->next;
749 DoLog(1) && (Log() << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl);
750 //MolecularWalker->Leaf->OutputListOfBonds(out); // output atom::ListOfBonds for debugging
751 if (MolecularWalker->Leaf->hasBondStructure()) {
752 // call BOSSANOVA method
753 DoLog(0) && (Log() << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl);
754 MolecularWalker->Leaf->FragmentBOSSANOVA(FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize);
755 } else {
756 DoeLog(1) && (eLog()<< Verbose(1) << "Subgraph " << MolecularWalker << " has no atoms!" << endl);
757 }
758 FragmentCounter++; // next fragment list
759 }
760 }
761 DoLog(2) && (Log() << Verbose(2) << "CheckOrder is " << CheckOrder << "." << endl);
762 delete[](RootStack);
763 delete[](AtomMask);
764 delete(ParsedFragmentList);
765 delete[](MinimumRingSize);
766
767 // ==================================== End of FRAGMENTATION ============================================
768
769 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
770 Subgraphs->next->TranslateIndicesToGlobalIDs(FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
771
772 // free subgraph memory again
773 FragmentCounter = 0;
774 while (Subgraphs != NULL) {
775 // remove entry in fragment list
776 // remove subgraph fragment
777 MolecularWalker = Subgraphs->next;
778 delete(Subgraphs);
779 Subgraphs = MolecularWalker;
780 }
781 // free fragment list
782 for (int i=0; i< FragmentCounter; ++i )
783 delete(FragmentList[i]);
784 delete[](FragmentList);
785
786 DoLog(0) && (Log() << Verbose(0) << FragmentCounter-1 << " subgraph fragments have been removed." << std::endl);
787
788 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
789 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
790 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
791 BondFragments = new MoleculeListClass(World::getPointer());
792 int k=0;
793 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
794 KeySet test = (*runner).first;
795 DoLog(0) && (Log() << Verbose(0) << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl);
796 BondFragments->insert(StoreFragmentFromKeySet(test, World::getInstance().getConfig()));
797 k++;
798 }
799 DoLog(0) && (Log() << Verbose(0) << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl);
800
801 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
802 if (BondFragments->ListOfMolecules.size() != 0) {
803 // create the SortIndex from BFS labels to order in the config file
804 int *SortIndex = NULL;
805 CreateMappingLabelsToConfigSequence(SortIndex);
806
807 DoLog(1) && (Log() << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl);
808 if (BondFragments->OutputConfigForListOfFragments(prefix, SortIndex))
809 DoLog(1) && (Log() << Verbose(1) << "All configs written." << endl);
810 else
811 DoLog(1) && (Log() << Verbose(1) << "Some config writing failed." << endl);
812
813 // store force index reference file
814 BondFragments->StoreForcesFile(prefix, SortIndex);
815
816 // store keysets file
817 StoreKeySetFile(TotalGraph, prefix);
818
819 {
820 // store Adjacency file
821 std::string filename = prefix + ADJACENCYFILE;
822 StoreAdjacencyToFile(filename);
823 }
824
825 // store Hydrogen saturation correction file
826 BondFragments->AddHydrogenCorrection(prefix);
827
828 // store adaptive orders into file
829 StoreOrderAtSiteFile(prefix);
830
831 // restore orbital and Stop values
832 //CalculateOrbitals(*configuration);
833
834 // free memory for bond part
835 DoLog(1) && (Log() << Verbose(1) << "Freeing bond memory" << endl);
836 delete[](SortIndex);
837 } else {
838 DoLog(1) && (Log() << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl);
839 }
840 // remove all create molecules again from the World including their atoms
841 for (MoleculeList::iterator iter = BondFragments->ListOfMolecules.begin();
842 !BondFragments->ListOfMolecules.empty();
843 iter = BondFragments->ListOfMolecules.begin()) {
844 // remove copied atoms and molecule again
845 molecule *mol = *iter;
846 mol->removeAtomsinMolecule();
847 World::getInstance().destroyMolecule(mol);
848 BondFragments->ListOfMolecules.erase(iter);
849 }
850 delete(BondFragments);
851 DoLog(0) && (Log() << Verbose(0) << "End of bond fragmentation." << endl);
852
853 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
854};
855
856
857/** Stores pairs (Atom::Nr, Atom::AdaptiveOrder) into file.
858 * Atoms not present in the file get "-1".
859 * \param &path path to file ORDERATSITEFILE
860 * \return true - file writable, false - not writable
861 */
862bool molecule::StoreOrderAtSiteFile(std::string &path)
863{
864 string line;
865 ofstream file;
866
867 line = path + ORDERATSITEFILE;
868 file.open(line.c_str());
869 DoLog(1) && (Log() << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl);
870 if (file.good()) {
871 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputOrder), &file));
872 file.close();
873 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
874 return true;
875 } else {
876 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line << "." << endl);
877 return false;
878 }
879};
880
881/** Parses pairs(Atom::Nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
882 * Atoms not present in the file get "0".
883 * \param &path path to file ORDERATSITEFILEe
884 * \return true - file found and scanned, false - file not found
885 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
886 */
887bool molecule::ParseOrderAtSiteFromFile(std::string &path)
888{
889 unsigned char *OrderArray = new unsigned char[getAtomCount()];
890 bool *MaxArray = new bool[getAtomCount()];
891 bool status;
892 int AtomNr, value;
893 string line;
894 ifstream file;
895
896 for(int i=0;i<getAtomCount();i++) {
897 OrderArray[i] = 0;
898 MaxArray[i] = false;
899 }
900
901 DoLog(1) && (Log() << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl);
902 line = path + ORDERATSITEFILE;
903 file.open(line.c_str());
904 if (file.good()) {
905 while (!file.eof()) { // parse from file
906 AtomNr = -1;
907 file >> AtomNr;
908 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
909 file >> value;
910 OrderArray[AtomNr] = value;
911 file >> value;
912 MaxArray[AtomNr] = value;
913 //Log() << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
914 }
915 }
916 file.close();
917
918 // set atom values
919 for(internal_iterator iter=atoms.begin();iter!=atoms.end();++iter){
920 (*iter)->AdaptiveOrder = OrderArray[(*iter)->getNr()];
921 (*iter)->MaxOrder = MaxArray[(*iter)->getNr()];
922 }
923 //SetAtomValueToIndexedArray( OrderArray, &atom::getNr(), &atom::AdaptiveOrder );
924 //SetAtomValueToIndexedArray( MaxArray, &atom::getNr(), &atom::MaxOrder );
925
926 DoLog(1) && (Log() << Verbose(1) << "\t ... done." << endl);
927 status = true;
928 } else {
929 DoLog(1) && (Log() << Verbose(1) << "\t ... failed to open file " << line << "." << endl);
930 status = false;
931 }
932 delete[](OrderArray);
933 delete[](MaxArray);
934
935 DoLog(1) && (Log() << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl);
936 return status;
937};
938
939
940
941/** Looks through a std::deque<atom *> and returns the likeliest removal candiate.
942 * \param *out output stream for debugging messages
943 * \param *&Leaf KeySet to look through
944 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
945 * \param index of the atom suggested for removal
946 */
947int molecule::LookForRemovalCandidate(KeySet *&Leaf, int *&ShortestPathList)
948{
949 atom *Runner = NULL;
950 int SP, Removal;
951
952 DoLog(2) && (Log() << Verbose(2) << "Looking for removal candidate." << endl);
953 SP = -1; //0; // not -1, so that Root is never removed
954 Removal = -1;
955 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
956 Runner = FindAtom((*runner));
957 if (Runner->getType()->getAtomicNumber() != 1) { // skip all those added hydrogens when re-filling snake stack
958 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
959 SP = ShortestPathList[(*runner)];
960 Removal = (*runner);
961 }
962 }
963 }
964 return Removal;
965};
966
967/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
968 * \param *mol total molecule
969 * \param *Leaf fragment molecule
970 * \param &Leaflet pointer to KeySet structure
971 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
972 * \return number of atoms in fragment
973 */
974int StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
975{
976 atom *FatherOfRunner = NULL;
977
978 // first create the minimal set of atoms from the KeySet
979 int size = 0;
980 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
981 FatherOfRunner = mol->FindAtom((*runner)); // find the id
982 SonList[FatherOfRunner->getNr()] = Leaf->AddCopyAtom(FatherOfRunner);
983 size++;
984 }
985 return size;
986};
987
988/** Creates an induced subgraph out of a fragmental key set, adding bonds and hydrogens (if treated specially).
989 * \param *out output stream for debugging messages
990 * \param *mol total molecule
991 * \param *Leaf fragment molecule
992 * \param IsAngstroem whether we have Ansgtroem or bohrradius
993 * \param **SonList list which atom of \a *Leaf is a son of which atom in \a *mol
994 */
995void CreateInducedSubgraphOfFragment(molecule *mol, molecule *Leaf, atom **SonList, bool IsAngstroem)
996{
997 bool LonelyFlag = false;
998 atom *OtherFather = NULL;
999 atom *FatherOfRunner = NULL;
1000
1001#ifdef ADDHYDROGEN
1002 molecule::const_iterator runner;
1003#endif
1004 // we increment the iter just before skipping the hydrogen
1005 for (molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end();) {
1006 LonelyFlag = true;
1007 FatherOfRunner = (*iter)->father;
1008 ASSERT(FatherOfRunner,"Atom without father found");
1009 if (SonList[FatherOfRunner->getNr()] != NULL) { // check if this, our father, is present in list
1010 // create all bonds
1011 const BondList& ListOfBonds = FatherOfRunner->getListOfBonds();
1012 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
1013 BondRunner != ListOfBonds.end();
1014 ++BondRunner) {
1015 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
1016// Log() << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->getNr()] << " is bound to " << *OtherFather;
1017 if (SonList[OtherFather->getNr()] != NULL) {
1018// Log() << Verbose(0) << ", whose son is " << *SonList[OtherFather->getNr()] << "." << endl;
1019 if (OtherFather->getNr() > FatherOfRunner->getNr()) { // add bond (Nr check is for adding only one of both variants: ab, ba)
1020// Log() << Verbose(3) << "Adding Bond: ";
1021// Log() << Verbose(0) <<
1022 Leaf->AddBond((*iter), SonList[OtherFather->getNr()], (*BondRunner)->BondDegree);
1023// Log() << Verbose(0) << "." << endl;
1024 //NumBonds[(*iter)->getNr()]++;
1025 } else {
1026// Log() << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
1027 }
1028 LonelyFlag = false;
1029 } else {
1030// Log() << Verbose(0) << ", who has no son in this fragment molecule." << endl;
1031#ifdef ADDHYDROGEN
1032 //Log() << Verbose(3) << "Adding Hydrogen to " << (*iter)->Name << " and a bond in between." << endl;
1033 if(!Leaf->AddHydrogenReplacementAtom((*BondRunner), (*iter), FatherOfRunner, OtherFather, IsAngstroem))
1034 exit(1);
1035#endif
1036 //NumBonds[(*iter)->getNr()] += Binder->BondDegree;
1037 }
1038 }
1039 } else {
1040 DoeLog(1) && (eLog()<< Verbose(1) << "Son " << (*iter)->getName() << " has father " << FatherOfRunner->getName() << " but its entry in SonList is " << SonList[FatherOfRunner->getNr()] << "!" << endl);
1041 }
1042 if ((LonelyFlag) && (Leaf->getAtomCount() > 1)) {
1043 DoLog(0) && (Log() << Verbose(0) << **iter << "has got bonds only to hydrogens!" << endl);
1044 }
1045 ++iter;
1046#ifdef ADDHYDROGEN
1047 while ((iter != Leaf->end()) && ((*iter)->getType()->getAtomicNumber() == 1)){ // skip added hydrogen
1048 iter++;
1049 }
1050#endif
1051 }
1052};
1053
1054/** Stores a fragment from \a KeySet into \a molecule.
1055 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
1056 * molecule and adds missing hydrogen where bonds were cut.
1057 * \param *out output stream for debugging messages
1058 * \param &Leaflet pointer to KeySet structure
1059 * \param IsAngstroem whether we have Ansgtroem or bohrradius
1060 * \return pointer to constructed molecule
1061 */
1062molecule * molecule::StoreFragmentFromKeySet(KeySet &Leaflet, bool IsAngstroem)
1063{
1064 atom **SonList = new atom*[getAtomCount()];
1065 molecule *Leaf = World::getInstance().createMolecule();
1066
1067 for(int i=0;i<getAtomCount();i++)
1068 SonList[i] = NULL;
1069
1070// Log() << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
1071 StoreFragmentFromKeySet_Init(this, Leaf, Leaflet, SonList);
1072 // create the bonds between all: Make it an induced subgraph and add hydrogen
1073// Log() << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
1074 CreateInducedSubgraphOfFragment(this, Leaf, SonList, IsAngstroem);
1075
1076 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
1077 delete[](SonList);
1078// Log() << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
1079 return Leaf;
1080};
1081
1082
1083/** Clears the touched list
1084 * \param *out output stream for debugging
1085 * \param verbosity verbosity level
1086 * \param *&TouchedList touched list
1087 * \param SubOrder current suborder
1088 * \param TouchedIndex currently touched
1089 */
1090void SPFragmentGenerator_ClearingTouched(int verbosity, int *&TouchedList, int SubOrder, int &TouchedIndex)
1091{
1092 Log() << Verbose(1+verbosity) << "Clearing touched list." << endl;
1093 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
1094 TouchedList[TouchedIndex] = -1;
1095 TouchedIndex = 0;
1096
1097}
1098
1099/** Adds the current combination of the power set to the snake stack.
1100 * \param *out output stream for debugging
1101 * \param verbosity verbosity level
1102 * \param CurrentCombination
1103 * \param SetDimension maximum number of bits in power set
1104 * \param *FragmentSet snake stack to remove from
1105 * \param &BondsSet set of bonds
1106 * \param *&TouchedList touched list
1107 * \param TouchedIndex currently touched
1108 * \return number of set bits
1109 */
1110int AddPowersetToSnakeStack(int verbosity, int CurrentCombination, int SetDimension, KeySet *FragmentSet, std::vector<bond *> &BondsSet, int *&TouchedList, int &TouchedIndex)
1111{
1112 atom *OtherWalker = NULL;
1113 bool bit = false;
1114 KeySetTestPair TestKeySetInsert;
1115
1116 int Added = 0;
1117 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
1118 bit = ((CurrentCombination & (1 << j)) != 0); // mask the bit for the j-th bond
1119 if (bit) { // if bit is set, we add this bond partner
1120 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
1121 //Log() << Verbose(1+verbosity) << "Current Bond is " << BondsSet[j] << ", checking on " << *OtherWalker << "." << endl;
1122 Log() << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->getNr() << "." << endl;
1123 TestKeySetInsert = FragmentSet->insert(OtherWalker->getNr());
1124 if (TestKeySetInsert.second) {
1125 TouchedList[TouchedIndex++] = OtherWalker->getNr(); // note as added
1126 Added++;
1127 } else {
1128 Log() << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
1129 }
1130 } else {
1131 Log() << Verbose(2+verbosity) << "Not adding." << endl;
1132 }
1133 }
1134 return Added;
1135};
1136
1137/** Counts the number of elements in a power set.
1138 * \param SetFirst begin iterator first bond
1139 * \param SetLast end iterator
1140 * \param *&TouchedList touched list
1141 * \param TouchedIndex currently touched
1142 * \return number of elements
1143 */
1144int CountSetMembers(std::list<bond *>::const_iterator SetFirst, std::list<bond *>::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
1145{
1146 int SetDimension = 0;
1147 for( std::list<bond *>::const_iterator Binder = SetFirst;
1148 Binder != SetLast;
1149 ++Binder) {
1150 for (int k=TouchedIndex;k--;) {
1151 if ((*Binder)->Contains(TouchedList[k])) // if we added this very endpiece
1152 SetDimension++;
1153 }
1154 }
1155 return SetDimension;
1156};
1157
1158/** Fills a list of bonds from another
1159 * \param *BondsList bonds array/vector to fill
1160 * \param SetFirst begin iterator first bond
1161 * \param SetLast end iterator
1162 * \param *&TouchedList touched list
1163 * \param TouchedIndex currently touched
1164 * \return number of elements
1165 */
1166int FillBondsList(std::vector<bond *> &BondsList, std::list<bond *>::const_iterator SetFirst, std::list<bond *>::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
1167{
1168 int SetDimension = 0;
1169 for( std::list<bond *>::const_iterator Binder = SetFirst;
1170 Binder != SetLast;
1171 ++Binder) {
1172 for (int k=0;k<TouchedIndex;k++) {
1173 if ((*Binder)->leftatom->getNr() == TouchedList[k]) // leftatom is always the closer one
1174 BondsList[SetDimension++] = (*Binder);
1175 }
1176 }
1177 return SetDimension;
1178};
1179
1180/** Remove all items that were added on this SP level.
1181 * \param *out output stream for debugging
1182 * \param verbosity verbosity level
1183 * \param *FragmentSet snake stack to remove from
1184 * \param *&TouchedList touched list
1185 * \param TouchedIndex currently touched
1186 */
1187void RemoveAllTouchedFromSnakeStack(int verbosity, KeySet *FragmentSet, int *&TouchedList, int &TouchedIndex)
1188{
1189 int Removal = 0;
1190 for(int j=0;j<TouchedIndex;j++) {
1191 Removal = TouchedList[j];
1192 Log() << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
1193 FragmentSet->erase(Removal);
1194 TouchedList[j] = -1;
1195 }
1196 DoLog(2) && (Log() << Verbose(2) << "Remaining local nr.s on snake stack are: ");
1197 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
1198 DoLog(0) && (Log() << Verbose(0) << (*runner) << " ");
1199 DoLog(0) && (Log() << Verbose(0) << endl);
1200 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
1201};
1202
1203/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
1204 * -# loops over every possible combination (2^dimension of edge set)
1205 * -# inserts current set, if there's still space left
1206 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
1207ance+1
1208 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
1209 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
1210distance) and current set
1211 * \param FragmentSearch UniqueFragments structure with all values needed
1212 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
1213 * \param BondsSet array of bonds to check
1214 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
1215 * \param SubOrder remaining number of allowed vertices to add
1216 */
1217void molecule::SPFragmentGenerator(struct UniqueFragments *FragmentSearch, int RootDistance, std::vector<bond *> &BondsSet, int SetDimension, int SubOrder)
1218{
1219 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
1220 int NumCombinations;
1221 int bits, TouchedIndex, SubSetDimension, SP, Added;
1222 int SpaceLeft;
1223 int *TouchedList = new int[SubOrder + 1];
1224 KeySetTestPair TestKeySetInsert;
1225
1226 NumCombinations = 1 << SetDimension;
1227
1228 // here for all bonds of Walker all combinations of end pieces (from the bonds)
1229 // have to be added and for the remaining ANOVA order GraphCrawler be called
1230 // recursively for the next level
1231
1232 Log() << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
1233 Log() << Verbose(1+verbosity) << "We are " << RootDistance << " away from Root, which is " << *FragmentSearch->Root << ", SubOrder is " << SubOrder << ", SetDimension is " << SetDimension << " and this means " << NumCombinations-1 << " combination(s)." << endl;
1234
1235 // initialised touched list (stores added atoms on this level)
1236 SPFragmentGenerator_ClearingTouched(verbosity, TouchedList, SubOrder, TouchedIndex);
1237
1238 // create every possible combination of the endpieces
1239 Log() << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
1240 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
1241 // count the set bit of i
1242 bits = 0;
1243 for (int j=SetDimension;j--;)
1244 bits += (i & (1 << j)) >> j;
1245
1246 Log() << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
1247 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
1248 // --1-- add this set of the power set of bond partners to the snake stack
1249 Added = AddPowersetToSnakeStack(verbosity, i, SetDimension, FragmentSearch->FragmentSet, BondsSet, TouchedList, TouchedIndex);
1250
1251 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
1252 if (SpaceLeft > 0) {
1253 Log() << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
1254 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
1255 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
1256 SP = RootDistance+1; // this is the next level
1257
1258 // first count the members in the subset
1259 SubSetDimension = CountSetMembers(FragmentSearch->BondsPerSPList[SP].begin(), FragmentSearch->BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
1260
1261 // then allocate and fill the list
1262 std::vector<bond *> BondsList;
1263 BondsList.resize(SubSetDimension);
1264 SubSetDimension = FillBondsList(BondsList, FragmentSearch->BondsPerSPList[SP].begin(), FragmentSearch->BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
1265
1266 // then iterate
1267 Log() << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
1268 SPFragmentGenerator(FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
1269 }
1270 } else {
1271 // --2-- otherwise store the complete fragment
1272 Log() << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
1273 // store fragment as a KeySet
1274 DoLog(2) && (Log() << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ");
1275 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
1276 DoLog(0) && (Log() << Verbose(0) << (*runner) << " ");
1277 DoLog(0) && (Log() << Verbose(0) << endl);
1278 //if (!CheckForConnectedSubgraph(FragmentSearch->FragmentSet))
1279 //DoeLog(1) && (eLog()<< Verbose(1) << "The found fragment is not a connected subgraph!" << endl);
1280 InsertFragmentIntoGraph(FragmentSearch);
1281 }
1282
1283 // --3-- remove all added items in this level from snake stack
1284 Log() << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
1285 RemoveAllTouchedFromSnakeStack(verbosity, FragmentSearch->FragmentSet, TouchedList, TouchedIndex);
1286 } else {
1287 Log() << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
1288 }
1289 }
1290 delete[](TouchedList);
1291 Log() << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
1292};
1293
1294/** Allocates memory for UniqueFragments::BondsPerSPList.
1295 * \param *out output stream
1296 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1297 * \param FragmentSearch UniqueFragments
1298 * \sa FreeSPList()
1299 */
1300void InitialiseSPList(int Order, struct UniqueFragments &FragmentSearch)
1301{
1302 FragmentSearch.BondsPerSPList.resize(Order);
1303 FragmentSearch.BondsPerSPCount = new int[Order];
1304 for (int i=Order;i--;) {
1305 FragmentSearch.BondsPerSPCount[i] = 0;
1306 }
1307};
1308
1309/** Free's memory for for UniqueFragments::BondsPerSPList.
1310 * \param *out output stream
1311 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1312 * \param FragmentSearch UniqueFragments\
1313 * \sa InitialiseSPList()
1314 */
1315void FreeSPList(int Order, struct UniqueFragments &FragmentSearch)
1316{
1317 delete[](FragmentSearch.BondsPerSPCount);
1318};
1319
1320/** Sets FragmenSearch to initial value.
1321 * Sets UniqueFragments::ShortestPathList entries to zero, UniqueFragments::BondsPerSPCount to zero (except zero level to 1) and
1322 * adds initial bond UniqueFragments::Root to UniqueFragments::Root to UniqueFragments::BondsPerSPList
1323 * \param *out output stream
1324 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1325 * \param FragmentSearch UniqueFragments
1326 * \sa FreeSPList()
1327 */
1328void SetSPList(int Order, struct UniqueFragments &FragmentSearch)
1329{
1330 // prepare Label and SP arrays of the BFS search
1331 FragmentSearch.ShortestPathList[FragmentSearch.Root->getNr()] = 0;
1332
1333 // prepare root level (SP = 0) and a loop bond denoting Root
1334 for (int i=Order;i--;)
1335 FragmentSearch.BondsPerSPCount[i] = 0;
1336 FragmentSearch.BondsPerSPCount[0] = 1;
1337 bond *Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
1338 FragmentSearch.BondsPerSPList[0].push_back(Binder);
1339};
1340
1341/** Resets UniqueFragments::ShortestPathList and cleans bonds from UniqueFragments::BondsPerSPList.
1342 * \param *out output stream
1343 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1344 * \param FragmentSearch UniqueFragments
1345 * \sa InitialiseSPList()
1346 */
1347void ResetSPList(int Order, struct UniqueFragments &FragmentSearch)
1348{
1349 DoLog(0) && (Log() << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl);
1350 for(int i=Order;i--;) {
1351 DoLog(1) && (Log() << Verbose(1) << "Current SP level is " << i << ": ");
1352 for (UniqueFragments::BondsPerSP::const_iterator iter = FragmentSearch.BondsPerSPList[i].begin();
1353 iter != FragmentSearch.BondsPerSPList[i].end();
1354 ++iter) {
1355 // Log() << Verbose(0) << "Removing atom " << Binder->leftatom->getNr() << " and " << Binder->rightatom->getNr() << "." << endl; // make sure numbers are local
1356 FragmentSearch.ShortestPathList[(*iter)->leftatom->getNr()] = -1;
1357 FragmentSearch.ShortestPathList[(*iter)->rightatom->getNr()] = -1;
1358 }
1359 // delete added bonds
1360 for (UniqueFragments::BondsPerSP::iterator iter = FragmentSearch.BondsPerSPList[i].begin();
1361 iter != FragmentSearch.BondsPerSPList[i].end();
1362 ++iter) {
1363 delete(*iter);
1364 }
1365 FragmentSearch.BondsPerSPList[i].clear();
1366 // also start and end node
1367 DoLog(0) && (Log() << Verbose(0) << "cleaned." << endl);
1368 }
1369};
1370
1371
1372/** Fills the Bonds per Shortest Path List and set the vertex labels.
1373 * \param *out output stream
1374 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1375 * \param FragmentSearch UniqueFragments
1376 * \param *mol molecule with atoms and bonds
1377 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
1378 */
1379void FillSPListandLabelVertices(int Order, struct UniqueFragments &FragmentSearch, molecule *mol, KeySet RestrictedKeySet)
1380{
1381 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into
1382 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning
1383 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth
1384 // (EdgeinSPLevel) of this tree ...
1385 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence
1386 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction.
1387 int AtomKeyNr = -1;
1388 atom *Walker = NULL;
1389 atom *OtherWalker = NULL;
1390 atom *Predecessor = NULL;
1391 bond *Binder = NULL;
1392 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->getNr();
1393 int RemainingWalkers = -1;
1394 int SP = -1;
1395
1396 DoLog(0) && (Log() << Verbose(0) << "Starting BFS analysis ..." << endl);
1397 for (SP = 0; SP < (Order-1); SP++) {
1398 DoLog(1) && (Log() << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)");
1399 if (SP > 0) {
1400 DoLog(0) && (Log() << Verbose(0) << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl);
1401 FragmentSearch.BondsPerSPCount[SP] = 0;
1402 } else
1403 DoLog(0) && (Log() << Verbose(0) << "." << endl);
1404
1405 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
1406 for (UniqueFragments::BondsPerSP::const_iterator CurrentEdge = FragmentSearch.BondsPerSPList[SP].begin();
1407 CurrentEdge != FragmentSearch.BondsPerSPList[SP].end();
1408 ++CurrentEdge) { /// start till end of this SP level's list
1409 RemainingWalkers--;
1410 Walker = (*CurrentEdge)->rightatom; // rightatom is always the one more distant
1411 Predecessor = (*CurrentEdge)->leftatom; // ... and leftatom is predecessor
1412 AtomKeyNr = Walker->getNr();
1413 DoLog(0) && (Log() << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->getNr() << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl);
1414 // check for new sp level
1415 // go through all its bonds
1416 DoLog(1) && (Log() << Verbose(1) << "Going through all bonds of Walker." << endl);
1417 const BondList& ListOfBonds = Walker->getListOfBonds();
1418 for (BondList::const_iterator Runner = ListOfBonds.begin();
1419 Runner != ListOfBonds.end();
1420 ++Runner) {
1421 OtherWalker = (*Runner)->GetOtherAtom(Walker);
1422 if ((RestrictedKeySet.find(OtherWalker->getNr()) != RestrictedKeySet.end())
1423 #ifdef ADDHYDROGEN
1424 && (OtherWalker->getType()->getAtomicNumber() != 1)
1425 #endif
1426 ) { // skip hydrogens and restrict to fragment
1427 DoLog(2) && (Log() << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->getNr() << " in bond " << *(*Runner) << "." << endl);
1428 // set the label if not set (and push on root stack as well)
1429 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->getNr() > RootKeyNr)) { // only pass through those with label bigger than Root's
1430 FragmentSearch.ShortestPathList[OtherWalker->getNr()] = SP+1;
1431 DoLog(3) && (Log() << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->getNr()] << "." << endl);
1432 // add the bond in between to the SP list
1433 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
1434 FragmentSearch.BondsPerSPList[SP+1].push_back(Binder);
1435 FragmentSearch.BondsPerSPCount[SP+1]++;
1436 DoLog(3) && (Log() << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl);
1437 } else {
1438 if (OtherWalker != Predecessor)
1439 DoLog(3) && (Log() << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->getNr() << " is smaller than that of Root " << RootKeyNr << "." << endl);
1440 else
1441 DoLog(3) && (Log() << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl);
1442 }
1443 } else Log() << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
1444 }
1445 }
1446 }
1447};
1448
1449/** prints the Bonds per Shortest Path list in UniqueFragments.
1450 * \param *out output stream
1451 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1452 * \param FragmentSearch UniqueFragments
1453 */
1454void OutputSPList(int Order, struct UniqueFragments &FragmentSearch)
1455{
1456 DoLog(0) && (Log() << Verbose(0) << "Printing all found lists." << endl);
1457 for(int i=1;i<Order;i++) { // skip the root edge in the printing
1458 DoLog(1) && (Log() << Verbose(1) << "Current SP level is " << i << "." << endl);
1459 for (UniqueFragments::BondsPerSP::const_iterator Binder = FragmentSearch.BondsPerSPList[i].begin();
1460 Binder != FragmentSearch.BondsPerSPList[i].end();
1461 ++Binder) {
1462 DoLog(2) && (Log() << Verbose(2) << *Binder << endl);
1463 }
1464 }
1465};
1466
1467/** Simply counts all bonds in all UniqueFragments::BondsPerSPList lists.
1468 * \param *out output stream
1469 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1470 * \param FragmentSearch UniqueFragments
1471 */
1472int CountNumbersInBondsList(int Order, struct UniqueFragments &FragmentSearch)
1473{
1474 int SP = -1; // the Root <-> Root edge must be subtracted!
1475 for(int i=Order;i--;) { // sum up all found edges
1476 for (UniqueFragments::BondsPerSP::const_iterator Binder = FragmentSearch.BondsPerSPList[i].begin();
1477 Binder != FragmentSearch.BondsPerSPList[i].end();
1478 ++Binder) {
1479 SP++;
1480 }
1481 }
1482 return SP;
1483};
1484
1485/** Creates a list of all unique fragments of certain vertex size from a given graph \a Fragment for a given root vertex in the context of \a this molecule.
1486 * -# initialises UniqueFragments structure
1487 * -# fills edge list via BFS
1488 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
1489 root distance, the edge set, its dimension and the current suborder
1490 * -# Free'ing structure
1491 * Note that we may use the fact that the atoms are SP-ordered on the atomstack. I.e. when popping always the last, we first get all
1492 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
1493 * \param *out output stream for debugging
1494 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1495 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
1496 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
1497 * \return number of inserted fragments
1498 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
1499 */
1500int molecule::PowerSetGenerator(int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
1501{
1502 int Counter = FragmentSearch.FragmentCounter; // mark current value of counter
1503
1504 DoLog(0) && (Log() << Verbose(0) << endl);
1505 DoLog(0) && (Log() << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl);
1506
1507 SetSPList(Order, FragmentSearch);
1508
1509 // do a BFS search to fill the SP lists and label the found vertices
1510 FillSPListandLabelVertices(Order, FragmentSearch, this, RestrictedKeySet);
1511
1512 // outputting all list for debugging
1513 OutputSPList(Order, FragmentSearch);
1514
1515 // creating fragments with the found edge sets (may be done in reverse order, faster)
1516 int SP = CountNumbersInBondsList(Order, FragmentSearch);
1517 DoLog(0) && (Log() << Verbose(0) << "Total number of edges is " << SP << "." << endl);
1518 if (SP >= (Order-1)) {
1519 // start with root (push on fragment stack)
1520 DoLog(0) && (Log() << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->getNr() << "." << endl);
1521 FragmentSearch.FragmentSet->clear();
1522 DoLog(0) && (Log() << Verbose(0) << "Preparing subset for this root and calling generator." << endl);
1523
1524 // prepare the subset and call the generator
1525 std::vector<bond*> BondsList;
1526 BondsList.resize(FragmentSearch.BondsPerSPCount[0]);
1527 ASSERT(FragmentSearch.BondsPerSPList[0].size() != 0,
1528 "molecule::PowerSetGenerator() - FragmentSearch.BondsPerSPList[0] contains no root bond.");
1529 BondsList[0] = (*FragmentSearch.BondsPerSPList[0].begin()); // on SP level 0 there's only the root bond
1530
1531 SPFragmentGenerator(&FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
1532 } else {
1533 DoLog(0) && (Log() << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl);
1534 }
1535
1536 // as FragmentSearch structure is used only once, we don't have to clean it anymore
1537 // remove root from stack
1538 DoLog(0) && (Log() << Verbose(0) << "Removing root again from stack." << endl);
1539 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->getNr());
1540
1541 // free'ing the bonds lists
1542 ResetSPList(Order, FragmentSearch);
1543
1544 // return list
1545 DoLog(0) && (Log() << Verbose(0) << "End of PowerSetGenerator." << endl);
1546 return (FragmentSearch.FragmentCounter - Counter);
1547};
1548
1549bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
1550{
1551 //Log() << Verbose(0) << "my check is used." << endl;
1552 if (SubgraphA.size() < SubgraphB.size()) {
1553 return true;
1554 } else {
1555 if (SubgraphA.size() > SubgraphB.size()) {
1556 return false;
1557 } else {
1558 KeySet::iterator IteratorA = SubgraphA.begin();
1559 KeySet::iterator IteratorB = SubgraphB.begin();
1560 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
1561 if ((*IteratorA) < (*IteratorB))
1562 return true;
1563 else if ((*IteratorA) > (*IteratorB)) {
1564 return false;
1565 } // else, go on to next index
1566 IteratorA++;
1567 IteratorB++;
1568 } // end of while loop
1569 }// end of check in case of equal sizes
1570 }
1571 return false; // if we reach this point, they are equal
1572};
1573
1574
1575/** Combines all KeySets from all orders into single ones (with just unique entries).
1576 * \param *out output stream for debugging
1577 * \param *&FragmentList list to fill
1578 * \param ***FragmentLowerOrdersList
1579 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1580 * \param *mol molecule with atoms and bonds
1581 */
1582int CombineAllOrderListIntoOne(Graph *&FragmentList, Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol)
1583{
1584 int RootNr = 0;
1585 int RootKeyNr = 0;
1586 int StartNr = 0;
1587 int counter = 0;
1588 int NumLevels = 0;
1589 atom *Walker = NULL;
1590
1591 DoLog(0) && (Log() << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl);
1592 if (FragmentList == NULL) {
1593 FragmentList = new Graph;
1594 counter = 0;
1595 } else {
1596 counter = FragmentList->size();
1597 }
1598
1599 StartNr = RootStack.back();
1600 do {
1601 RootKeyNr = RootStack.front();
1602 RootStack.pop_front();
1603 Walker = mol->FindAtom(RootKeyNr);
1604 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
1605 for(int i=0;i<NumLevels;i++) {
1606 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
1607 InsertGraphIntoGraph(*FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
1608 }
1609 }
1610 RootStack.push_back(Walker->getNr());
1611 RootNr++;
1612 } while (RootKeyNr != StartNr);
1613 return counter;
1614};
1615
1616/** Free's memory allocated for all KeySets from all orders.
1617 * \param *out output stream for debugging
1618 * \param ***FragmentLowerOrdersList
1619 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1620 * \param *mol molecule with atoms and bonds
1621 */
1622void FreeAllOrdersList(Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol)
1623{
1624 DoLog(1) && (Log() << Verbose(1) << "Free'ing the lists of all orders per order." << endl);
1625 int RootNr = 0;
1626 int RootKeyNr = 0;
1627 int NumLevels = 0;
1628 atom *Walker = NULL;
1629 while (!RootStack.empty()) {
1630 RootKeyNr = RootStack.front();
1631 RootStack.pop_front();
1632 Walker = mol->FindAtom(RootKeyNr);
1633 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
1634 for(int i=0;i<NumLevels;i++) {
1635 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
1636 delete(FragmentLowerOrdersList[RootNr][i]);
1637 }
1638 }
1639 delete[](FragmentLowerOrdersList[RootNr]);
1640 RootNr++;
1641 }
1642 delete[](FragmentLowerOrdersList);
1643};
1644
1645
1646/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
1647 * -# constructs a complete keyset of the molecule
1648 * -# In a loop over all possible roots from the given rootstack
1649 * -# increases order of root site
1650 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
1651 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
1652as the restricted one and each site in the set as the root)
1653 * -# these are merged into a fragment list of keysets
1654 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
1655 * Important only is that we create all fragments, it is not important if we create them more than once
1656 * as these copies are filtered out via use of the hash table (KeySet).
1657 * \param *out output stream for debugging
1658 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
1659 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1660 * \param *MinimumRingSize minimum ring size for each atom (molecule::Atomcount)
1661 * \return pointer to Graph list
1662 */
1663void molecule::FragmentBOSSANOVA(Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize)
1664{
1665 Graph ***FragmentLowerOrdersList = NULL;
1666 int NumLevels = 0;
1667 int NumMolecules = 0;
1668 int TotalNumMolecules = 0;
1669 int *NumMoleculesOfOrder = NULL;
1670 int Order = 0;
1671 int UpgradeCount = RootStack.size();
1672 KeyStack FragmentRootStack;
1673 int RootKeyNr = 0;
1674 int RootNr = 0;
1675 struct UniqueFragments FragmentSearch;
1676
1677 DoLog(0) && (Log() << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl);
1678
1679 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
1680 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
1681 NumMoleculesOfOrder = new int[UpgradeCount];
1682 FragmentLowerOrdersList = new Graph**[UpgradeCount];
1683
1684 for(int i=0;i<UpgradeCount;i++) {
1685 NumMoleculesOfOrder[i] = 0;
1686 FragmentLowerOrdersList[i] = NULL;
1687 }
1688
1689 // initialise the fragments structure
1690 FragmentSearch.FragmentCounter = 0;
1691 FragmentSearch.FragmentSet = new KeySet;
1692 FragmentSearch.Root = FindAtom(RootKeyNr);
1693 FragmentSearch.ShortestPathList = new int[getAtomCount()];
1694 for (int i=getAtomCount();i--;) {
1695 FragmentSearch.ShortestPathList[i] = -1;
1696 }
1697
1698 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
1699 KeySet CompleteMolecule;
1700 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
1701 CompleteMolecule.insert((*iter)->GetTrueFather()->getNr());
1702 }
1703
1704 // this can easily be seen: if Order is 5, then the number of levels for each lower order is the total sum of the number of levels above, as
1705 // each has to be split up. E.g. for the second level we have one from 5th, one from 4th, two from 3th (which in turn is one from 5th, one from 4th),
1706 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
1707 // with the order along the cells as this: 5433222211111111 for BondOrder 5 needing 16=pow(2,5-1) cells (only we use bit-shifting which is faster)
1708 RootNr = 0; // counts through the roots in RootStack
1709 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
1710 RootKeyNr = RootStack.front();
1711 RootStack.pop_front();
1712 atom *Walker = FindAtom(RootKeyNr);
1713 // check cyclic lengths
1714 //if ((MinimumRingSize[Walker->GetTrueFather()->getNr()] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->getNr()])) {
1715 // Log() << Verbose(0) << "Bond order " << Walker->GetTrueFather()->AdaptiveOrder << " of Root " << *Walker << " greater than or equal to Minimum Ring size of " << MinimumRingSize << " found is not allowed." << endl;
1716 //} else
1717 {
1718 // increase adaptive order by one
1719 Walker->GetTrueFather()->AdaptiveOrder++;
1720 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
1721
1722 // initialise Order-dependent entries of UniqueFragments structure
1723 InitialiseSPList(Order, FragmentSearch);
1724
1725 // allocate memory for all lower level orders in this 1D-array of ptrs
1726 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
1727 FragmentLowerOrdersList[RootNr] = new Graph*[NumLevels];
1728 for (int i=0;i<NumLevels;i++)
1729 FragmentLowerOrdersList[RootNr][i] = NULL;
1730
1731 // create top order where nothing is reduced
1732 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1733 DoLog(0) && (Log() << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl); // , NumLevels is " << NumLevels << "
1734
1735 // Create list of Graphs of current Bond Order (i.e. F_{ij})
1736 FragmentLowerOrdersList[RootNr][0] = new Graph;
1737 FragmentSearch.TEFactor = 1.;
1738 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
1739 FragmentSearch.Root = Walker;
1740 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
1741
1742 // output resulting number
1743 DoLog(1) && (Log() << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl);
1744 if (NumMoleculesOfOrder[RootNr] != 0) {
1745 NumMolecules = 0;
1746 } else {
1747 Walker->GetTrueFather()->MaxOrder = true;
1748 }
1749 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
1750 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
1751 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
1752// Log() << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
1753 RootStack.push_back(RootKeyNr); // put back on stack
1754 RootNr++;
1755
1756 // free Order-dependent entries of UniqueFragments structure for next loop cycle
1757 FreeSPList(Order, FragmentSearch);
1758 }
1759 }
1760 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1761 DoLog(1) && (Log() << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl);
1762 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1763
1764 // cleanup FragmentSearch structure
1765 delete[](FragmentSearch.ShortestPathList);
1766 delete(FragmentSearch.FragmentSet);
1767
1768 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
1769 // 5433222211111111
1770 // 43221111
1771 // 3211
1772 // 21
1773 // 1
1774
1775 // Subsequently, we combine all into a single list (FragmentList)
1776 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, this);
1777 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, this);
1778 delete[](NumMoleculesOfOrder);
1779
1780 DoLog(0) && (Log() << Verbose(0) << "End of FragmentBOSSANOVA." << endl);
1781};
1782
1783/** Corrects the nuclei position if the fragment was created over the cell borders.
1784 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
1785 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
1786 * and re-add the bond. Looping on the distance check.
1787 * \param *out ofstream for debugging messages
1788 */
1789bool molecule::ScanForPeriodicCorrection()
1790{
1791 bond *Binder = NULL;
1792 //bond *OtherBinder = NULL;
1793 atom *Walker = NULL;
1794 atom *OtherWalker = NULL;
1795 RealSpaceMatrix matrix = World::getInstance().getDomain().getM();
1796 enum bond::Shading *ColorList = NULL;
1797 double tmp;
1798 //bool LastBond = true; // only needed to due list construct
1799 Vector Translationvector;
1800 //std::deque<atom *> *CompStack = NULL;
1801 std::deque<atom *> *AtomStack = new std::deque<atom *>; // (getAtomCount());
1802 bool flag = true;
1803 BondGraph *BG = World::getInstance().getBondGraph();
1804
1805 DoLog(2) && (Log() << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl);
1806
1807 ColorList = new enum bond::Shading[getAtomCount()];
1808 for (int i=0;i<getAtomCount();i++)
1809 ColorList[i] = (enum bond::Shading)0;
1810 if (flag) {
1811 // remove bonds that are beyond bonddistance
1812 Translationvector.Zero();
1813 // scan all bonds
1814 flag = false;
1815 for(molecule::iterator AtomRunner = begin(); (!flag) && (AtomRunner != end()); ++AtomRunner) {
1816 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
1817 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
1818 (!flag) && (BondRunner != ListOfBonds.end());
1819 ++BondRunner) {
1820 Binder = (*BondRunner);
1821 for (int i=NDIM;i--;) {
1822 tmp = fabs(Binder->leftatom->at(i) - Binder->rightatom->at(i));
1823 //Log() << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
1824 double MinBondDistance;
1825 double MaxBondDistance;
1826 BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom, MinBondDistance, MaxBondDistance, true);
1827 if ((tmp < MinBondDistance) || ((tmp > MaxBondDistance))) {
1828 DoLog(2) && (Log() << Verbose(2) << "Correcting at bond " << *Binder << "." << endl);
1829 flag = true;
1830 break;
1831 }
1832 }
1833 }
1834 }
1835 //if (flag) {
1836 if (0) {
1837 // create translation vector from their periodically modified distance
1838 for (int i=NDIM;i--;) {
1839 tmp = Binder->leftatom->at(i) - Binder->rightatom->at(i);
1840 double MinBondDistance;
1841 double MaxBondDistance;
1842 BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom, MinBondDistance, MaxBondDistance, true);
1843 if (fabs(tmp) > MaxBondDistance) // check against Min is not useful for components
1844 Translationvector[i] = (tmp < 0) ? +1. : -1.;
1845 }
1846 Translationvector *= matrix;
1847 //Log() << Verbose(3) << "Translation vector is ";
1848 Log() << Verbose(0) << Translationvector << endl;
1849 // apply to all atoms of first component via BFS
1850 for (int i=getAtomCount();i--;)
1851 ColorList[i] = bond::white;
1852 AtomStack->push_front(Binder->leftatom);
1853 while (!AtomStack->empty()) {
1854 Walker = AtomStack->front();
1855 AtomStack->pop_front();
1856 //Log() << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
1857 ColorList[Walker->getNr()] = bond::black; // mark as explored
1858 *Walker += Translationvector; // translate
1859 const BondList& ListOfBonds = Walker->getListOfBonds();
1860 for (BondList::const_iterator Runner = ListOfBonds.begin();
1861 Runner != ListOfBonds.end();
1862 ++Runner) {
1863 if ((*Runner) != Binder) {
1864 OtherWalker = (*Runner)->GetOtherAtom(Walker);
1865 if (ColorList[OtherWalker->getNr()] == bond::white) {
1866 AtomStack->push_front(OtherWalker); // push if yet unexplored
1867 }
1868 }
1869 }
1870 }
1871// // re-add bond
1872// if (OtherBinder == NULL) { // is the only bond?
1873// //Do nothing
1874// } else {
1875// if (!LastBond) {
1876// link(Binder, OtherBinder); // no more implemented bond::previous ...
1877// } else {
1878// link(OtherBinder, Binder); // no more implemented bond::previous ...
1879// }
1880// }
1881 } else {
1882 DoLog(3) && (Log() << Verbose(3) << "No corrections for this fragment." << endl);
1883 }
1884 //delete(CompStack);
1885 }
1886 // free allocated space from ReturnFullMatrixforSymmetric()
1887 delete(AtomStack);
1888 delete[](ColorList);
1889 DoLog(2) && (Log() << Verbose(2) << "End of ScanForPeriodicCorrection." << endl);
1890
1891 return flag;
1892};
Note: See TracBrowser for help on using the repository browser.