source: src/molecule_fragmentation.cpp@ 5b9bba

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

Fixing ticket #18.

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