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