source: src/molecule_fragmentation.cpp@ 23b830

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

class molecule implementation split up into six separate parts.

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