source: src/molecule_fragmentation.cpp@ 1a6bda

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

molecule::FragmentMolecule() - Bond degree is now re-calculated by default.

  • if we load bond graph from file (e.g. pdb), bond degree is not given and set to 1 by default which may not be correct. As bond degree is very important to the fragmentation, we rather re-calculate it before fragmenting.
  • Property mode set to 100644
File size: 82.3 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 "config.hpp"
28#include "element.hpp"
29#include "Helpers/helpers.hpp"
30#include "lists.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 c = ((*iter)->ListOfBonds.size() > c) ? (*iter)->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->nr]) {
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->nr] << " 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)->nr] = 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)->nr] = true; // include all (non-hydrogen) atoms
511 if ((Order != 0) && ((*iter)->AdaptiveOrder < Order)) // && ((*iter)->AdaptiveOrder < MinimumRingSize[(*iter)->nr]))
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)->nr]==-1,"Same SortIndex set twice");
549 SortIndex[(*iter)->nr] = 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()->nr) ? (*iter)->GetTrueFather()->nr : 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()->nr;
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 // reset bond degree to 1
669 for (molecule::iterator atomiter = (*iter)->begin();
670 atomiter != (*iter)->end();
671 ++atomiter) {
672 for (BondList::iterator bonditer = (*atomiter)->ListOfBonds.begin();
673 bonditer != (*atomiter)->ListOfBonds.end();
674 ++bonditer) {
675 (*bonditer)->BondDegree = 1;
676 }
677 }
678 // correct bond degree
679 (*iter)->CorrectBondDegree();
680 }
681
682 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
683 Subgraphs = DepthFirstSearchAnalysis(BackEdgeStack);
684
685 // analysis of the cycles (print rings, get minimum cycle length) for each subgraph
686 for(int i=getAtomCount();i--;)
687 MinimumRingSize[i] = getAtomCount();
688 MolecularWalker = Subgraphs;
689 const int LeafCount = Subgraphs->next->Count();
690 FragmentCounter = 0;
691 while (MolecularWalker->next != NULL) {
692 MolecularWalker = MolecularWalker->next;
693 // fill the bond structure of the individually stored subgraphs
694 ListOfAtoms = NULL;
695 MolecularWalker->FillBondStructureFromReference(this, ListOfAtoms, false); // we want to keep the created ListOfLocalAtoms
696 DoLog(0) && (Log() << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
697 LocalBackEdgeStack = new std::deque<bond *>; // (MolecularWalker->Leaf->BondCount);
698// // check the list of local atoms for debugging
699// Log() << Verbose(0) << "ListOfLocalAtoms for this subgraph is:" << endl;
700// for (int i=0;i<getAtomCount();i++)
701// if (ListOfLocalAtoms[FragmentCounter][i] == NULL)
702// Log() << Verbose(0) << "\tNULL";
703// else
704// Log() << Verbose(0) << "\t" << ListOfLocalAtoms[FragmentCounter][i]->Name;
705 DoLog(0) && (Log() << Verbose(0) << "Gathering local back edges for subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
706 MolecularWalker->Leaf->PickLocalBackEdges(ListOfAtoms, BackEdgeStack, LocalBackEdgeStack);
707 DoLog(0) && (Log() << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
708 MolecularWalker->Leaf->CyclicStructureAnalysis(LocalBackEdgeStack, MinimumRingSize);
709 DoLog(0) && (Log() << Verbose(0) << "Done with Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
710 delete(LocalBackEdgeStack);
711 delete(ListOfAtoms);
712 FragmentCounter++;
713 }
714 delete(BackEdgeStack);
715
716 // ===== 3. if structure still valid, parse key set file and others =====
717 FragmentationToDo = FragmentationToDo && ParseKeySetFile(prefix, ParsedFragmentList);
718
719 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
720 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(prefix);
721
722 // =================================== Begin of FRAGMENTATION ===============================
723 // ===== 6a. assign each keyset to its respective subgraph =====
724 ListOfLocalAtoms = new atom **[LeafCount];
725 for (int i=0;i<LeafCount;i++)
726 ListOfLocalAtoms[i] = NULL;
727 FragmentCounter = 0;
728 Subgraphs->next->AssignKeySetsToFragment(this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, FragmentCounter, true);
729 delete[](ListOfLocalAtoms);
730
731 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
732 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
733 AtomMask = new bool[getAtomCount()+1];
734 AtomMask[getAtomCount()] = false;
735 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
736 while ((CheckOrder = CheckOrderAtSite(AtomMask, ParsedFragmentList, Order, MinimumRingSize, prefix))) {
737 FragmentationToDo = FragmentationToDo || CheckOrder;
738 AtomMask[getAtomCount()] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
739 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
740 Subgraphs->next->FillRootStackForSubgraphs(RootStack, AtomMask, (FragmentCounter = 0));
741
742 // ===== 7. fill the bond fragment list =====
743 FragmentCounter = 0;
744 MolecularWalker = Subgraphs;
745 while (MolecularWalker->next != NULL) {
746 MolecularWalker = MolecularWalker->next;
747 DoLog(1) && (Log() << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl);
748 //MolecularWalker->Leaf->OutputListOfBonds(out); // output atom::ListOfBonds for debugging
749 if (MolecularWalker->Leaf->hasBondStructure()) {
750 // call BOSSANOVA method
751 DoLog(0) && (Log() << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl);
752 MolecularWalker->Leaf->FragmentBOSSANOVA(FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize);
753 } else {
754 DoeLog(1) && (eLog()<< Verbose(1) << "Subgraph " << MolecularWalker << " has no atoms!" << endl);
755 }
756 FragmentCounter++; // next fragment list
757 }
758 }
759 DoLog(2) && (Log() << Verbose(2) << "CheckOrder is " << CheckOrder << "." << endl);
760 delete[](RootStack);
761 delete[](AtomMask);
762 delete(ParsedFragmentList);
763 delete[](MinimumRingSize);
764
765 // ==================================== End of FRAGMENTATION ============================================
766
767 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
768 Subgraphs->next->TranslateIndicesToGlobalIDs(FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
769
770 // free subgraph memory again
771 FragmentCounter = 0;
772 while (Subgraphs != NULL) {
773 // remove entry in fragment list
774 // remove subgraph fragment
775 MolecularWalker = Subgraphs->next;
776 delete(Subgraphs);
777 Subgraphs = MolecularWalker;
778 }
779 // free fragment list
780 for (int i=0; i< FragmentCounter; ++i )
781 delete(FragmentList[i]);
782 delete[](FragmentList);
783
784 DoLog(0) && (Log() << Verbose(0) << FragmentCounter-1 << " subgraph fragments have been removed." << std::endl);
785
786 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
787 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
788 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
789 BondFragments = new MoleculeListClass(World::getPointer());
790 int k=0;
791 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
792 KeySet test = (*runner).first;
793 DoLog(0) && (Log() << Verbose(0) << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl);
794 BondFragments->insert(StoreFragmentFromKeySet(test, World::getInstance().getConfig()));
795 k++;
796 }
797 DoLog(0) && (Log() << Verbose(0) << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl);
798
799 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
800 if (BondFragments->ListOfMolecules.size() != 0) {
801 // create the SortIndex from BFS labels to order in the config file
802 int *SortIndex = NULL;
803 CreateMappingLabelsToConfigSequence(SortIndex);
804
805 DoLog(1) && (Log() << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl);
806 if (BondFragments->OutputConfigForListOfFragments(prefix, SortIndex))
807 DoLog(1) && (Log() << Verbose(1) << "All configs written." << endl);
808 else
809 DoLog(1) && (Log() << Verbose(1) << "Some config writing failed." << endl);
810
811 // store force index reference file
812 BondFragments->StoreForcesFile(prefix, SortIndex);
813
814 // store keysets file
815 StoreKeySetFile(TotalGraph, prefix);
816
817 {
818 // store Adjacency file
819 std::string filename = prefix + ADJACENCYFILE;
820 StoreAdjacencyToFile(filename);
821 }
822
823 // store Hydrogen saturation correction file
824 BondFragments->AddHydrogenCorrection(prefix);
825
826 // store adaptive orders into file
827 StoreOrderAtSiteFile(prefix);
828
829 // restore orbital and Stop values
830 //CalculateOrbitals(*configuration);
831
832 // free memory for bond part
833 DoLog(1) && (Log() << Verbose(1) << "Freeing bond memory" << endl);
834 delete[](SortIndex);
835 } else {
836 DoLog(1) && (Log() << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl);
837 }
838 // remove all create molecules again from the World including their atoms
839 for (MoleculeList::iterator iter = BondFragments->ListOfMolecules.begin();
840 !BondFragments->ListOfMolecules.empty();
841 iter = BondFragments->ListOfMolecules.begin()) {
842 // remove copied atoms and molecule again
843 molecule *mol = *iter;
844 mol->removeAtomsinMolecule();
845 World::getInstance().destroyMolecule(mol);
846 BondFragments->ListOfMolecules.erase(iter);
847 }
848 delete(BondFragments);
849 DoLog(0) && (Log() << Verbose(0) << "End of bond fragmentation." << endl);
850
851 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
852};
853
854
855/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
856 * Atoms not present in the file get "-1".
857 * \param &path path to file ORDERATSITEFILE
858 * \return true - file writable, false - not writable
859 */
860bool molecule::StoreOrderAtSiteFile(std::string &path)
861{
862 string line;
863 ofstream file;
864
865 line = path + ORDERATSITEFILE;
866 file.open(line.c_str());
867 DoLog(1) && (Log() << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl);
868 if (file.good()) {
869 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputOrder), &file));
870 file.close();
871 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
872 return true;
873 } else {
874 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line << "." << endl);
875 return false;
876 }
877};
878
879/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
880 * Atoms not present in the file get "0".
881 * \param &path path to file ORDERATSITEFILEe
882 * \return true - file found and scanned, false - file not found
883 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
884 */
885bool molecule::ParseOrderAtSiteFromFile(std::string &path)
886{
887 unsigned char *OrderArray = new unsigned char[getAtomCount()];
888 bool *MaxArray = new bool[getAtomCount()];
889 bool status;
890 int AtomNr, value;
891 string line;
892 ifstream file;
893
894 for(int i=0;i<getAtomCount();i++) {
895 OrderArray[i] = 0;
896 MaxArray[i] = false;
897 }
898
899 DoLog(1) && (Log() << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl);
900 line = path + ORDERATSITEFILE;
901 file.open(line.c_str());
902 if (file.good()) {
903 while (!file.eof()) { // parse from file
904 AtomNr = -1;
905 file >> AtomNr;
906 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
907 file >> value;
908 OrderArray[AtomNr] = value;
909 file >> value;
910 MaxArray[AtomNr] = value;
911 //Log() << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
912 }
913 }
914 file.close();
915
916 // set atom values
917 for(internal_iterator iter=atoms.begin();iter!=atoms.end();++iter){
918 (*iter)->AdaptiveOrder = OrderArray[(*iter)->nr];
919 (*iter)->MaxOrder = MaxArray[(*iter)->nr];
920 }
921 //SetAtomValueToIndexedArray( OrderArray, &atom::nr, &atom::AdaptiveOrder );
922 //SetAtomValueToIndexedArray( MaxArray, &atom::nr, &atom::MaxOrder );
923
924 DoLog(1) && (Log() << Verbose(1) << "\t ... done." << endl);
925 status = true;
926 } else {
927 DoLog(1) && (Log() << Verbose(1) << "\t ... failed to open file " << line << "." << endl);
928 status = false;
929 }
930 delete[](OrderArray);
931 delete[](MaxArray);
932
933 DoLog(1) && (Log() << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl);
934 return status;
935};
936
937
938
939/** Looks through a std::deque<atom *> and returns the likeliest removal candiate.
940 * \param *out output stream for debugging messages
941 * \param *&Leaf KeySet to look through
942 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
943 * \param index of the atom suggested for removal
944 */
945int molecule::LookForRemovalCandidate(KeySet *&Leaf, int *&ShortestPathList)
946{
947 atom *Runner = NULL;
948 int SP, Removal;
949
950 DoLog(2) && (Log() << Verbose(2) << "Looking for removal candidate." << endl);
951 SP = -1; //0; // not -1, so that Root is never removed
952 Removal = -1;
953 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
954 Runner = FindAtom((*runner));
955 if (Runner->getType()->getAtomicNumber() != 1) { // skip all those added hydrogens when re-filling snake stack
956 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
957 SP = ShortestPathList[(*runner)];
958 Removal = (*runner);
959 }
960 }
961 }
962 return Removal;
963};
964
965/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
966 * \param *mol total molecule
967 * \param *Leaf fragment molecule
968 * \param &Leaflet pointer to KeySet structure
969 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
970 * \return number of atoms in fragment
971 */
972int StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
973{
974 atom *FatherOfRunner = NULL;
975
976 Leaf->BondDistance = mol->BondDistance;
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->nr] = 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->nr] != NULL) { // check if this, our father, is present in list
1010 // create all bonds
1011 for (BondList::const_iterator BondRunner = FatherOfRunner->ListOfBonds.begin(); BondRunner != FatherOfRunner->ListOfBonds.end(); (++BondRunner)) {
1012 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
1013// Log() << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
1014 if (SonList[OtherFather->nr] != NULL) {
1015// Log() << Verbose(0) << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
1016 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
1017// Log() << Verbose(3) << "Adding Bond: ";
1018// Log() << Verbose(0) <<
1019 Leaf->AddBond((*iter), SonList[OtherFather->nr], (*BondRunner)->BondDegree);
1020// Log() << Verbose(0) << "." << endl;
1021 //NumBonds[(*iter)->nr]++;
1022 } else {
1023// Log() << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
1024 }
1025 LonelyFlag = false;
1026 } else {
1027// Log() << Verbose(0) << ", who has no son in this fragment molecule." << endl;
1028#ifdef ADDHYDROGEN
1029 //Log() << Verbose(3) << "Adding Hydrogen to " << (*iter)->Name << " and a bond in between." << endl;
1030 if(!Leaf->AddHydrogenReplacementAtom((*BondRunner), (*iter), FatherOfRunner, OtherFather, IsAngstroem))
1031 exit(1);
1032#endif
1033 //NumBonds[(*iter)->nr] += Binder->BondDegree;
1034 }
1035 }
1036 } else {
1037 DoeLog(1) && (eLog()<< Verbose(1) << "Son " << (*iter)->getName() << " has father " << FatherOfRunner->getName() << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl);
1038 }
1039 if ((LonelyFlag) && (Leaf->getAtomCount() > 1)) {
1040 DoLog(0) && (Log() << Verbose(0) << **iter << "has got bonds only to hydrogens!" << endl);
1041 }
1042 ++iter;
1043#ifdef ADDHYDROGEN
1044 while ((iter != Leaf->end()) && ((*iter)->getType()->getAtomicNumber() == 1)){ // skip added hydrogen
1045 iter++;
1046 }
1047#endif
1048 }
1049};
1050
1051/** Stores a fragment from \a KeySet into \a molecule.
1052 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
1053 * molecule and adds missing hydrogen where bonds were cut.
1054 * \param *out output stream for debugging messages
1055 * \param &Leaflet pointer to KeySet structure
1056 * \param IsAngstroem whether we have Ansgtroem or bohrradius
1057 * \return pointer to constructed molecule
1058 */
1059molecule * molecule::StoreFragmentFromKeySet(KeySet &Leaflet, bool IsAngstroem)
1060{
1061 atom **SonList = new atom*[getAtomCount()];
1062 molecule *Leaf = World::getInstance().createMolecule();
1063
1064 for(int i=0;i<getAtomCount();i++)
1065 SonList[i] = NULL;
1066
1067// Log() << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
1068 StoreFragmentFromKeySet_Init(this, Leaf, Leaflet, SonList);
1069 // create the bonds between all: Make it an induced subgraph and add hydrogen
1070// Log() << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
1071 CreateInducedSubgraphOfFragment(this, Leaf, SonList, IsAngstroem);
1072
1073 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
1074 delete[](SonList);
1075// Log() << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
1076 return Leaf;
1077};
1078
1079
1080/** Clears the touched list
1081 * \param *out output stream for debugging
1082 * \param verbosity verbosity level
1083 * \param *&TouchedList touched list
1084 * \param SubOrder current suborder
1085 * \param TouchedIndex currently touched
1086 */
1087void SPFragmentGenerator_ClearingTouched(int verbosity, int *&TouchedList, int SubOrder, int &TouchedIndex)
1088{
1089 Log() << Verbose(1+verbosity) << "Clearing touched list." << endl;
1090 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
1091 TouchedList[TouchedIndex] = -1;
1092 TouchedIndex = 0;
1093
1094}
1095
1096/** Adds the current combination of the power set to the snake stack.
1097 * \param *out output stream for debugging
1098 * \param verbosity verbosity level
1099 * \param CurrentCombination
1100 * \param SetDimension maximum number of bits in power set
1101 * \param *FragmentSet snake stack to remove from
1102 * \param *&TouchedList touched list
1103 * \param TouchedIndex currently touched
1104 * \return number of set bits
1105 */
1106int AddPowersetToSnakeStack(int verbosity, int CurrentCombination, int SetDimension, KeySet *FragmentSet, bond **BondsSet, int *&TouchedList, int &TouchedIndex)
1107{
1108 atom *OtherWalker = NULL;
1109 bool bit = false;
1110 KeySetTestPair TestKeySetInsert;
1111
1112 int Added = 0;
1113 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
1114 bit = ((CurrentCombination & (1 << j)) != 0); // mask the bit for the j-th bond
1115 if (bit) { // if bit is set, we add this bond partner
1116 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
1117 //Log() << Verbose(1+verbosity) << "Current Bond is " << BondsSet[j] << ", checking on " << *OtherWalker << "." << endl;
1118 Log() << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
1119 TestKeySetInsert = FragmentSet->insert(OtherWalker->nr);
1120 if (TestKeySetInsert.second) {
1121 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
1122 Added++;
1123 } else {
1124 Log() << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
1125 }
1126 } else {
1127 Log() << Verbose(2+verbosity) << "Not adding." << endl;
1128 }
1129 }
1130 return Added;
1131};
1132
1133/** Counts the number of elements in a power set.
1134 * \param *SetFirst
1135 * \param *SetLast
1136 * \param *&TouchedList touched list
1137 * \param TouchedIndex currently touched
1138 * \return number of elements
1139 */
1140int CountSetMembers(bond *SetFirst, bond *SetLast, int *&TouchedList, int TouchedIndex)
1141{
1142 int SetDimension = 0;
1143 bond *Binder = SetFirst; // start node for this level
1144 while (Binder->next != SetLast) { // compare to end node of this level
1145 Binder = Binder->next;
1146 for (int k=TouchedIndex;k--;) {
1147 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
1148 SetDimension++;
1149 }
1150 }
1151 return SetDimension;
1152};
1153
1154/** Counts the number of elements in a power set.
1155 * \param *BondsList bonds list to fill
1156 * \param *SetFirst
1157 * \param *SetLast
1158 * \param *&TouchedList touched list
1159 * \param TouchedIndex currently touched
1160 * \return number of elements
1161 */
1162int FillBondsList(bond **BondsList, bond *SetFirst, bond *SetLast, int *&TouchedList, int TouchedIndex)
1163{
1164 int SetDimension = 0;
1165 bond *Binder = SetFirst; // start node for this level
1166 while (Binder->next != SetLast) { // compare to end node of this level
1167 Binder = Binder->next;
1168 for (int k=0;k<TouchedIndex;k++) {
1169 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
1170 BondsList[SetDimension++] = Binder;
1171 }
1172 }
1173 return SetDimension;
1174};
1175
1176/** Remove all items that were added on this SP level.
1177 * \param *out output stream for debugging
1178 * \param verbosity verbosity level
1179 * \param *FragmentSet snake stack to remove from
1180 * \param *&TouchedList touched list
1181 * \param TouchedIndex currently touched
1182 */
1183void RemoveAllTouchedFromSnakeStack(int verbosity, KeySet *FragmentSet, int *&TouchedList, int &TouchedIndex)
1184{
1185 int Removal = 0;
1186 for(int j=0;j<TouchedIndex;j++) {
1187 Removal = TouchedList[j];
1188 Log() << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
1189 FragmentSet->erase(Removal);
1190 TouchedList[j] = -1;
1191 }
1192 DoLog(2) && (Log() << Verbose(2) << "Remaining local nr.s on snake stack are: ");
1193 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
1194 DoLog(0) && (Log() << Verbose(0) << (*runner) << " ");
1195 DoLog(0) && (Log() << Verbose(0) << endl);
1196 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
1197};
1198
1199/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
1200 * -# loops over every possible combination (2^dimension of edge set)
1201 * -# inserts current set, if there's still space left
1202 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
1203ance+1
1204 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
1205 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
1206distance) and current set
1207 * \param *out output stream for debugging
1208 * \param FragmentSearch UniqueFragments structure with all values needed
1209 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
1210 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
1211 * \param SubOrder remaining number of allowed vertices to add
1212 */
1213void molecule::SPFragmentGenerator(struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
1214{
1215 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
1216 int NumCombinations;
1217 int bits, TouchedIndex, SubSetDimension, SP, Added;
1218 int SpaceLeft;
1219 int *TouchedList = new int[SubOrder + 1];
1220 KeySetTestPair TestKeySetInsert;
1221
1222 NumCombinations = 1 << SetDimension;
1223
1224 // here for all bonds of Walker all combinations of end pieces (from the bonds)
1225 // have to be added and for the remaining ANOVA order GraphCrawler be called
1226 // recursively for the next level
1227
1228 Log() << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
1229 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;
1230
1231 // initialised touched list (stores added atoms on this level)
1232 SPFragmentGenerator_ClearingTouched(verbosity, TouchedList, SubOrder, TouchedIndex);
1233
1234 // create every possible combination of the endpieces
1235 Log() << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
1236 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
1237 // count the set bit of i
1238 bits = 0;
1239 for (int j=SetDimension;j--;)
1240 bits += (i & (1 << j)) >> j;
1241
1242 Log() << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
1243 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
1244 // --1-- add this set of the power set of bond partners to the snake stack
1245 Added = AddPowersetToSnakeStack(verbosity, i, SetDimension, FragmentSearch->FragmentSet, BondsSet, TouchedList, TouchedIndex);
1246
1247 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
1248 if (SpaceLeft > 0) {
1249 Log() << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
1250 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
1251 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
1252 SP = RootDistance+1; // this is the next level
1253
1254 // first count the members in the subset
1255 SubSetDimension = CountSetMembers(FragmentSearch->BondsPerSPList[2*SP], FragmentSearch->BondsPerSPList[2*SP+1], TouchedList, TouchedIndex);
1256
1257 // then allocate and fill the list
1258 bond *BondsList[SubSetDimension];
1259 SubSetDimension = FillBondsList(BondsList, FragmentSearch->BondsPerSPList[2*SP], FragmentSearch->BondsPerSPList[2*SP+1], TouchedList, TouchedIndex);
1260
1261 // then iterate
1262 Log() << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
1263 SPFragmentGenerator(FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
1264 }
1265 } else {
1266 // --2-- otherwise store the complete fragment
1267 Log() << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
1268 // store fragment as a KeySet
1269 DoLog(2) && (Log() << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ");
1270 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
1271 DoLog(0) && (Log() << Verbose(0) << (*runner) << " ");
1272 DoLog(0) && (Log() << Verbose(0) << endl);
1273 //if (!CheckForConnectedSubgraph(FragmentSearch->FragmentSet))
1274 //DoeLog(1) && (eLog()<< Verbose(1) << "The found fragment is not a connected subgraph!" << endl);
1275 InsertFragmentIntoGraph(FragmentSearch);
1276 }
1277
1278 // --3-- remove all added items in this level from snake stack
1279 Log() << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
1280 RemoveAllTouchedFromSnakeStack(verbosity, FragmentSearch->FragmentSet, TouchedList, TouchedIndex);
1281 } else {
1282 Log() << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
1283 }
1284 }
1285 delete[](TouchedList);
1286 Log() << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
1287};
1288
1289/** Allocates memory for UniqueFragments::BondsPerSPList.
1290 * \param *out output stream
1291 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1292 * \param FragmentSearch UniqueFragments
1293 * \sa FreeSPList()
1294 */
1295void InitialiseSPList(int Order, struct UniqueFragments &FragmentSearch)
1296{
1297 FragmentSearch.BondsPerSPList = new bond* [Order * 2];
1298 FragmentSearch.BondsPerSPCount = new int[Order];
1299 for (int i=Order;i--;) {
1300 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node
1301 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node
1302 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two
1303 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i];
1304 FragmentSearch.BondsPerSPCount[i] = 0;
1305 }
1306};
1307
1308/** Free's memory for for UniqueFragments::BondsPerSPList.
1309 * \param *out output stream
1310 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1311 * \param FragmentSearch UniqueFragments\
1312 * \sa InitialiseSPList()
1313 */
1314void FreeSPList(int Order, struct UniqueFragments &FragmentSearch)
1315{
1316 delete[](FragmentSearch.BondsPerSPCount);
1317 for (int i=Order;i--;) {
1318 delete(FragmentSearch.BondsPerSPList[2*i]);
1319 delete(FragmentSearch.BondsPerSPList[2*i+1]);
1320 }
1321 delete[](FragmentSearch.BondsPerSPList);
1322};
1323
1324/** Sets FragmenSearch to initial value.
1325 * Sets UniqueFragments::ShortestPathList entries to zero, UniqueFragments::BondsPerSPCount to zero (except zero level to 1) and
1326 * adds initial bond UniqueFragments::Root to UniqueFragments::Root to UniqueFragments::BondsPerSPList
1327 * \param *out output stream
1328 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1329 * \param FragmentSearch UniqueFragments
1330 * \sa FreeSPList()
1331 */
1332void SetSPList(int Order, struct UniqueFragments &FragmentSearch)
1333{
1334 // prepare Label and SP arrays of the BFS search
1335 FragmentSearch.ShortestPathList[FragmentSearch.Root->nr] = 0;
1336
1337 // prepare root level (SP = 0) and a loop bond denoting Root
1338 for (int i=Order;i--;)
1339 FragmentSearch.BondsPerSPCount[i] = 0;
1340 FragmentSearch.BondsPerSPCount[0] = 1;
1341 bond *Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
1342 add(Binder, FragmentSearch.BondsPerSPList[1]);
1343};
1344
1345/** Resets UniqueFragments::ShortestPathList and cleans bonds from UniqueFragments::BondsPerSPList.
1346 * \param *out output stream
1347 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1348 * \param FragmentSearch UniqueFragments
1349 * \sa InitialiseSPList()
1350 */
1351void ResetSPList(int Order, struct UniqueFragments &FragmentSearch)
1352{
1353 bond *Binder = NULL;
1354 DoLog(0) && (Log() << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl);
1355 for(int i=Order;i--;) {
1356 DoLog(1) && (Log() << Verbose(1) << "Current SP level is " << i << ": ");
1357 Binder = FragmentSearch.BondsPerSPList[2*i];
1358 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
1359 Binder = Binder->next;
1360 // Log() << Verbose(0) << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local
1361 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1;
1362 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1;
1363 }
1364 // delete added bonds
1365 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]);
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 *CurrentEdge = NULL;
1392 bond *Binder = NULL;
1393 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->nr;
1394 int RemainingWalkers = -1;
1395 int SP = -1;
1396
1397 DoLog(0) && (Log() << Verbose(0) << "Starting BFS analysis ..." << endl);
1398 for (SP = 0; SP < (Order-1); SP++) {
1399 DoLog(1) && (Log() << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)");
1400 if (SP > 0) {
1401 DoLog(0) && (Log() << Verbose(0) << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl);
1402 FragmentSearch.BondsPerSPCount[SP] = 0;
1403 } else
1404 DoLog(0) && (Log() << Verbose(0) << "." << endl);
1405
1406 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
1407 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP]; /// start of this SP level's list
1408 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) { /// end of this SP level's list
1409 CurrentEdge = CurrentEdge->next;
1410 RemainingWalkers--;
1411 Walker = CurrentEdge->rightatom; // rightatom is always the one more distant
1412 Predecessor = CurrentEdge->leftatom; // ... and leftatom is predecessor
1413 AtomKeyNr = Walker->nr;
1414 DoLog(0) && (Log() << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl);
1415 // check for new sp level
1416 // go through all its bonds
1417 DoLog(1) && (Log() << Verbose(1) << "Going through all bonds of Walker." << endl);
1418 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1419 OtherWalker = (*Runner)->GetOtherAtom(Walker);
1420 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end())
1421 #ifdef ADDHYDROGEN
1422 && (OtherWalker->getType()->getAtomicNumber() != 1)
1423 #endif
1424 ) { // skip hydrogens and restrict to fragment
1425 DoLog(2) && (Log() << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *(*Runner) << "." << endl);
1426 // set the label if not set (and push on root stack as well)
1427 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->nr > RootKeyNr)) { // only pass through those with label bigger than Root's
1428 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1;
1429 DoLog(3) && (Log() << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl);
1430 // add the bond in between to the SP list
1431 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
1432 add(Binder, FragmentSearch.BondsPerSPList[2*(SP+1)+1]);
1433 FragmentSearch.BondsPerSPCount[SP+1]++;
1434 DoLog(3) && (Log() << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl);
1435 } else {
1436 if (OtherWalker != Predecessor)
1437 DoLog(3) && (Log() << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->nr << " is smaller than that of Root " << RootKeyNr << "." << endl);
1438 else
1439 DoLog(3) && (Log() << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl);
1440 }
1441 } else Log() << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
1442 }
1443 }
1444 }
1445};
1446
1447/** prints the Bonds per Shortest Path list in UniqueFragments.
1448 * \param *out output stream
1449 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1450 * \param FragmentSearch UniqueFragments
1451 */
1452void OutputSPList(int Order, struct UniqueFragments &FragmentSearch)
1453{
1454 bond *Binder = NULL;
1455 DoLog(0) && (Log() << Verbose(0) << "Printing all found lists." << endl);
1456 for(int i=1;i<Order;i++) { // skip the root edge in the printing
1457 Binder = FragmentSearch.BondsPerSPList[2*i];
1458 DoLog(1) && (Log() << Verbose(1) << "Current SP level is " << i << "." << endl);
1459 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
1460 Binder = Binder->next;
1461 DoLog(2) && (Log() << Verbose(2) << *Binder << endl);
1462 }
1463 }
1464};
1465
1466/** Simply counts all bonds in all UniqueFragments::BondsPerSPList lists.
1467 * \param *out output stream
1468 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1469 * \param FragmentSearch UniqueFragments
1470 */
1471int CountNumbersInBondsList(int Order, struct UniqueFragments &FragmentSearch)
1472{
1473 bond *Binder = NULL;
1474 int SP = -1; // the Root <-> Root edge must be subtracted!
1475 for(int i=Order;i--;) { // sum up all found edges
1476 Binder = FragmentSearch.BondsPerSPList[2*i];
1477 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
1478 Binder = Binder->next;
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->nr << "." << 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 bond* BondsList[FragmentSearch.BondsPerSPCount[0]];
1526 for(int i=0;i<FragmentSearch.BondsPerSPCount[0];i++)
1527 BondsList[i] = NULL;
1528 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond
1529
1530 SPFragmentGenerator(&FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
1531 } else {
1532 DoLog(0) && (Log() << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl);
1533 }
1534
1535 // as FragmentSearch structure is used only once, we don't have to clean it anymore
1536 // remove root from stack
1537 DoLog(0) && (Log() << Verbose(0) << "Removing root again from stack." << endl);
1538 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr);
1539
1540 // free'ing the bonds lists
1541 ResetSPList(Order, FragmentSearch);
1542
1543 // return list
1544 DoLog(0) && (Log() << Verbose(0) << "End of PowerSetGenerator." << endl);
1545 return (FragmentSearch.FragmentCounter - Counter);
1546};
1547
1548bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
1549{
1550 //Log() << Verbose(0) << "my check is used." << endl;
1551 if (SubgraphA.size() < SubgraphB.size()) {
1552 return true;
1553 } else {
1554 if (SubgraphA.size() > SubgraphB.size()) {
1555 return false;
1556 } else {
1557 KeySet::iterator IteratorA = SubgraphA.begin();
1558 KeySet::iterator IteratorB = SubgraphB.begin();
1559 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
1560 if ((*IteratorA) < (*IteratorB))
1561 return true;
1562 else if ((*IteratorA) > (*IteratorB)) {
1563 return false;
1564 } // else, go on to next index
1565 IteratorA++;
1566 IteratorB++;
1567 } // end of while loop
1568 }// end of check in case of equal sizes
1569 }
1570 return false; // if we reach this point, they are equal
1571};
1572
1573
1574/** Combines all KeySets from all orders into single ones (with just unique entries).
1575 * \param *out output stream for debugging
1576 * \param *&FragmentList list to fill
1577 * \param ***FragmentLowerOrdersList
1578 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1579 * \param *mol molecule with atoms and bonds
1580 */
1581int CombineAllOrderListIntoOne(Graph *&FragmentList, Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol)
1582{
1583 int RootNr = 0;
1584 int RootKeyNr = 0;
1585 int StartNr = 0;
1586 int counter = 0;
1587 int NumLevels = 0;
1588 atom *Walker = NULL;
1589
1590 DoLog(0) && (Log() << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl);
1591 if (FragmentList == NULL) {
1592 FragmentList = new Graph;
1593 counter = 0;
1594 } else {
1595 counter = FragmentList->size();
1596 }
1597
1598 StartNr = RootStack.back();
1599 do {
1600 RootKeyNr = RootStack.front();
1601 RootStack.pop_front();
1602 Walker = mol->FindAtom(RootKeyNr);
1603 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
1604 for(int i=0;i<NumLevels;i++) {
1605 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
1606 InsertGraphIntoGraph(*FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
1607 }
1608 }
1609 RootStack.push_back(Walker->nr);
1610 RootNr++;
1611 } while (RootKeyNr != StartNr);
1612 return counter;
1613};
1614
1615/** Free's memory allocated for all KeySets from all orders.
1616 * \param *out output stream for debugging
1617 * \param ***FragmentLowerOrdersList
1618 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1619 * \param *mol molecule with atoms and bonds
1620 */
1621void FreeAllOrdersList(Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol)
1622{
1623 DoLog(1) && (Log() << Verbose(1) << "Free'ing the lists of all orders per order." << endl);
1624 int RootNr = 0;
1625 int RootKeyNr = 0;
1626 int NumLevels = 0;
1627 atom *Walker = NULL;
1628 while (!RootStack.empty()) {
1629 RootKeyNr = RootStack.front();
1630 RootStack.pop_front();
1631 Walker = mol->FindAtom(RootKeyNr);
1632 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
1633 for(int i=0;i<NumLevels;i++) {
1634 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
1635 delete(FragmentLowerOrdersList[RootNr][i]);
1636 }
1637 }
1638 delete[](FragmentLowerOrdersList[RootNr]);
1639 RootNr++;
1640 }
1641 delete[](FragmentLowerOrdersList);
1642};
1643
1644
1645/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
1646 * -# constructs a complete keyset of the molecule
1647 * -# In a loop over all possible roots from the given rootstack
1648 * -# increases order of root site
1649 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
1650 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
1651as the restricted one and each site in the set as the root)
1652 * -# these are merged into a fragment list of keysets
1653 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
1654 * Important only is that we create all fragments, it is not important if we create them more than once
1655 * as these copies are filtered out via use of the hash table (KeySet).
1656 * \param *out output stream for debugging
1657 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
1658 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1659 * \param *MinimumRingSize minimum ring size for each atom (molecule::Atomcount)
1660 * \return pointer to Graph list
1661 */
1662void molecule::FragmentBOSSANOVA(Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize)
1663{
1664 Graph ***FragmentLowerOrdersList = NULL;
1665 int NumLevels = 0;
1666 int NumMolecules = 0;
1667 int TotalNumMolecules = 0;
1668 int *NumMoleculesOfOrder = NULL;
1669 int Order = 0;
1670 int UpgradeCount = RootStack.size();
1671 KeyStack FragmentRootStack;
1672 int RootKeyNr = 0;
1673 int RootNr = 0;
1674 struct UniqueFragments FragmentSearch;
1675
1676 DoLog(0) && (Log() << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl);
1677
1678 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
1679 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
1680 NumMoleculesOfOrder = new int[UpgradeCount];
1681 FragmentLowerOrdersList = new Graph**[UpgradeCount];
1682
1683 for(int i=0;i<UpgradeCount;i++) {
1684 NumMoleculesOfOrder[i] = 0;
1685 FragmentLowerOrdersList[i] = NULL;
1686 }
1687
1688 // initialise the fragments structure
1689 FragmentSearch.FragmentCounter = 0;
1690 FragmentSearch.FragmentSet = new KeySet;
1691 FragmentSearch.Root = FindAtom(RootKeyNr);
1692 FragmentSearch.ShortestPathList = new int[getAtomCount()];
1693 for (int i=getAtomCount();i--;) {
1694 FragmentSearch.ShortestPathList[i] = -1;
1695 }
1696
1697 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
1698 KeySet CompleteMolecule;
1699 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
1700 CompleteMolecule.insert((*iter)->GetTrueFather()->nr);
1701 }
1702
1703 // 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
1704 // 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),
1705 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
1706 // 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)
1707 RootNr = 0; // counts through the roots in RootStack
1708 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
1709 RootKeyNr = RootStack.front();
1710 RootStack.pop_front();
1711 atom *Walker = FindAtom(RootKeyNr);
1712 // check cyclic lengths
1713 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) {
1714 // 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;
1715 //} else
1716 {
1717 // increase adaptive order by one
1718 Walker->GetTrueFather()->AdaptiveOrder++;
1719 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
1720
1721 // initialise Order-dependent entries of UniqueFragments structure
1722 InitialiseSPList(Order, FragmentSearch);
1723
1724 // allocate memory for all lower level orders in this 1D-array of ptrs
1725 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
1726 FragmentLowerOrdersList[RootNr] = new Graph*[NumLevels];
1727 for (int i=0;i<NumLevels;i++)
1728 FragmentLowerOrdersList[RootNr][i] = NULL;
1729
1730 // create top order where nothing is reduced
1731 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1732 DoLog(0) && (Log() << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl); // , NumLevels is " << NumLevels << "
1733
1734 // Create list of Graphs of current Bond Order (i.e. F_{ij})
1735 FragmentLowerOrdersList[RootNr][0] = new Graph;
1736 FragmentSearch.TEFactor = 1.;
1737 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
1738 FragmentSearch.Root = Walker;
1739 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
1740
1741 // output resulting number
1742 DoLog(1) && (Log() << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl);
1743 if (NumMoleculesOfOrder[RootNr] != 0) {
1744 NumMolecules = 0;
1745 } else {
1746 Walker->GetTrueFather()->MaxOrder = true;
1747 }
1748 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
1749 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
1750 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
1751// Log() << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
1752 RootStack.push_back(RootKeyNr); // put back on stack
1753 RootNr++;
1754
1755 // free Order-dependent entries of UniqueFragments structure for next loop cycle
1756 FreeSPList(Order, FragmentSearch);
1757 }
1758 }
1759 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1760 DoLog(1) && (Log() << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl);
1761 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1762
1763 // cleanup FragmentSearch structure
1764 delete[](FragmentSearch.ShortestPathList);
1765 delete(FragmentSearch.FragmentSet);
1766
1767 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
1768 // 5433222211111111
1769 // 43221111
1770 // 3211
1771 // 21
1772 // 1
1773
1774 // Subsequently, we combine all into a single list (FragmentList)
1775 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, this);
1776 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, this);
1777 delete[](NumMoleculesOfOrder);
1778
1779 DoLog(0) && (Log() << Verbose(0) << "End of FragmentBOSSANOVA." << endl);
1780};
1781
1782/** Corrects the nuclei position if the fragment was created over the cell borders.
1783 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
1784 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
1785 * and re-add the bond. Looping on the distance check.
1786 * \param *out ofstream for debugging messages
1787 */
1788bool molecule::ScanForPeriodicCorrection()
1789{
1790 bond *Binder = NULL;
1791 bond *OtherBinder = NULL;
1792 atom *Walker = NULL;
1793 atom *OtherWalker = NULL;
1794 RealSpaceMatrix matrix = World::getInstance().getDomain().getM();
1795 enum Shading *ColorList = NULL;
1796 double tmp;
1797 bool LastBond = true; // only needed to due list construct
1798 Vector Translationvector;
1799 //std::deque<atom *> *CompStack = NULL;
1800 std::deque<atom *> *AtomStack = new std::deque<atom *>; // (getAtomCount());
1801 bool flag = true;
1802
1803 DoLog(2) && (Log() << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl);
1804
1805 ColorList = new enum Shading[getAtomCount()];
1806 for (int i=0;i<getAtomCount();i++)
1807 ColorList[i] = (enum Shading)0;
1808 if (flag) {
1809 // remove bonds that are beyond bonddistance
1810 Translationvector.Zero();
1811 // scan all bonds
1812 flag = false;
1813 for(molecule::iterator AtomRunner = begin(); (!flag) && (AtomRunner != end()); ++AtomRunner)
1814 for(BondList::iterator BondRunner = (*AtomRunner)->ListOfBonds.begin(); (!flag) && (BondRunner != (*AtomRunner)->ListOfBonds.end()); ++BondRunner) {
1815 Binder = (*BondRunner);
1816 for (int i=NDIM;i--;) {
1817 tmp = fabs(Binder->leftatom->at(i) - Binder->rightatom->at(i));
1818 //Log() << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
1819 if (tmp > BondDistance) {
1820// OtherBinder = Binder->next; // note down binding partner for later re-insertion
1821// if (OtherBinder != NULL) {
1822// LastBond = false;
1823// } else {
1824// OtherBinder = Binder->previous;
1825// LastBond = true;
1826// }
1827// unlink(Binder); // unlink bond
1828 DoLog(2) && (Log() << Verbose(2) << "Correcting at bond " << *Binder << "." << endl);
1829 flag = true;
1830 break;
1831 }
1832 }
1833 }
1834 //if (flag) {
1835 if (0) {
1836 // create translation vector from their periodically modified distance
1837 for (int i=NDIM;i--;) {
1838 tmp = Binder->leftatom->at(i) - Binder->rightatom->at(i);
1839 if (fabs(tmp) > BondDistance)
1840 Translationvector[i] = (tmp < 0) ? +1. : -1.;
1841 }
1842 Translationvector *= matrix;
1843 //Log() << Verbose(3) << "Translation vector is ";
1844 Log() << Verbose(0) << Translationvector << endl;
1845 // apply to all atoms of first component via BFS
1846 for (int i=getAtomCount();i--;)
1847 ColorList[i] = white;
1848 AtomStack->push_front(Binder->leftatom);
1849 while (!AtomStack->empty()) {
1850 Walker = AtomStack->front();
1851 AtomStack->pop_front();
1852 //Log() << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
1853 ColorList[Walker->nr] = black; // mark as explored
1854 *Walker += Translationvector; // translate
1855 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1856 if ((*Runner) != Binder) {
1857 OtherWalker = (*Runner)->GetOtherAtom(Walker);
1858 if (ColorList[OtherWalker->nr] == white) {
1859 AtomStack->push_front(OtherWalker); // push if yet unexplored
1860 }
1861 }
1862 }
1863 }
1864 // re-add bond
1865 if (OtherBinder == NULL) { // is the only bond?
1866 //Do nothing
1867 } else {
1868 if (!LastBond) {
1869 link(Binder, OtherBinder);
1870 } else {
1871 link(OtherBinder, Binder);
1872 }
1873 }
1874 } else {
1875 DoLog(3) && (Log() << Verbose(3) << "No corrections for this fragment." << endl);
1876 }
1877 //delete(CompStack);
1878 }
1879 // free allocated space from ReturnFullMatrixforSymmetric()
1880 delete(AtomStack);
1881 delete[](ColorList);
1882 DoLog(2) && (Log() << Verbose(2) << "End of ScanForPeriodicCorrection." << endl);
1883
1884 return flag;
1885};
Note: See TracBrowser for help on using the repository browser.