source: src/molecule_fragmentation.cpp@ a479fa

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

Renamed ParticleInfo::nr to ParticleInfo::ParticleInfo_nr for easier privatization.

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