source: src/molecule_fragmentation.cpp@ 2aeefd

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 Candidate_v1.7.0 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 2aeefd was 7218f8, checked in by Frederik Heber <heber@…>, 16 years ago

Several memory bugfixes (thx valgrind).

Fixed Calloc:

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 "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 delete[](RootStack);
644 delete[](AtomMask);
645 delete(ParsedFragmentList);
646 delete[](MinimumRingSize);
647
648
649 // ==================================== End of FRAGMENTATION ============================================
650
651 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
652 Subgraphs->next->TranslateIndicesToGlobalIDs(out, FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
653
654 // free subgraph memory again
655 FragmentCounter = 0;
656 if (Subgraphs != NULL) {
657 while (Subgraphs->next != NULL) {
658 Subgraphs = Subgraphs->next;
659 delete(FragmentList[FragmentCounter++]);
660 delete(Subgraphs->previous);
661 }
662 delete(Subgraphs);
663 }
664 Free(&FragmentList);
665
666 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
667 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
668 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
669 BondFragments = new MoleculeListClass();
670 int k=0;
671 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
672 KeySet test = (*runner).first;
673 *out << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl;
674 BondFragments->insert(StoreFragmentFromKeySet(out, test, configuration));
675 k++;
676 }
677 *out << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl;
678
679 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
680 if (BondFragments->ListOfMolecules.size() != 0) {
681 // create the SortIndex from BFS labels to order in the config file
682 CreateMappingLabelsToConfigSequence(out, SortIndex);
683
684 *out << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl;
685 if (BondFragments->OutputConfigForListOfFragments(out, configuration, SortIndex))
686 *out << Verbose(1) << "All configs written." << endl;
687 else
688 *out << Verbose(1) << "Some config writing failed." << endl;
689
690 // store force index reference file
691 BondFragments->StoreForcesFile(out, configuration->configpath, SortIndex);
692
693 // store keysets file
694 StoreKeySetFile(out, TotalGraph, configuration->configpath);
695
696 // store Adjacency file
697 StoreAdjacencyToFile(out, configuration->configpath);
698
699 // store Hydrogen saturation correction file
700 BondFragments->AddHydrogenCorrection(out, configuration->configpath);
701
702 // store adaptive orders into file
703 StoreOrderAtSiteFile(out, configuration->configpath);
704
705 // restore orbital and Stop values
706 CalculateOrbitals(*configuration);
707
708 // free memory for bond part
709 *out << Verbose(1) << "Freeing bond memory" << endl;
710 delete(FragmentList); // remove bond molecule from memory
711 Free(&SortIndex);
712 } else {
713 *out << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl;
714 }
715 delete(BondFragments);
716 *out << Verbose(0) << "End of bond fragmentation." << endl;
717
718 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
719};
720
721
722/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
723 * Atoms not present in the file get "-1".
724 * \param *out output stream for debugging
725 * \param *path path to file ORDERATSITEFILE
726 * \return true - file writable, false - not writable
727 */
728bool molecule::StoreOrderAtSiteFile(ofstream *out, char *path)
729{
730 stringstream line;
731 ofstream file;
732
733 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
734 file.open(line.str().c_str());
735 *out << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl;
736 if (file != NULL) {
737 ActOnAllAtoms( &atom::OutputOrder, &file );
738 file.close();
739 *out << Verbose(1) << "done." << endl;
740 return true;
741 } else {
742 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
743 return false;
744 }
745};
746
747/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
748 * Atoms not present in the file get "0".
749 * \param *out output stream for debugging
750 * \param *path path to file ORDERATSITEFILEe
751 * \return true - file found and scanned, false - file not found
752 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
753 */
754bool molecule::ParseOrderAtSiteFromFile(ofstream *out, char *path)
755{
756 unsigned char *OrderArray = Calloc<unsigned char>(AtomCount, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
757 bool *MaxArray = Calloc<bool>(AtomCount, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
758 bool status;
759 int AtomNr, value;
760 stringstream line;
761 ifstream file;
762
763 *out << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl;
764 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
765 file.open(line.str().c_str());
766 if (file != NULL) {
767 while (!file.eof()) { // parse from file
768 AtomNr = -1;
769 file >> AtomNr;
770 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
771 file >> value;
772 OrderArray[AtomNr] = value;
773 file >> value;
774 MaxArray[AtomNr] = value;
775 //*out << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
776 }
777 }
778 file.close();
779
780 // set atom values
781 SetAtomValueToIndexedArray( OrderArray, &atom::nr, &atom::AdaptiveOrder );
782 SetAtomValueToIndexedArray( MaxArray, &atom::nr, &atom::MaxOrder );
783
784 *out << Verbose(1) << "done." << endl;
785 status = true;
786 } else {
787 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
788 status = false;
789 }
790 Free(&OrderArray);
791 Free(&MaxArray);
792
793 *out << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl;
794 return status;
795};
796
797
798
799/** Looks through a StackClass<atom *> and returns the likeliest removal candiate.
800 * \param *out output stream for debugging messages
801 * \param *&Leaf KeySet to look through
802 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
803 * \param index of the atom suggested for removal
804 */
805int molecule::LookForRemovalCandidate(ofstream *&out, KeySet *&Leaf, int *&ShortestPathList)
806{
807 atom *Runner = NULL;
808 int SP, Removal;
809
810 *out << Verbose(2) << "Looking for removal candidate." << endl;
811 SP = -1; //0; // not -1, so that Root is never removed
812 Removal = -1;
813 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
814 Runner = FindAtom((*runner));
815 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack
816 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
817 SP = ShortestPathList[(*runner)];
818 Removal = (*runner);
819 }
820 }
821 }
822 return Removal;
823};
824
825/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
826 * \param *mol total molecule
827 * \param *Leaf fragment molecule
828 * \param &Leaflet pointer to KeySet structure
829 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
830 * \return number of atoms in fragment
831 */
832int StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
833{
834 atom *FatherOfRunner = NULL;
835
836 Leaf->BondDistance = mol->BondDistance;
837 for(int i=NDIM*2;i--;)
838 Leaf->cell_size[i] = mol->cell_size[i];
839
840 // first create the minimal set of atoms from the KeySet
841 int size = 0;
842 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
843 FatherOfRunner = mol->FindAtom((*runner)); // find the id
844 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner);
845 size++;
846 }
847 return size;
848};
849
850/** Creates an induced subgraph out of a fragmental key set, adding bonds and hydrogens (if treated specially).
851 * \param *out output stream for debugging messages
852 * \param *mol total molecule
853 * \param *Leaf fragment molecule
854 * \param IsAngstroem whether we have Ansgtroem or bohrradius
855 * \param **SonList list which atom of \a *Leaf is a son of which atom in \a *mol
856 */
857void CreateInducedSubgraphOfFragment(ofstream *out, molecule *mol, molecule *Leaf, atom **SonList, bool IsAngstroem)
858{
859 bool LonelyFlag = false;
860 atom *OtherFather = NULL;
861 atom *FatherOfRunner = NULL;
862 Leaf->CountAtoms(out);
863
864 atom *Runner = Leaf->start;
865 while (Runner->next != Leaf->end) {
866 Runner = Runner->next;
867 LonelyFlag = true;
868 FatherOfRunner = Runner->father;
869 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list
870 // create all bonds
871 for (BondList::const_iterator BondRunner = FatherOfRunner->ListOfBonds.begin(); BondRunner != FatherOfRunner->ListOfBonds.end(); (++BondRunner)) {
872 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
873// *out << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
874 if (SonList[OtherFather->nr] != NULL) {
875// *out << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
876 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
877// *out << Verbose(3) << "Adding Bond: ";
878// *out <<
879 Leaf->AddBond(Runner, SonList[OtherFather->nr], (*BondRunner)->BondDegree);
880// *out << "." << endl;
881 //NumBonds[Runner->nr]++;
882 } else {
883// *out << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
884 }
885 LonelyFlag = false;
886 } else {
887// *out << ", who has no son in this fragment molecule." << endl;
888#ifdef ADDHYDROGEN
889 //*out << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl;
890 if(!Leaf->AddHydrogenReplacementAtom(out, (*BondRunner), Runner, FatherOfRunner, OtherFather, IsAngstroem))
891 exit(1);
892#endif
893 //NumBonds[Runner->nr] += Binder->BondDegree;
894 }
895 }
896 } else {
897 *out << Verbose(0) << "ERROR: Son " << Runner->Name << " has father " << FatherOfRunner->Name << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl;
898 }
899 if ((LonelyFlag) && (Leaf->AtomCount > 1)) {
900 *out << Verbose(0) << *Runner << "has got bonds only to hydrogens!" << endl;
901 }
902#ifdef ADDHYDROGEN
903 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen
904 Runner = Runner->next;
905#endif
906 }
907};
908
909/** Stores a fragment from \a KeySet into \a molecule.
910 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
911 * molecule and adds missing hydrogen where bonds were cut.
912 * \param *out output stream for debugging messages
913 * \param &Leaflet pointer to KeySet structure
914 * \param IsAngstroem whether we have Ansgtroem or bohrradius
915 * \return pointer to constructed molecule
916 */
917molecule * molecule::StoreFragmentFromKeySet(ofstream *out, KeySet &Leaflet, bool IsAngstroem)
918{
919 atom **SonList = Calloc<atom*>(AtomCount, "molecule::StoreFragmentFromStack: **SonList");
920 molecule *Leaf = new molecule(elemente);
921
922// *out << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
923 StoreFragmentFromKeySet_Init(this, Leaf, Leaflet, SonList);
924 // create the bonds between all: Make it an induced subgraph and add hydrogen
925// *out << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
926 CreateInducedSubgraphOfFragment(out, this, Leaf, SonList, IsAngstroem);
927
928 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
929 Free(&SonList);
930// *out << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
931 return Leaf;
932};
933
934
935/** Clears the touched list
936 * \param *out output stream for debugging
937 * \param verbosity verbosity level
938 * \param *&TouchedList touched list
939 * \param SubOrder current suborder
940 * \param TouchedIndex currently touched
941 */
942void SPFragmentGenerator_ClearingTouched(ofstream *out, int verbosity, int *&TouchedList, int SubOrder, int &TouchedIndex)
943{
944 *out << Verbose(1+verbosity) << "Clearing touched list." << endl;
945 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
946 TouchedList[TouchedIndex] = -1;
947 TouchedIndex = 0;
948
949}
950
951/** Adds the current combination of the power set to the snake stack.
952 * \param *out output stream for debugging
953 * \param verbosity verbosity level
954 * \param CurrentCombination
955 * \param SetDimension maximum number of bits in power set
956 * \param *FragmentSet snake stack to remove from
957 * \param *&TouchedList touched list
958 * \param TouchedIndex currently touched
959 * \return number of set bits
960 */
961int AddPowersetToSnakeStack(ofstream *out, int verbosity, int CurrentCombination, int SetDimension, KeySet *FragmentSet, bond **BondsSet, int *&TouchedList, int &TouchedIndex)
962{
963 atom *OtherWalker = NULL;
964 bool bit = false;
965 KeySetTestPair TestKeySetInsert;
966
967 int Added = 0;
968 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
969 bit = ((CurrentCombination & (1 << j)) != 0); // mask the bit for the j-th bond
970 if (bit) { // if bit is set, we add this bond partner
971 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
972 //*out << Verbose(1+verbosity) << "Current Bond is " << BondsSet[j] << ", checking on " << *OtherWalker << "." << endl;
973 *out << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
974 TestKeySetInsert = FragmentSet->insert(OtherWalker->nr);
975 if (TestKeySetInsert.second) {
976 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
977 Added++;
978 } else {
979 *out << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
980 }
981 } else {
982 *out << Verbose(2+verbosity) << "Not adding." << endl;
983 }
984 }
985 return Added;
986};
987
988/** Counts the number of elements in a power set.
989 * \param *SetFirst
990 * \param *SetLast
991 * \param *&TouchedList touched list
992 * \param TouchedIndex currently touched
993 * \return number of elements
994 */
995int CountSetMembers(bond *SetFirst, bond *SetLast, int *&TouchedList, int TouchedIndex)
996{
997 int SetDimension = 0;
998 bond *Binder = SetFirst; // start node for this level
999 while (Binder->next != SetLast) { // compare to end node of this level
1000 Binder = Binder->next;
1001 for (int k=TouchedIndex;k--;) {
1002 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
1003 SetDimension++;
1004 }
1005 }
1006 return SetDimension;
1007};
1008
1009/** Counts the number of elements in a power set.
1010 * \param *BondsList bonds list to fill
1011 * \param *SetFirst
1012 * \param *SetLast
1013 * \param *&TouchedList touched list
1014 * \param TouchedIndex currently touched
1015 * \return number of elements
1016 */
1017int FillBondsList(bond **BondsList, bond *SetFirst, bond *SetLast, int *&TouchedList, int TouchedIndex)
1018{
1019 int SetDimension = 0;
1020 bond *Binder = SetFirst; // start node for this level
1021 while (Binder->next != SetLast) { // compare to end node of this level
1022 Binder = Binder->next;
1023 for (int k=0;k<TouchedIndex;k++) {
1024 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
1025 BondsList[SetDimension++] = Binder;
1026 }
1027 }
1028 return SetDimension;
1029};
1030
1031/** Remove all items that were added on this SP level.
1032 * \param *out output stream for debugging
1033 * \param verbosity verbosity level
1034 * \param *FragmentSet snake stack to remove from
1035 * \param *&TouchedList touched list
1036 * \param TouchedIndex currently touched
1037 */
1038void RemoveAllTouchedFromSnakeStack(ofstream *out, int verbosity, KeySet *FragmentSet, int *&TouchedList, int &TouchedIndex)
1039{
1040 int Removal = 0;
1041 for(int j=0;j<TouchedIndex;j++) {
1042 Removal = TouchedList[j];
1043 *out << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
1044 FragmentSet->erase(Removal);
1045 TouchedList[j] = -1;
1046 }
1047 *out << Verbose(2) << "Remaining local nr.s on snake stack are: ";
1048 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
1049 *out << (*runner) << " ";
1050 *out << endl;
1051 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
1052};
1053
1054/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
1055 * -# loops over every possible combination (2^dimension of edge set)
1056 * -# inserts current set, if there's still space left
1057 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
1058ance+1
1059 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
1060 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
1061distance) and current set
1062 * \param *out output stream for debugging
1063 * \param FragmentSearch UniqueFragments structure with all values needed
1064 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
1065 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
1066 * \param SubOrder remaining number of allowed vertices to add
1067 */
1068void molecule::SPFragmentGenerator(ofstream *out, struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
1069{
1070 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
1071 int NumCombinations;
1072 int bits, TouchedIndex, SubSetDimension, SP, Added;
1073 int SpaceLeft;
1074 int *TouchedList = Malloc<int>(SubOrder + 1, "molecule::SPFragmentGenerator: *TouchedList");
1075 bond **BondsList = NULL;
1076 KeySetTestPair TestKeySetInsert;
1077
1078 NumCombinations = 1 << SetDimension;
1079
1080 // here for all bonds of Walker all combinations of end pieces (from the bonds)
1081 // have to be added and for the remaining ANOVA order GraphCrawler be called
1082 // recursively for the next level
1083
1084 *out << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
1085 *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;
1086
1087 // initialised touched list (stores added atoms on this level)
1088 SPFragmentGenerator_ClearingTouched(out, verbosity, TouchedList, SubOrder, TouchedIndex);
1089
1090 // create every possible combination of the endpieces
1091 *out << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
1092 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
1093 // count the set bit of i
1094 bits = 0;
1095 for (int j=SetDimension;j--;)
1096 bits += (i & (1 << j)) >> j;
1097
1098 *out << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
1099 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
1100 // --1-- add this set of the power set of bond partners to the snake stack
1101 Added = AddPowersetToSnakeStack(out, verbosity, i, SetDimension, FragmentSearch->FragmentSet, BondsSet, TouchedList, TouchedIndex);
1102
1103 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
1104 if (SpaceLeft > 0) {
1105 *out << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
1106 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
1107 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
1108 SP = RootDistance+1; // this is the next level
1109
1110 // first count the members in the subset
1111 SubSetDimension = CountSetMembers(FragmentSearch->BondsPerSPList[2*SP], FragmentSearch->BondsPerSPList[2*SP+1], TouchedList, TouchedIndex);
1112
1113 // then allocate and fill the list
1114 BondsList = Malloc<bond*>(SubSetDimension, "molecule::SPFragmentGenerator: **BondsList");
1115 SubSetDimension = FillBondsList(BondsList, FragmentSearch->BondsPerSPList[2*SP], FragmentSearch->BondsPerSPList[2*SP+1], TouchedList, TouchedIndex);
1116
1117 // then iterate
1118 *out << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
1119 SPFragmentGenerator(out, FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
1120
1121 Free(&BondsList);
1122 }
1123 } else {
1124 // --2-- otherwise store the complete fragment
1125 *out << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
1126 // store fragment as a KeySet
1127 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
1128 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
1129 *out << (*runner) << " ";
1130 *out << endl;
1131 //if (!CheckForConnectedSubgraph(out, FragmentSearch->FragmentSet))
1132 //*out << Verbose(0) << "ERROR: The found fragment is not a connected subgraph!" << endl;
1133 InsertFragmentIntoGraph(out, FragmentSearch);
1134 }
1135
1136 // --3-- remove all added items in this level from snake stack
1137 *out << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
1138 RemoveAllTouchedFromSnakeStack(out, verbosity, FragmentSearch->FragmentSet, TouchedList, TouchedIndex);
1139 } else {
1140 *out << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
1141 }
1142 }
1143 Free(&TouchedList);
1144 *out << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
1145};
1146
1147/** Allocates memory for UniqueFragments::BondsPerSPList.
1148 * \param *out output stream
1149 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1150 * \param FragmentSearch UniqueFragments
1151 * \sa FreeSPList()
1152 */
1153void InitialiseSPList(ofstream *out, int Order, struct UniqueFragments &FragmentSearch)
1154{
1155 FragmentSearch.BondsPerSPList = Malloc<bond*>(Order * 2, "molecule::PowerSetGenerator: ***BondsPerSPList");
1156 FragmentSearch.BondsPerSPCount = Malloc<int>(Order, "molecule::PowerSetGenerator: *BondsPerSPCount");
1157 for (int i=Order;i--;) {
1158 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node
1159 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node
1160 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two
1161 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i];
1162 FragmentSearch.BondsPerSPCount[i] = 0;
1163 }
1164};
1165
1166/** Free's memory for for UniqueFragments::BondsPerSPList.
1167 * \param *out output stream
1168 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1169 * \param FragmentSearch UniqueFragments\
1170 * \sa InitialiseSPList()
1171 */
1172void FreeSPList(ofstream *out, int Order, struct UniqueFragments &FragmentSearch)
1173{
1174 Free(&FragmentSearch.BondsPerSPCount);
1175 for (int i=Order;i--;) {
1176 delete(FragmentSearch.BondsPerSPList[2*i]);
1177 delete(FragmentSearch.BondsPerSPList[2*i+1]);
1178 }
1179 Free(&FragmentSearch.BondsPerSPList);
1180};
1181
1182/** Sets FragmenSearch to initial value.
1183 * Sets UniqueFragments::ShortestPathList entries to zero, UniqueFragments::BondsPerSPCount to zero (except zero level to 1) and
1184 * adds initial bond UniqueFragments::Root to UniqueFragments::Root to UniqueFragments::BondsPerSPList
1185 * \param *out output stream
1186 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1187 * \param FragmentSearch UniqueFragments
1188 * \sa FreeSPList()
1189 */
1190void SetSPList(ofstream *out, int Order, struct UniqueFragments &FragmentSearch)
1191{
1192 // prepare Label and SP arrays of the BFS search
1193 FragmentSearch.ShortestPathList[FragmentSearch.Root->nr] = 0;
1194
1195 // prepare root level (SP = 0) and a loop bond denoting Root
1196 for (int i=Order;i--;)
1197 FragmentSearch.BondsPerSPCount[i] = 0;
1198 FragmentSearch.BondsPerSPCount[0] = 1;
1199 bond *Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
1200 add(Binder, FragmentSearch.BondsPerSPList[1]);
1201};
1202
1203/** Resets UniqueFragments::ShortestPathList and cleans bonds from UniqueFragments::BondsPerSPList.
1204 * \param *out output stream
1205 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1206 * \param FragmentSearch UniqueFragments
1207 * \sa InitialiseSPList()
1208 */
1209void ResetSPList(ofstream *out, int Order, struct UniqueFragments &FragmentSearch)
1210{
1211 bond *Binder = NULL;
1212 *out << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl;
1213 for(int i=Order;i--;) {
1214 *out << Verbose(1) << "Current SP level is " << i << ": ";
1215 Binder = FragmentSearch.BondsPerSPList[2*i];
1216 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
1217 Binder = Binder->next;
1218 // *out << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local
1219 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1;
1220 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1;
1221 }
1222 // delete added bonds
1223 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]);
1224 // also start and end node
1225 *out << "cleaned." << endl;
1226 }
1227};
1228
1229
1230/** Fills the Bonds per Shortest Path List and set the vertex labels.
1231 * \param *out output stream
1232 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1233 * \param FragmentSearch UniqueFragments
1234 * \param *mol molecule with atoms and bonds
1235 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
1236 */
1237void FillSPListandLabelVertices(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, molecule *mol, KeySet RestrictedKeySet)
1238{
1239 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into
1240 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning
1241 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth
1242 // (EdgeinSPLevel) of this tree ...
1243 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence
1244 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction.
1245 int AtomKeyNr = -1;
1246 atom *Walker = NULL;
1247 atom *OtherWalker = NULL;
1248 atom *Predecessor = NULL;
1249 bond *CurrentEdge = NULL;
1250 bond *Binder = NULL;
1251 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->nr;
1252 int RemainingWalkers = -1;
1253 int SP = -1;
1254
1255 *out << Verbose(0) << "Starting BFS analysis ..." << endl;
1256 for (SP = 0; SP < (Order-1); SP++) {
1257 *out << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)";
1258 if (SP > 0) {
1259 *out << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl;
1260 FragmentSearch.BondsPerSPCount[SP] = 0;
1261 } else
1262 *out << "." << endl;
1263
1264 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
1265 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP]; /// start of this SP level's list
1266 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) { /// end of this SP level's list
1267 CurrentEdge = CurrentEdge->next;
1268 RemainingWalkers--;
1269 Walker = CurrentEdge->rightatom; // rightatom is always the one more distant
1270 Predecessor = CurrentEdge->leftatom; // ... and leftatom is predecessor
1271 AtomKeyNr = Walker->nr;
1272 *out << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl;
1273 // check for new sp level
1274 // go through all its bonds
1275 *out << Verbose(1) << "Going through all bonds of Walker." << endl;
1276 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1277 OtherWalker = (*Runner)->GetOtherAtom(Walker);
1278 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end())
1279 #ifdef ADDHYDROGEN
1280 && (OtherWalker->type->Z != 1)
1281 #endif
1282 ) { // skip hydrogens and restrict to fragment
1283 *out << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *(*Runner) << "." << endl;
1284 // set the label if not set (and push on root stack as well)
1285 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->nr > RootKeyNr)) { // only pass through those with label bigger than Root's
1286 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1;
1287 *out << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl;
1288 // add the bond in between to the SP list
1289 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
1290 add(Binder, FragmentSearch.BondsPerSPList[2*(SP+1)+1]);
1291 FragmentSearch.BondsPerSPCount[SP+1]++;
1292 *out << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl;
1293 } else {
1294 if (OtherWalker != Predecessor)
1295 *out << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->nr << " is smaller than that of Root " << RootKeyNr << "." << endl;
1296 else
1297 *out << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl;
1298 }
1299 } else *out << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
1300 }
1301 }
1302 }
1303};
1304
1305/** prints the Bonds per Shortest Path list in UniqueFragments.
1306 * \param *out output stream
1307 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1308 * \param FragmentSearch UniqueFragments
1309 */
1310void OutputSPList(ofstream *out, int Order, struct UniqueFragments &FragmentSearch)
1311{
1312 bond *Binder = NULL;
1313 *out << Verbose(0) << "Printing all found lists." << endl;
1314 for(int i=1;i<Order;i++) { // skip the root edge in the printing
1315 Binder = FragmentSearch.BondsPerSPList[2*i];
1316 *out << Verbose(1) << "Current SP level is " << i << "." << endl;
1317 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
1318 Binder = Binder->next;
1319 *out << Verbose(2) << *Binder << endl;
1320 }
1321 }
1322};
1323
1324/** Simply counts all bonds in all UniqueFragments::BondsPerSPList lists.
1325 * \param *out output stream
1326 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1327 * \param FragmentSearch UniqueFragments
1328 */
1329int CountNumbersInBondsList(ofstream *out, int Order, struct UniqueFragments &FragmentSearch)
1330{
1331 bond *Binder = NULL;
1332 int SP = -1; // the Root <-> Root edge must be subtracted!
1333 for(int i=Order;i--;) { // sum up all found edges
1334 Binder = FragmentSearch.BondsPerSPList[2*i];
1335 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
1336 Binder = Binder->next;
1337 SP++;
1338 }
1339 }
1340 return SP;
1341};
1342
1343/** 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.
1344 * -# initialises UniqueFragments structure
1345 * -# fills edge list via BFS
1346 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
1347 root distance, the edge set, its dimension and the current suborder
1348 * -# Free'ing structure
1349 * 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
1350 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
1351 * \param *out output stream for debugging
1352 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
1353 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
1354 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
1355 * \return number of inserted fragments
1356 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
1357 */
1358int molecule::PowerSetGenerator(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
1359{
1360 bond **BondsList = NULL;
1361 int Counter = FragmentSearch.FragmentCounter; // mark current value of counter
1362
1363 *out << endl;
1364 *out << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl;
1365
1366 SetSPList(out, Order, FragmentSearch);
1367
1368 // do a BFS search to fill the SP lists and label the found vertices
1369 FillSPListandLabelVertices(out, Order, FragmentSearch, this, RestrictedKeySet);
1370
1371 // outputting all list for debugging
1372 OutputSPList(out, Order, FragmentSearch);
1373
1374 // creating fragments with the found edge sets (may be done in reverse order, faster)
1375 int SP = CountNumbersInBondsList(out, Order, FragmentSearch);
1376 *out << Verbose(0) << "Total number of edges is " << SP << "." << endl;
1377 if (SP >= (Order-1)) {
1378 // start with root (push on fragment stack)
1379 *out << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->nr << "." << endl;
1380 FragmentSearch.FragmentSet->clear();
1381 *out << Verbose(0) << "Preparing subset for this root and calling generator." << endl;
1382
1383 // prepare the subset and call the generator
1384 BondsList = Calloc<bond*>(FragmentSearch.BondsPerSPCount[0], "molecule::PowerSetGenerator: **BondsList");
1385 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond
1386
1387 SPFragmentGenerator(out, &FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
1388
1389 Free(&BondsList);
1390 } else {
1391 *out << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl;
1392 }
1393
1394 // as FragmentSearch structure is used only once, we don't have to clean it anymore
1395 // remove root from stack
1396 *out << Verbose(0) << "Removing root again from stack." << endl;
1397 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr);
1398
1399 // free'ing the bonds lists
1400 ResetSPList(out, Order, FragmentSearch);
1401
1402 // return list
1403 *out << Verbose(0) << "End of PowerSetGenerator." << endl;
1404 return (FragmentSearch.FragmentCounter - Counter);
1405};
1406
1407bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
1408{
1409 //cout << "my check is used." << endl;
1410 if (SubgraphA.size() < SubgraphB.size()) {
1411 return true;
1412 } else {
1413 if (SubgraphA.size() > SubgraphB.size()) {
1414 return false;
1415 } else {
1416 KeySet::iterator IteratorA = SubgraphA.begin();
1417 KeySet::iterator IteratorB = SubgraphB.begin();
1418 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
1419 if ((*IteratorA) < (*IteratorB))
1420 return true;
1421 else if ((*IteratorA) > (*IteratorB)) {
1422 return false;
1423 } // else, go on to next index
1424 IteratorA++;
1425 IteratorB++;
1426 } // end of while loop
1427 }// end of check in case of equal sizes
1428 }
1429 return false; // if we reach this point, they are equal
1430};
1431
1432
1433/** Combines all KeySets from all orders into single ones (with just unique entries).
1434 * \param *out output stream for debugging
1435 * \param *&FragmentList list to fill
1436 * \param ***FragmentLowerOrdersList
1437 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1438 * \param *mol molecule with atoms and bonds
1439 */
1440int CombineAllOrderListIntoOne(ofstream *out, Graph *&FragmentList, Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol)
1441{
1442 int RootNr = 0;
1443 int RootKeyNr = 0;
1444 int StartNr = 0;
1445 int counter = 0;
1446 int NumLevels = 0;
1447 atom *Walker = NULL;
1448
1449 *out << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl;
1450 if (FragmentList == NULL) {
1451 FragmentList = new Graph;
1452 counter = 0;
1453 } else {
1454 counter = FragmentList->size();
1455 }
1456
1457 StartNr = RootStack.back();
1458 do {
1459 RootKeyNr = RootStack.front();
1460 RootStack.pop_front();
1461 Walker = mol->FindAtom(RootKeyNr);
1462 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
1463 for(int i=0;i<NumLevels;i++) {
1464 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
1465 InsertGraphIntoGraph(out, *FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
1466 }
1467 }
1468 RootStack.push_back(Walker->nr);
1469 RootNr++;
1470 } while (RootKeyNr != StartNr);
1471 return counter;
1472};
1473
1474/** Free's memory allocated for all KeySets from all orders.
1475 * \param *out output stream for debugging
1476 * \param ***FragmentLowerOrdersList
1477 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1478 * \param *mol molecule with atoms and bonds
1479 */
1480void FreeAllOrdersList(ofstream *out, Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol)
1481{
1482 *out << Verbose(1) << "Free'ing the lists of all orders per order." << endl;
1483 int RootNr = 0;
1484 int RootKeyNr = 0;
1485 int NumLevels = 0;
1486 atom *Walker = NULL;
1487 while (!RootStack.empty()) {
1488 RootKeyNr = RootStack.front();
1489 RootStack.pop_front();
1490 Walker = mol->FindAtom(RootKeyNr);
1491 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
1492 for(int i=0;i<NumLevels;i++) {
1493 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
1494 delete(FragmentLowerOrdersList[RootNr][i]);
1495 }
1496 }
1497 Free(&FragmentLowerOrdersList[RootNr]);
1498 RootNr++;
1499 }
1500 Free(&FragmentLowerOrdersList);
1501};
1502
1503
1504/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
1505 * -# constructs a complete keyset of the molecule
1506 * -# In a loop over all possible roots from the given rootstack
1507 * -# increases order of root site
1508 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
1509 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
1510as the restricted one and each site in the set as the root)
1511 * -# these are merged into a fragment list of keysets
1512 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
1513 * Important only is that we create all fragments, it is not important if we create them more than once
1514 * as these copies are filtered out via use of the hash table (KeySet).
1515 * \param *out output stream for debugging
1516 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
1517 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
1518 * \param *MinimumRingSize minimum ring size for each atom (molecule::Atomcount)
1519 * \return pointer to Graph list
1520 */
1521void molecule::FragmentBOSSANOVA(ofstream *out, Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize)
1522{
1523 Graph ***FragmentLowerOrdersList = NULL;
1524 int NumLevels = 0;
1525 int NumMolecules = 0;
1526 int TotalNumMolecules = 0;
1527 int *NumMoleculesOfOrder = NULL;
1528 int Order = 0;
1529 int UpgradeCount = RootStack.size();
1530 KeyStack FragmentRootStack;
1531 int RootKeyNr = 0;
1532 int RootNr = 0;
1533 struct UniqueFragments FragmentSearch;
1534
1535 *out << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl;
1536
1537 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
1538 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
1539 NumMoleculesOfOrder = Calloc<int>(UpgradeCount, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
1540 FragmentLowerOrdersList = Calloc<Graph**>(UpgradeCount, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
1541
1542 // initialise the fragments structure
1543 FragmentSearch.FragmentCounter = 0;
1544 FragmentSearch.FragmentSet = new KeySet;
1545 FragmentSearch.Root = FindAtom(RootKeyNr);
1546 FragmentSearch.ShortestPathList = Malloc<int>(AtomCount, "molecule::PowerSetGenerator: *ShortestPathList");
1547 for (int i=AtomCount;i--;) {
1548 FragmentSearch.ShortestPathList[i] = -1;
1549 }
1550
1551 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
1552 atom *Walker = start;
1553 KeySet CompleteMolecule;
1554 while (Walker->next != end) {
1555 Walker = Walker->next;
1556 CompleteMolecule.insert(Walker->GetTrueFather()->nr);
1557 }
1558
1559 // 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
1560 // 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),
1561 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
1562 // 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)
1563 RootNr = 0; // counts through the roots in RootStack
1564 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
1565 RootKeyNr = RootStack.front();
1566 RootStack.pop_front();
1567 Walker = FindAtom(RootKeyNr);
1568 // check cyclic lengths
1569 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) {
1570 // *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;
1571 //} else
1572 {
1573 // increase adaptive order by one
1574 Walker->GetTrueFather()->AdaptiveOrder++;
1575 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
1576
1577 // initialise Order-dependent entries of UniqueFragments structure
1578 InitialiseSPList(out, Order, FragmentSearch);
1579
1580 // allocate memory for all lower level orders in this 1D-array of ptrs
1581 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
1582 FragmentLowerOrdersList[RootNr] = Calloc<Graph*>(NumLevels, "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
1583
1584 // create top order where nothing is reduced
1585 *out << Verbose(0) << "==============================================================================================================" << endl;
1586 *out << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl; // , NumLevels is " << NumLevels << "
1587
1588 // Create list of Graphs of current Bond Order (i.e. F_{ij})
1589 FragmentLowerOrdersList[RootNr][0] = new Graph;
1590 FragmentSearch.TEFactor = 1.;
1591 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
1592 FragmentSearch.Root = Walker;
1593 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(out, Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
1594
1595 // output resulting number
1596 *out << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
1597 if (NumMoleculesOfOrder[RootNr] != 0) {
1598 NumMolecules = 0;
1599 } else {
1600 Walker->GetTrueFather()->MaxOrder = true;
1601 }
1602 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
1603 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
1604 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
1605// *out << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
1606 RootStack.push_back(RootKeyNr); // put back on stack
1607 RootNr++;
1608
1609 // free Order-dependent entries of UniqueFragments structure for next loop cycle
1610 FreeSPList(out, Order, FragmentSearch);
1611 }
1612 }
1613 *out << Verbose(0) << "==============================================================================================================" << endl;
1614 *out << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl;
1615 *out << Verbose(0) << "==============================================================================================================" << endl;
1616
1617 // cleanup FragmentSearch structure
1618 Free(&FragmentSearch.ShortestPathList);
1619 delete(FragmentSearch.FragmentSet);
1620
1621 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
1622 // 5433222211111111
1623 // 43221111
1624 // 3211
1625 // 21
1626 // 1
1627
1628 // Subsequently, we combine all into a single list (FragmentList)
1629 CombineAllOrderListIntoOne(out, FragmentList, FragmentLowerOrdersList, RootStack, this);
1630 FreeAllOrdersList(out, FragmentLowerOrdersList, RootStack, this);
1631 Free(&NumMoleculesOfOrder);
1632
1633 *out << Verbose(0) << "End of FragmentBOSSANOVA." << endl;
1634};
1635
1636/** Corrects the nuclei position if the fragment was created over the cell borders.
1637 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
1638 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
1639 * and re-add the bond. Looping on the distance check.
1640 * \param *out ofstream for debugging messages
1641 */
1642void molecule::ScanForPeriodicCorrection(ofstream *out)
1643{
1644 bond *Binder = NULL;
1645 bond *OtherBinder = NULL;
1646 atom *Walker = NULL;
1647 atom *OtherWalker = NULL;
1648 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
1649 enum Shading *ColorList = NULL;
1650 double tmp;
1651 Vector Translationvector;
1652 //class StackClass<atom *> *CompStack = NULL;
1653 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
1654 bool flag = true;
1655
1656 *out << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl;
1657
1658 ColorList = Calloc<enum Shading>(AtomCount, "molecule::ScanForPeriodicCorrection: *ColorList");
1659 while (flag) {
1660 // remove bonds that are beyond bonddistance
1661 for(int i=NDIM;i--;)
1662 Translationvector.x[i] = 0.;
1663 // scan all bonds
1664 Binder = first;
1665 flag = false;
1666 while ((!flag) && (Binder->next != last)) {
1667 Binder = Binder->next;
1668 for (int i=NDIM;i--;) {
1669 tmp = fabs(Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]);
1670 //*out << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
1671 if (tmp > BondDistance) {
1672 OtherBinder = Binder->next; // note down binding partner for later re-insertion
1673 unlink(Binder); // unlink bond
1674 *out << Verbose(2) << "Correcting at bond " << *Binder << "." << endl;
1675 flag = true;
1676 break;
1677 }
1678 }
1679 }
1680 if (flag) {
1681 // create translation vector from their periodically modified distance
1682 for (int i=NDIM;i--;) {
1683 tmp = Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i];
1684 if (fabs(tmp) > BondDistance)
1685 Translationvector.x[i] = (tmp < 0) ? +1. : -1.;
1686 }
1687 Translationvector.MatrixMultiplication(matrix);
1688 //*out << Verbose(3) << "Translation vector is ";
1689 Translationvector.Output(out);
1690 *out << endl;
1691 // apply to all atoms of first component via BFS
1692 for (int i=AtomCount;i--;)
1693 ColorList[i] = white;
1694 AtomStack->Push(Binder->leftatom);
1695 while (!AtomStack->IsEmpty()) {
1696 Walker = AtomStack->PopFirst();
1697 //*out << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
1698 ColorList[Walker->nr] = black; // mark as explored
1699 Walker->x.AddVector(&Translationvector); // translate
1700 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1701 if ((*Runner) != Binder) {
1702 OtherWalker = (*Runner)->GetOtherAtom(Walker);
1703 if (ColorList[OtherWalker->nr] == white) {
1704 AtomStack->Push(OtherWalker); // push if yet unexplored
1705 }
1706 }
1707 }
1708 }
1709 // re-add bond
1710 link(Binder, OtherBinder);
1711 } else {
1712 *out << Verbose(3) << "No corrections for this fragment." << endl;
1713 }
1714 //delete(CompStack);
1715 }
1716
1717 // free allocated space from ReturnFullMatrixforSymmetric()
1718 delete(AtomStack);
1719 Free(&ColorList);
1720 Free(&matrix);
1721 *out << Verbose(2) << "End of ScanForPeriodicCorrection." << endl;
1722};
Note: See TracBrowser for help on using the repository browser.