source: src/molecule_fragmentation.cpp@ 111387

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

Moved bond.* to Bond/, new class GraphEdge which contains graph parts of bond.

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