source: src/molecule_fragmentation.cpp@ a7b761b

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 Candidate_v1.7.0 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 a7b761b was a7b761b, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Merge branch 'MoleculeStartEndSwitch' into StructureRefactoring

Conflicts:

molecuilder/src/Helpers/Assert.cpp
molecuilder/src/Helpers/Assert.hpp
molecuilder/src/Legacy/oldmenu.cpp
molecuilder/src/Makefile.am
molecuilder/src/Patterns/Cacheable.hpp
molecuilder/src/Patterns/Observer.cpp
molecuilder/src/Patterns/Observer.hpp
molecuilder/src/analysis_correlation.cpp
molecuilder/src/boundary.cpp
molecuilder/src/builder.cpp
molecuilder/src/config.cpp
molecuilder/src/helpers.hpp
molecuilder/src/molecule.cpp
molecuilder/src/molecule.hpp
molecuilder/src/molecule_dynamics.cpp
molecuilder/src/molecule_fragmentation.cpp
molecuilder/src/molecule_geometry.cpp
molecuilder/src/molecule_graph.cpp
molecuilder/src/moleculelist.cpp
molecuilder/src/tesselation.cpp
molecuilder/src/unittests/AnalysisCorrelationToSurfaceUnitTest.cpp
molecuilder/src/unittests/ObserverTest.cpp
molecuilder/src/unittests/ObserverTest.hpp

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