source: src/molecule_fragmentation.cpp@ 205d9b

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 205d9b was 84c494, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Made the world store the cell_size within a Box object.

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