source: src/molecule_fragmentation.cpp@ b9947d

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 b9947d was e138de, checked in by Frederik Heber <heber@…>, 15 years ago

Huge change from ofstream * (const) out --> Log().

  • first shift was done via regular expressions
  • then via error messages from the code
  • note that class atom, class element and class molecule kept in parts their output stream, was they print to file.
  • make check runs fine
  • MISSING: Verbosity is not fixed for everything (i.e. if no endl; is present and next has Verbose(0) ...)

Signed-off-by: Frederik Heber <heber@…>

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