source: src/molecule_fragmentation.cpp@ 5034e1

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 5034e1 was 5034e1, checked in by Frederik Heber <heber@…>, 16 years ago

First half of molecule_fragmentation.cpp refactoring.

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