source: src/molecule_fragmentation.cpp@ bf3817

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

Added ifdef HAVE_CONFIG and config.h include to each and every cpp file.

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