source: src/molecule_fragmentation.cpp@ 5f8660a

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

Added copyright note to each .cpp file and an extensive one to builder.cpp.

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