source: src/molecule_fragmentation.cpp@ 42af9e

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 Candidate_v1.7.0 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 42af9e was 42af9e, checked in by Frederik Heber <heber@…>, 15 years ago

MEMFIXES: no more default saving/loading of element's db, config::SaveTREMOLO(), molecule::CreateMappingLabelsToConfigSequence()

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
519 return true;
520};
521
522/** Performs a many-body bond order analysis for a given bond order.
523 * -# parses adjacency, keysets and orderatsite files
524 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
525 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
526y contribution", and that's why this consciously not done in the following loop)
527 * -# in a loop over all subgraphs
528 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
529 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
530 * -# combines the generated molecule lists from all subgraphs
531 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
532 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
533 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
534 * subgraph in the MoleculeListClass.
535 * \param *out output stream for debugging
536 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
537 * \param *configuration configuration for writing config files for each fragment
538 * \return 1 - continue, 2 - stop (no fragmentation occured)
539 */
540int molecule::FragmentMolecule(int Order, config *configuration)
541{
542 MoleculeListClass *BondFragments = NULL;
543 int *MinimumRingSize = new int[AtomCount];
544 int FragmentCounter;
545 MoleculeLeafClass *MolecularWalker = NULL;
546 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
547 fstream File;
548 bool FragmentationToDo = true;
549 class StackClass<bond *> *BackEdgeStack = NULL, *LocalBackEdgeStack = NULL;
550 bool CheckOrder = false;
551 Graph **FragmentList = NULL;
552 Graph *ParsedFragmentList = NULL;
553 Graph TotalGraph; // graph with all keysets however local numbers
554 int TotalNumberOfKeySets = 0;
555 atom **ListOfAtoms = NULL;
556 atom ***ListOfLocalAtoms = NULL;
557 bool *AtomMask = NULL;
558
559 DoLog(0) && (Log() << Verbose(0) << endl);
560#ifdef ADDHYDROGEN
561 DoLog(0) && (Log() << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl);
562#else
563 DoLog(0) && (Log() << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl);
564#endif
565
566 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
567
568 // ===== 1. Check whether bond structure is same as stored in files ====
569
570 // create lookup table for Atom::nr
571 FragmentationToDo = FragmentationToDo && CreateFatherLookupTable(start, end, ListOfAtoms, AtomCount);
572
573 // === compare it with adjacency file ===
574 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(configuration->configpath, ListOfAtoms);
575 delete[](ListOfAtoms);
576
577 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
578 Subgraphs = DepthFirstSearchAnalysis(BackEdgeStack);
579
580 // analysis of the cycles (print rings, get minimum cycle length) for each subgraph
581 for(int i=AtomCount;i--;)
582 MinimumRingSize[i] = AtomCount;
583 MolecularWalker = Subgraphs;
584 FragmentCounter = 0;
585 while (MolecularWalker->next != NULL) {
586 MolecularWalker = MolecularWalker->next;
587 // fill the bond structure of the individually stored subgraphs
588 MolecularWalker->FillBondStructureFromReference(this, FragmentCounter, ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms
589 DoLog(0) && (Log() << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
590 LocalBackEdgeStack = new StackClass<bond *> (MolecularWalker->Leaf->BondCount);
591// // check the list of local atoms for debugging
592// Log() << Verbose(0) << "ListOfLocalAtoms for this subgraph is:" << endl;
593// for (int i=0;i<AtomCount;i++)
594// if (ListOfLocalAtoms[FragmentCounter][i] == NULL)
595// Log() << Verbose(0) << "\tNULL";
596// else
597// Log() << Verbose(0) << "\t" << ListOfLocalAtoms[FragmentCounter][i]->Name;
598 DoLog(0) && (Log() << Verbose(0) << "Gathering local back edges for subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
599 MolecularWalker->Leaf->PickLocalBackEdges(ListOfLocalAtoms[FragmentCounter++], BackEdgeStack, LocalBackEdgeStack);
600 DoLog(0) && (Log() << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
601 MolecularWalker->Leaf->CyclicStructureAnalysis(LocalBackEdgeStack, MinimumRingSize);
602 DoLog(0) && (Log() << Verbose(0) << "Done with Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl);
603 delete(LocalBackEdgeStack);
604 }
605 delete(BackEdgeStack);
606
607 // ===== 3. if structure still valid, parse key set file and others =====
608 FragmentationToDo = FragmentationToDo && ParseKeySetFile(configuration->configpath, ParsedFragmentList);
609
610 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
611 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(configuration->configpath);
612
613 // =================================== Begin of FRAGMENTATION ===============================
614 // ===== 6a. assign each keyset to its respective subgraph =====
615 Subgraphs->next->AssignKeySetsToFragment(this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, (FragmentCounter = 0), true);
616
617 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
618 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
619 AtomMask = new bool[AtomCount+1];
620 AtomMask[AtomCount] = false;
621 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
622 while ((CheckOrder = CheckOrderAtSite(AtomMask, ParsedFragmentList, Order, MinimumRingSize, configuration->configpath))) {
623 FragmentationToDo = FragmentationToDo || CheckOrder;
624 AtomMask[AtomCount] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
625 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
626 Subgraphs->next->FillRootStackForSubgraphs(RootStack, AtomMask, (FragmentCounter = 0));
627
628 // ===== 7. fill the bond fragment list =====
629 FragmentCounter = 0;
630 MolecularWalker = Subgraphs;
631 while (MolecularWalker->next != NULL) {
632 MolecularWalker = MolecularWalker->next;
633 DoLog(1) && (Log() << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl);
634 //MolecularWalker->Leaf->OutputListOfBonds(out); // output atom::ListOfBonds for debugging
635 if (MolecularWalker->Leaf->first->next != MolecularWalker->Leaf->last) {
636 // call BOSSANOVA method
637 DoLog(0) && (Log() << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl);
638 MolecularWalker->Leaf->FragmentBOSSANOVA(FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize);
639 } else {
640 DoeLog(1) && (eLog()<< Verbose(1) << "Subgraph " << MolecularWalker << " has no atoms!" << endl);
641 }
642 FragmentCounter++; // next fragment list
643 }
644 }
645 DoLog(2) && (Log() << Verbose(2) << "CheckOrder is " << CheckOrder << "." << endl);
646 delete[](RootStack);
647 delete[](AtomMask);
648 delete(ParsedFragmentList);
649 delete[](MinimumRingSize);
650
651
652 // ==================================== End of FRAGMENTATION ============================================
653
654 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
655 Subgraphs->next->TranslateIndicesToGlobalIDs(FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
656
657 // free subgraph memory again
658 FragmentCounter = 0;
659 if (Subgraphs != NULL) {
660 while (Subgraphs->next != NULL) {
661 Subgraphs = Subgraphs->next;
662 delete(FragmentList[FragmentCounter++]);
663 delete(Subgraphs->previous);
664 }
665 delete(Subgraphs);
666 }
667 delete[](FragmentList);
668
669 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
670 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
671 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
672 BondFragments = new MoleculeListClass(World::getPointer());
673 int k=0;
674 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
675 KeySet test = (*runner).first;
676 DoLog(0) && (Log() << Verbose(0) << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl);
677 BondFragments->insert(StoreFragmentFromKeySet(test, configuration));
678 k++;
679 }
680 DoLog(0) && (Log() << Verbose(0) << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl);
681
682 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
683 if (BondFragments->ListOfMolecules.size() != 0) {
684 // create the SortIndex from BFS labels to order in the config file
685 int *SortIndex = NULL;
686 CreateMappingLabelsToConfigSequence(SortIndex);
687
688 DoLog(1) && (Log() << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl);
689 if (BondFragments->OutputConfigForListOfFragments(configuration, SortIndex))
690 DoLog(1) && (Log() << Verbose(1) << "All configs written." << endl);
691 else
692 DoLog(1) && (Log() << Verbose(1) << "Some config writing failed." << endl);
693
694 // store force index reference file
695 BondFragments->StoreForcesFile(configuration->configpath, SortIndex);
696
697 // store keysets file
698 StoreKeySetFile(TotalGraph, configuration->configpath);
699
700 {
701 // store Adjacency file
702 char filename[MAXSTRINGSIZE];
703 strcpy(filename, FRAGMENTPREFIX);
704 strcat(filename, ADJACENCYFILE);
705 StoreAdjacencyToFile(configuration->configpath, filename);
706 }
707
708 // store Hydrogen saturation correction file
709 BondFragments->AddHydrogenCorrection(configuration->configpath);
710
711 // store adaptive orders into file
712 StoreOrderAtSiteFile(configuration->configpath);
713
714 // restore orbital and Stop values
715 CalculateOrbitals(*configuration);
716
717 // free memory for bond part
718 DoLog(1) && (Log() << Verbose(1) << "Freeing bond memory" << endl);
719 delete[](SortIndex);
720 } else {
721 DoLog(1) && (Log() << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl);
722 }
723 delete(BondFragments);
724 DoLog(0) && (Log() << Verbose(0) << "End of bond fragmentation." << endl);
725
726 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
727};
728
729
730/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
731 * Atoms not present in the file get "-1".
732 * \param *out output stream for debugging
733 * \param *path path to file ORDERATSITEFILE
734 * \return true - file writable, false - not writable
735 */
736bool molecule::StoreOrderAtSiteFile(char *path)
737{
738 stringstream line;
739 ofstream file;
740
741 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
742 file.open(line.str().c_str());
743 DoLog(1) && (Log() << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl);
744 if (file != NULL) {
745 ActOnAllAtoms( &atom::OutputOrder, &file );
746 file.close();
747 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
748 return true;
749 } else {
750 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line.str() << "." << endl);
751 return false;
752 }
753};
754
755/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
756 * Atoms not present in the file get "0".
757 * \param *out output stream for debugging
758 * \param *path path to file ORDERATSITEFILEe
759 * \return true - file found and scanned, false - file not found
760 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
761 */
762bool molecule::ParseOrderAtSiteFromFile(char *path)
763{
764 unsigned char *OrderArray = new unsigned char[AtomCount];
765 bool *MaxArray = new bool[AtomCount];
766 bool status;
767 int AtomNr, value;
768 stringstream line;
769 ifstream file;
770
771 for(int i=0;i<AtomCount;i++) {
772 OrderArray[i] = 0;
773 MaxArray[i] = false;
774 }
775
776 DoLog(1) && (Log() << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl);
777 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
778 file.open(line.str().c_str());
779 if (file != NULL) {
780 while (!file.eof()) { // parse from file
781 AtomNr = -1;
782 file >> AtomNr;
783 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
784 file >> value;
785 OrderArray[AtomNr] = value;
786 file >> value;
787 MaxArray[AtomNr] = value;
788 //Log() << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
789 }
790 }
791 file.close();
792
793 // set atom values
794 SetAtomValueToIndexedArray( OrderArray, &atom::nr, &atom::AdaptiveOrder );
795 SetAtomValueToIndexedArray( MaxArray, &atom::nr, &atom::MaxOrder );
796
797 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
798 status = true;
799 } else {
800 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line.str() << "." << endl);
801 status = false;
802 }
803 delete[](OrderArray);
804 delete[](MaxArray);
805
806 DoLog(1) && (Log() << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl);
807 return status;
808};
809
810
811
812/** Looks through a StackClass<atom *> and returns the likeliest removal candiate.
813 * \param *out output stream for debugging messages
814 * \param *&Leaf KeySet to look through
815 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
816 * \param index of the atom suggested for removal
817 */
818int molecule::LookForRemovalCandidate(KeySet *&Leaf, int *&ShortestPathList)
819{
820 atom *Runner = NULL;
821 int SP, Removal;
822
823 DoLog(2) && (Log() << Verbose(2) << "Looking for removal candidate." << endl);
824 SP = -1; //0; // not -1, so that Root is never removed
825 Removal = -1;
826 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
827 Runner = FindAtom((*runner));
828 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack
829 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
830 SP = ShortestPathList[(*runner)];
831 Removal = (*runner);
832 }
833 }
834 }
835 return Removal;
836};
837
838/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
839 * \param *mol total molecule
840 * \param *Leaf fragment molecule
841 * \param &Leaflet pointer to KeySet structure
842 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
843 * \return number of atoms in fragment
844 */
845int StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
846{
847 atom *FatherOfRunner = NULL;
848
849 Leaf->BondDistance = mol->BondDistance;
850
851 // first create the minimal set of atoms from the KeySet
852 int size = 0;
853 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
854 FatherOfRunner = mol->FindAtom((*runner)); // find the id
855 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner);
856 size++;
857 }
858 return size;
859};
860
861/** Creates an induced subgraph out of a fragmental key set, adding bonds and hydrogens (if treated specially).
862 * \param *out output stream for debugging messages
863 * \param *mol total molecule
864 * \param *Leaf fragment molecule
865 * \param IsAngstroem whether we have Ansgtroem or bohrradius
866 * \param **SonList list which atom of \a *Leaf is a son of which atom in \a *mol
867 */
868void CreateInducedSubgraphOfFragment(molecule *mol, molecule *Leaf, atom **SonList, bool IsAngstroem)
869{
870 bool LonelyFlag = false;
871 atom *OtherFather = NULL;
872 atom *FatherOfRunner = NULL;
873 Leaf->CountAtoms();
874
875 atom *Runner = Leaf->start;
876 while (Runner->next != Leaf->end) {
877 Runner = Runner->next;
878 LonelyFlag = true;
879 FatherOfRunner = Runner->father;
880 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list
881 // create all bonds
882 for (BondList::const_iterator BondRunner = FatherOfRunner->ListOfBonds.begin(); BondRunner != FatherOfRunner->ListOfBonds.end(); (++BondRunner)) {
883 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
884// Log() << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
885 if (SonList[OtherFather->nr] != NULL) {
886// Log() << Verbose(0) << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
887 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
888// Log() << Verbose(3) << "Adding Bond: ";
889// Log() << Verbose(0) <<
890 Leaf->AddBond(Runner, SonList[OtherFather->nr], (*BondRunner)->BondDegree);
891// Log() << Verbose(0) << "." << endl;
892 //NumBonds[Runner->nr]++;
893 } else {
894// Log() << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
895 }
896 LonelyFlag = false;
897 } else {
898// Log() << Verbose(0) << ", who has no son in this fragment molecule." << endl;
899#ifdef ADDHYDROGEN
900 //Log() << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl;
901 if(!Leaf->AddHydrogenReplacementAtom((*BondRunner), Runner, FatherOfRunner, OtherFather, IsAngstroem))
902 exit(1);
903#endif
904 //NumBonds[Runner->nr] += Binder->BondDegree;
905 }
906 }
907 } else {
908 DoeLog(1) && (eLog()<< Verbose(1) << "Son " << Runner->getName() << " has father " << FatherOfRunner->getName() << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl);
909 }
910 if ((LonelyFlag) && (Leaf->AtomCount > 1)) {
911 DoLog(0) && (Log() << Verbose(0) << *Runner << "has got bonds only to hydrogens!" << endl);
912 }
913#ifdef ADDHYDROGEN
914 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen
915 Runner = Runner->next;
916#endif
917 }
918};
919
920/** Stores a fragment from \a KeySet into \a molecule.
921 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
922 * molecule and adds missing hydrogen where bonds were cut.
923 * \param *out output stream for debugging messages
924 * \param &Leaflet pointer to KeySet structure
925 * \param IsAngstroem whether we have Ansgtroem or bohrradius
926 * \return pointer to constructed molecule
927 */
928molecule * molecule::StoreFragmentFromKeySet(KeySet &Leaflet, bool IsAngstroem)
929{
930 atom **SonList = new atom*[AtomCount];
931 molecule *Leaf = World::getInstance().createMolecule();
932
933 for(int i=0;i<AtomCount;i++)
934 SonList[i] = NULL;
935
936// Log() << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
937 StoreFragmentFromKeySet_Init(this, Leaf, Leaflet, SonList);
938 // create the bonds between all: Make it an induced subgraph and add hydrogen
939// Log() << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
940 CreateInducedSubgraphOfFragment(this, Leaf, SonList, IsAngstroem);
941
942 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
943 delete[](SonList);
944// Log() << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
945 return Leaf;
946};
947
948
949/** Clears the touched list
950 * \param *out output stream for debugging
951 * \param verbosity verbosity level
952 * \param *&TouchedList touched list
953 * \param SubOrder current suborder
954 * \param TouchedIndex currently touched
955 */
956void SPFragmentGenerator_ClearingTouched(int verbosity, int *&TouchedList, int SubOrder, int &TouchedIndex)
957{
958 Log() << Verbose(1+verbosity) << "Clearing touched list." << endl;
959 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
960 TouchedList[TouchedIndex] = -1;
961 TouchedIndex = 0;
962
963}
964
965/** Adds the current combination of the power set to the snake stack.
966 * \param *out output stream for debugging
967 * \param verbosity verbosity level
968 * \param CurrentCombination
969 * \param SetDimension maximum number of bits in power set
970 * \param *FragmentSet snake stack to remove from
971 * \param *&TouchedList touched list
972 * \param TouchedIndex currently touched
973 * \return number of set bits
974 */
975int AddPowersetToSnakeStack(int verbosity, int CurrentCombination, int SetDimension, KeySet *FragmentSet, bond **BondsSet, int *&TouchedList, int &TouchedIndex)
976{
977 atom *OtherWalker = NULL;
978 bool bit = false;
979 KeySetTestPair TestKeySetInsert;
980
981 int Added = 0;
982 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
983 bit = ((CurrentCombination & (1 << j)) != 0); // mask the bit for the j-th bond
984 if (bit) { // if bit is set, we add this bond partner
985 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
986 //Log() << Verbose(1+verbosity) << "Current Bond is " << BondsSet[j] << ", checking on " << *OtherWalker << "." << endl;
987 Log() << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
988 TestKeySetInsert = FragmentSet->insert(OtherWalker->nr);
989 if (TestKeySetInsert.second) {
990 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
991 Added++;
992 } else {
993 Log() << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
994 }
995 } else {
996 Log() << Verbose(2+verbosity) << "Not adding." << endl;
997 }
998 }
999 return Added;
1000};
1001
1002/** Counts the number of elements in a power set.
1003 * \param *SetFirst
1004 * \param *SetLast
1005 * \param *&TouchedList touched list
1006 * \param TouchedIndex currently touched
1007 * \return number of elements
1008 */
1009int CountSetMembers(bond *SetFirst, bond *SetLast, int *&TouchedList, int TouchedIndex)
1010{
1011 int SetDimension = 0;
1012 bond *Binder = SetFirst; // start node for this level
1013 while (Binder->next != SetLast) { // compare to end node of this level
1014 Binder = Binder->next;
1015 for (int k=TouchedIndex;k--;) {
1016 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
1017 SetDimension++;
1018 }
1019 }
1020 return SetDimension;
1021};
1022
1023/** Counts the number of elements in a power set.
1024 * \param *BondsList bonds list to fill
1025 * \param *SetFirst
1026 * \param *SetLast
1027 * \param *&TouchedList touched list
1028 * \param TouchedIndex currently touched
1029 * \return number of elements
1030 */
1031int FillBondsList(bond **BondsList, bond *SetFirst, bond *SetLast, int *&TouchedList, int TouchedIndex)
1032{
1033 int SetDimension = 0;
1034 bond *Binder = SetFirst; // start node for this level
1035 while (Binder->next != SetLast) { // compare to end node of this level
1036 Binder = Binder->next;
1037 for (int k=0;k<TouchedIndex;k++) {
1038 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
1039 BondsList[SetDimension++] = Binder;
1040 }
1041 }
1042 return SetDimension;
1043};
1044
1045/** Remove all items that were added on this SP level.
1046 * \param *out output stream for debugging
1047 * \param verbosity verbosity level
1048 * \param *FragmentSet snake stack to remove from
1049 * \param *&TouchedList touched list
1050 * \param TouchedIndex currently touched
1051 */
1052void RemoveAllTouchedFromSnakeStack(int verbosity, KeySet *FragmentSet, int *&TouchedList, int &TouchedIndex)
1053{
1054 int Removal = 0;
1055 for(int j=0;j<TouchedIndex;j++) {
1056 Removal = TouchedList[j];
1057 Log() << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
1058 FragmentSet->erase(Removal);
1059 TouchedList[j] = -1;
1060 }
1061 DoLog(2) && (Log() << Verbose(2) << "Remaining local nr.s on snake stack are: ");
1062 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
1063 DoLog(0) && (Log() << Verbose(0) << (*runner) << " ");
1064 DoLog(0) && (Log() << Verbose(0) << endl);
1065 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
1066};
1067
1068/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
1069 * -# loops over every possible combination (2^dimension of edge set)
1070 * -# inserts current set, if there's still space left
1071 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
1072ance+1
1073 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
1074 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
1075distance) and current set
1076 * \param *out output stream for debugging
1077 * \param FragmentSearch UniqueFragments structure with all values needed
1078 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
1079 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
1080 * \param SubOrder remaining number of allowed vertices to add
1081 */
1082void molecule::SPFragmentGenerator(struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
1083{
1084 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
1085 int NumCombinations;
1086 int bits, TouchedIndex, SubSetDimension, SP, Added;
1087 int SpaceLeft;
1088 int *TouchedList = new int[SubOrder + 1];
1089 bond **BondsList = NULL;
1090 KeySetTestPair TestKeySetInsert;
1091
1092 NumCombinations = 1 << SetDimension;
1093
1094 // here for all bonds of Walker all combinations of end pieces (from the bonds)
1095 // have to be added and for the remaining ANOVA order GraphCrawler be called
1096 // recursively for the next level
1097
1098 Log() << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
1099 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;
1100
1101 // initialised touched list (stores added atoms on this level)
1102 SPFragmentGenerator_ClearingTouched(verbosity, TouchedList, SubOrder, TouchedIndex);
1103
1104 // create every possible combination of the endpieces
1105 Log() << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
1106 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
1107 // count the set bit of i
1108 bits = 0;
1109 for (int j=SetDimension;j--;)
1110 bits += (i & (1 << j)) >> j;
1111
1112 Log() << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
1113 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
1114 // --1-- add this set of the power set of bond partners to the snake stack
1115 Added = AddPowersetToSnakeStack(verbosity, i, SetDimension, FragmentSearch->FragmentSet, BondsSet, TouchedList, TouchedIndex);
1116
1117 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
1118 if (SpaceLeft > 0) {
1119 Log() << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
1120 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
1121 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
1122 SP = RootDistance+1; // this is the next level
1123
1124 // first count the members in the subset
1125 SubSetDimension = CountSetMembers(FragmentSearch->BondsPerSPList[2*SP], FragmentSearch->BondsPerSPList[2*SP+1], TouchedList, TouchedIndex);
1126
1127 // then allocate and fill the list
1128 bond *BondsList[SubSetDimension];
1129 SubSetDimension = FillBondsList(BondsList, FragmentSearch->BondsPerSPList[2*SP], FragmentSearch->BondsPerSPList[2*SP+1], TouchedList, TouchedIndex);
1130
1131 // then iterate
1132 Log() << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
1133 SPFragmentGenerator(FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
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 delete[](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 = new bond* [Order * 2];
1168 FragmentSearch.BondsPerSPCount = new int[Order];
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 delete[](FragmentSearch.BondsPerSPCount);
1187 for (int i=Order;i--;) {
1188 delete(FragmentSearch.BondsPerSPList[2*i]);
1189 delete(FragmentSearch.BondsPerSPList[2*i+1]);
1190 }
1191 delete[](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 bond* BondsList[FragmentSearch.BondsPerSPCount[0]];
1397 for(int i=0;i<FragmentSearch.BondsPerSPCount[0];i++)
1398 BondsList[i] = NULL;
1399 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond
1400
1401 SPFragmentGenerator(&FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
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 delete[](FragmentLowerOrdersList[RootNr]);
1510 RootNr++;
1511 }
1512 delete[](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 = new int[UpgradeCount];
1552 FragmentLowerOrdersList = new Graph**[UpgradeCount];
1553
1554 for(int i=0;i<UpgradeCount;i++) {
1555 NumMoleculesOfOrder[i] = 0;
1556 FragmentLowerOrdersList[i] = NULL;
1557 }
1558
1559 // initialise the fragments structure
1560 FragmentSearch.FragmentCounter = 0;
1561 FragmentSearch.FragmentSet = new KeySet;
1562 FragmentSearch.Root = FindAtom(RootKeyNr);
1563 FragmentSearch.ShortestPathList = new int[AtomCount];
1564 for (int i=AtomCount;i--;) {
1565 FragmentSearch.ShortestPathList[i] = -1;
1566 }
1567
1568 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
1569 atom *Walker = start;
1570 KeySet CompleteMolecule;
1571 while (Walker->next != end) {
1572 Walker = Walker->next;
1573 CompleteMolecule.insert(Walker->GetTrueFather()->nr);
1574 }
1575
1576 // 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
1577 // 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),
1578 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
1579 // 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)
1580 RootNr = 0; // counts through the roots in RootStack
1581 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
1582 RootKeyNr = RootStack.front();
1583 RootStack.pop_front();
1584 Walker = FindAtom(RootKeyNr);
1585 // check cyclic lengths
1586 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) {
1587 // 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;
1588 //} else
1589 {
1590 // increase adaptive order by one
1591 Walker->GetTrueFather()->AdaptiveOrder++;
1592 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
1593
1594 // initialise Order-dependent entries of UniqueFragments structure
1595 InitialiseSPList(Order, FragmentSearch);
1596
1597 // allocate memory for all lower level orders in this 1D-array of ptrs
1598 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
1599 FragmentLowerOrdersList[RootNr] = new Graph*[NumLevels];
1600 for (int i=0;i<NumLevels;i++)
1601 FragmentLowerOrdersList[RootNr][i] = NULL;
1602
1603 // create top order where nothing is reduced
1604 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1605 DoLog(0) && (Log() << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl); // , NumLevels is " << NumLevels << "
1606
1607 // Create list of Graphs of current Bond Order (i.e. F_{ij})
1608 FragmentLowerOrdersList[RootNr][0] = new Graph;
1609 FragmentSearch.TEFactor = 1.;
1610 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
1611 FragmentSearch.Root = Walker;
1612 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
1613
1614 // output resulting number
1615 DoLog(1) && (Log() << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl);
1616 if (NumMoleculesOfOrder[RootNr] != 0) {
1617 NumMolecules = 0;
1618 } else {
1619 Walker->GetTrueFather()->MaxOrder = true;
1620 }
1621 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
1622 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
1623 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
1624// Log() << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
1625 RootStack.push_back(RootKeyNr); // put back on stack
1626 RootNr++;
1627
1628 // free Order-dependent entries of UniqueFragments structure for next loop cycle
1629 FreeSPList(Order, FragmentSearch);
1630 }
1631 }
1632 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1633 DoLog(1) && (Log() << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl);
1634 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
1635
1636 // cleanup FragmentSearch structure
1637 delete[](FragmentSearch.ShortestPathList);
1638 delete(FragmentSearch.FragmentSet);
1639
1640 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
1641 // 5433222211111111
1642 // 43221111
1643 // 3211
1644 // 21
1645 // 1
1646
1647 // Subsequently, we combine all into a single list (FragmentList)
1648 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, this);
1649 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, this);
1650 delete[](NumMoleculesOfOrder);
1651
1652 DoLog(0) && (Log() << Verbose(0) << "End of FragmentBOSSANOVA." << endl);
1653};
1654
1655/** Corrects the nuclei position if the fragment was created over the cell borders.
1656 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
1657 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
1658 * and re-add the bond. Looping on the distance check.
1659 * \param *out ofstream for debugging messages
1660 */
1661void molecule::ScanForPeriodicCorrection()
1662{
1663 bond *Binder = NULL;
1664 bond *OtherBinder = NULL;
1665 atom *Walker = NULL;
1666 atom *OtherWalker = NULL;
1667 double * const cell_size = World::getInstance().getDomain();
1668 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
1669 enum Shading *ColorList = NULL;
1670 double tmp;
1671 Vector Translationvector;
1672 //class StackClass<atom *> *CompStack = NULL;
1673 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
1674 bool flag = true;
1675
1676 DoLog(2) && (Log() << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl);
1677
1678 ColorList = new enum Shading[AtomCount];
1679 for (int i=0;i<AtomCount;i++)
1680 ColorList[i] = (enum Shading)0;
1681 while (flag) {
1682 // remove bonds that are beyond bonddistance
1683 for(int i=NDIM;i--;)
1684 Translationvector[i] = 0.;
1685 // scan all bonds
1686 Binder = first;
1687 flag = false;
1688 while ((!flag) && (Binder->next != last)) {
1689 Binder = Binder->next;
1690 for (int i=NDIM;i--;) {
1691 tmp = fabs(Binder->leftatom->x[i] - Binder->rightatom->x[i]);
1692 //Log() << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
1693 if (tmp > BondDistance) {
1694 OtherBinder = Binder->next; // note down binding partner for later re-insertion
1695 unlink(Binder); // unlink bond
1696 DoLog(2) && (Log() << Verbose(2) << "Correcting at bond " << *Binder << "." << endl);
1697 flag = true;
1698 break;
1699 }
1700 }
1701 }
1702 if (flag) {
1703 // create translation vector from their periodically modified distance
1704 for (int i=NDIM;i--;) {
1705 tmp = Binder->leftatom->x[i] - Binder->rightatom->x[i];
1706 if (fabs(tmp) > BondDistance)
1707 Translationvector[i] = (tmp < 0) ? +1. : -1.;
1708 }
1709 Translationvector.MatrixMultiplication(matrix);
1710 //Log() << Verbose(3) << "Translation vector is ";
1711 Log() << Verbose(0) << Translationvector << endl;
1712 // apply to all atoms of first component via BFS
1713 for (int i=AtomCount;i--;)
1714 ColorList[i] = white;
1715 AtomStack->Push(Binder->leftatom);
1716 while (!AtomStack->IsEmpty()) {
1717 Walker = AtomStack->PopFirst();
1718 //Log() << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
1719 ColorList[Walker->nr] = black; // mark as explored
1720 Walker->x += Translationvector; // translate
1721 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1722 if ((*Runner) != Binder) {
1723 OtherWalker = (*Runner)->GetOtherAtom(Walker);
1724 if (ColorList[OtherWalker->nr] == white) {
1725 AtomStack->Push(OtherWalker); // push if yet unexplored
1726 }
1727 }
1728 }
1729 }
1730 // re-add bond
1731 link(Binder, OtherBinder);
1732 } else {
1733 DoLog(3) && (Log() << Verbose(3) << "No corrections for this fragment." << endl);
1734 }
1735 //delete(CompStack);
1736 }
1737
1738 // free allocated space from ReturnFullMatrixforSymmetric()
1739 delete(AtomStack);
1740 delete[](ColorList);
1741 delete[](matrix);
1742 DoLog(2) && (Log() << Verbose(2) << "End of ScanForPeriodicCorrection." << endl);
1743};
Note: See TracBrowser for help on using the repository browser.