source: src/molecule_fragmentation.cpp@ a2bdbe

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

BondedParticleInfo now has vector<BondList>

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