source: src/molecule_fragmentation.cpp@ 586055

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

Renamed Matrix to RealSpaceMatrix.

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