source: src/molecule_fragmentation.cpp@ 2f40c0e

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 2f40c0e was 112b09, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Added #include "Helpers/MemDebug.hpp" to all .cpp files

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