source: src/molecule_fragmentation.cpp@ 708798

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

Rewrite of CheckAgainstAdjacencyFile.

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