source: src/molecule_fragmentation.cpp@ 766ba5

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

Moved FillBondStructureFromReference from MoleculeLeafClass to molecule.

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