source: src/molecule_fragmentation.cpp@ 49c059

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

Moved DepthFirstSearchAnalysis into functor in Graph/.

Smaller fixes:

TESTFIXES:

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