source: src/molecule_fragmentation.cpp@ 05a97c

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 05a97c was ea7176, checked in by Tillmann Crueger <crueger@…>, 15 years ago

FIX: Made AtomCount a Cacheable so that the number of atoms in a molecule will always be correct

All unittests working.
All Complete testcases fail.

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