source: src/molecule_fragmentation.cpp@ d766b5

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

Removed ancient StackClass, replaced by std::deque.

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