source: src/molecule_fragmentation.cpp@ ccd9f5

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

forward declarations used to untangle interdependet classes.

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