source: src/molecule_fragmentation.cpp@ 673c7f

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 673c7f was 8cbb97, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Merge branch 'VectorRefactoring' into StructureRefactoring

Conflicts:

molecuilder/src/Legacy/oldmenu.cpp
molecuilder/src/Makefile.am
molecuilder/src/analysis_correlation.cpp
molecuilder/src/boundary.cpp
molecuilder/src/builder.cpp
molecuilder/src/config.cpp
molecuilder/src/ellipsoid.cpp
molecuilder/src/linkedcell.cpp
molecuilder/src/molecule.cpp
molecuilder/src/molecule_fragmentation.cpp
molecuilder/src/molecule_geometry.cpp
molecuilder/src/molecule_graph.cpp
molecuilder/src/moleculelist.cpp
molecuilder/src/tesselation.cpp
molecuilder/src/tesselationhelpers.cpp
molecuilder/src/unittests/AnalysisCorrelationToSurfaceUnitTest.cpp
molecuilder/src/unittests/bondgraphunittest.cpp
molecuilder/src/vector.cpp
molecuilder/src/vector.hpp

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