source: src/molecule_fragmentation.cpp@ 3839e5

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 3839e5 was 4e10f5, checked in by Tillmann Crueger <crueger@…>, 14 years ago

Merge branch 'stable' into StructureRefactoring

Conflicts:

src/Actions/WorldAction/CenterOnEdgeAction.cpp
src/Actions/WorldAction/ChangeBoxAction.cpp
src/Actions/WorldAction/RepeatBoxAction.cpp
src/Actions/WorldAction/ScaleBoxAction.cpp
src/World.cpp
src/boundary.cpp

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