source: src/molecule_fragmentation.cpp@ 920c70

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

Removed all Malloc/Calloc/ReAlloc (&Free) and replaced by new and delete/delete[].

Due to the new MemDebug framework there is no need (or even unnecessary/unwanted competition between it and) for the MemoryAllocator and ..UsageObserver anymore.
They can however still be used with c codes such as pcp and alikes.

In Molecuilder lots of glibc corruptions arose and the C-like syntax make it generally harder to get allocation and deallocation straight.

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

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