source: src/molecule_fragmentation.cpp@ 5be0eb

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 5be0eb was 23b547, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Added generic singleton Pattern that can be inherited to any class making that class a singleton.

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