source: src/molecule_fragmentation.cpp@ 436f04

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 436f04 was d10eb6, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Made the ReturnFullMatrixForSymmetric return a Matrix object directely instead of a double array

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