source: src/molecule_fragmentation.cpp@ 986ed3

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 986ed3 was 36166d, checked in by Tillmann Crueger <crueger@…>, 14 years ago

Removed left over parts from old memory-tracker

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