source: src/molecule_fragmentation.cpp@ e30ce8

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

FIX: Test Fragmentation is at MaxOrder was broken.

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