source: src/molecule_fragmentation.cpp@ 3bdb6d

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

Moved all stuff related to elements into own subfolder and has its own convenience library.

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