source: src/molecule_fragmentation.cpp@ 3b9e34

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

Huge change: Log() << Verbose(.) --> DoLog(.) && (Log() << Verbose(.) << ...);

Most of the files are affected, but this is necessary as if DoLog() says verbosity is not enough, all the stream operators won"t get executed which saves substantial amount of computation time.

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

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