source: src/molecule_fragmentation.cpp@ 111387

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

Moved bond.* to Bond/, new class GraphEdge which contains graph parts of bond.

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