source: src/molecule_fragmentation.cpp@ f4e1f5

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 f4e1f5 was 3c349b, checked in by Frederik Heber <heber@…>, 16 years ago

"not working parsed molecule into subgraph splitting"-BUG fixed, BugFinder branch can be closed.

  • config::Load() - atoms were not in the right order for MaxOrder-test (12). Hence, the BondFragmentAdjacency could not be parsed. Now, we just take the subgraphs as the association of each atom to a molecule, i.e. we make a list and then re-link each atom to its new connected subgraph molecule, which is returned as the MoleculeListClass.

other fixes:

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