source: src/molecule_fragmentation.cpp@ e73ad9a

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

Moved CyclicStructureAnalysis from molecule_graph.cpp into own functor in Graph/.

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