source: src/Fragmentation/fragmentation_helpers.cpp@ d9a032

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since d9a032 was ba1823, checked in by Frederik Heber <heber@…>, 13 years ago

Moved all helpers fragmentation functions into folder src/Fragmentation.

  • Property mode set to 100644
File size: 34.0 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * fragmentation_helpers.cpp
10 *
11 * Created on: Oct 18, 2011
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include "fragmentation_helpers.hpp"
23
24#include <sstream>
25
26#include "CodePatterns/Log.hpp"
27
28#include "atom.hpp"
29#include "Bond/bond.hpp"
30#include "Element/element.hpp"
31#include "Helpers/defs.hpp"
32#include "Helpers/helpers.hpp"
33#include "molecule.hpp"
34
35using namespace std;
36
37/** Scans a single line for number and puts them into \a KeySet.
38 * \param *out output stream for debugging
39 * \param *buffer buffer to scan
40 * \param &CurrentSet filled KeySet on return
41 * \return true - at least one valid atom id parsed, false - CurrentSet is empty
42 */
43bool ScanBufferIntoKeySet(char *buffer, KeySet &CurrentSet)
44{
45 stringstream line;
46 int AtomNr;
47 int status = 0;
48
49 line.str(buffer);
50 while (!line.eof()) {
51 line >> AtomNr;
52 if (AtomNr >= 0) {
53 CurrentSet.insert(AtomNr); // insert at end, hence in same order as in file!
54 status++;
55 } // else it's "-1" or else and thus must not be added
56 }
57 DoLog(1) && (Log() << Verbose(1) << "The scanned KeySet is ");
58 for(KeySet::iterator runner = CurrentSet.begin(); runner != CurrentSet.end(); runner++) {
59 DoLog(0) && (Log() << Verbose(0) << (*runner) << "\t");
60 }
61 DoLog(0) && (Log() << Verbose(0) << endl);
62 return (status != 0);
63};
64
65/** Parses the KeySet file and fills \a *FragmentList from the known molecule structure.
66 * Does two-pass scanning:
67 * -# Scans the keyset file and initialises a temporary graph
68 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
69 * Finally, the temporary graph is inserted into the given \a FragmentList for return.
70 * \param &path path to file
71 * \param *FragmentList empty, filled on return
72 * \return true - parsing successfully, false - failure on parsing (FragmentList will be NULL)
73 */
74bool ParseKeySetFile(std::string &path, Graph *&FragmentList)
75{
76 bool status = true;
77 ifstream InputFile;
78 stringstream line;
79 GraphTestPair testGraphInsert;
80 int NumberOfFragments = 0;
81 string filename;
82
83 if (FragmentList == NULL) { // check list pointer
84 FragmentList = new Graph;
85 }
86
87 // 1st pass: open file and read
88 DoLog(1) && (Log() << Verbose(1) << "Parsing the KeySet file ... " << endl);
89 filename = path + KEYSETFILE;
90 InputFile.open(filename.c_str());
91 if (InputFile.good()) {
92 // each line represents a new fragment
93 char buffer[MAXSTRINGSIZE];
94 // 1. parse keysets and insert into temp. graph
95 while (!InputFile.eof()) {
96 InputFile.getline(buffer, MAXSTRINGSIZE);
97 KeySet CurrentSet;
98 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(buffer, CurrentSet))) { // if at least one valid atom was added, write config
99 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1))); // store fragment number and current factor
100 if (!testGraphInsert.second) {
101 DoeLog(0) && (eLog()<< Verbose(0) << "KeySet file must be corrupt as there are two equal key sets therein!" << endl);
102 performCriticalExit();
103 }
104 }
105 }
106 // 2. Free and done
107 InputFile.close();
108 InputFile.clear();
109 DoLog(1) && (Log() << Verbose(1) << "\t ... done." << endl);
110 } else {
111 DoLog(1) && (Log() << Verbose(1) << "\t ... File " << filename << " not found." << endl);
112 status = false;
113 }
114
115 return status;
116};
117
118/** Parses the TE factors file and fills \a *FragmentList from the known molecule structure.
119 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
120 * \param *out output stream for debugging
121 * \param *path path to file
122 * \param *FragmentList graph whose nodes's TE factors are set on return
123 * \return true - parsing successfully, false - failure on parsing
124 */
125bool ParseTEFactorsFile(char *path, Graph *FragmentList)
126{
127 bool status = true;
128 ifstream InputFile;
129 stringstream line;
130 GraphTestPair testGraphInsert;
131 int NumberOfFragments = 0;
132 double TEFactor;
133 char filename[MAXSTRINGSIZE];
134
135 if (FragmentList == NULL) { // check list pointer
136 FragmentList = new Graph;
137 }
138
139 // 2nd pass: open TEFactors file and read
140 DoLog(1) && (Log() << Verbose(1) << "Parsing the TEFactors file ... " << endl);
141 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, TEFACTORSFILE);
142 InputFile.open(filename);
143 if (InputFile != NULL) {
144 // 3. add found TEFactors to each keyset
145 NumberOfFragments = 0;
146 for(Graph::iterator runner = FragmentList->begin();runner != FragmentList->end(); runner++) {
147 if (!InputFile.eof()) {
148 InputFile >> TEFactor;
149 (*runner).second.second = TEFactor;
150 DoLog(2) && (Log() << Verbose(2) << "Setting " << ++NumberOfFragments << " fragment's TEFactor to " << (*runner).second.second << "." << endl);
151 } else {
152 status = false;
153 break;
154 }
155 }
156 // 4. Free and done
157 InputFile.close();
158 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
159 } else {
160 DoLog(1) && (Log() << Verbose(1) << "File " << filename << " not found." << endl);
161 status = false;
162 }
163
164 return status;
165};
166
167/** Stores key sets to file.
168 * \param KeySetList Graph with Keysets
169 * \param &path path to file
170 * \return true - file written successfully, false - writing failed
171 */
172bool StoreKeySetFile(Graph &KeySetList, std::string &path)
173{
174 bool status = true;
175 string line = path + KEYSETFILE;
176 ofstream output(line.c_str());
177
178 // open KeySet file
179 DoLog(1) && (Log() << Verbose(1) << "Saving key sets of the total graph ... ");
180 if(output.good()) {
181 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) {
182 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
183 if (sprinter != (*runner).first.begin())
184 output << "\t";
185 output << *sprinter;
186 }
187 output << endl;
188 }
189 DoLog(0) && (Log() << Verbose(0) << "done." << endl);
190 } else {
191 DoeLog(0) && (eLog()<< Verbose(0) << "Unable to open " << line << " for writing keysets!" << endl);
192 performCriticalExit();
193 status = false;
194 }
195 output.close();
196 output.clear();
197
198 return status;
199};
200
201
202/** Stores TEFactors to file.
203 * \param *out output stream for debugging
204 * \param KeySetList Graph with factors
205 * \param *path path to file
206 * \return true - file written successfully, false - writing failed
207 */
208bool StoreTEFactorsFile(Graph &KeySetList, char *path)
209{
210 ofstream output;
211 bool status = true;
212 string line;
213
214 // open TEFactors file
215 line = path;
216 line.append("/");
217 line += FRAGMENTPREFIX;
218 line += TEFACTORSFILE;
219 output.open(line.c_str(), ios::out);
220 DoLog(1) && (Log() << Verbose(1) << "Saving TEFactors of the total graph ... ");
221 if(output != NULL) {
222 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++)
223 output << (*runner).second.second << endl;
224 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
225 } else {
226 DoLog(1) && (Log() << Verbose(1) << "failed to open " << line << "." << endl);
227 status = false;
228 }
229 output.close();
230
231 return status;
232};
233
234/** For a given graph, sorts KeySets into a (index, keyset) map.
235 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
236 * \return map from index to keyset
237 */
238std::map<int,KeySet> * GraphToIndexedKeySet(Graph *GlobalKeySetList)
239{
240 map<int,KeySet> *IndexKeySetList = new map<int,KeySet>;
241 for(Graph::iterator runner = GlobalKeySetList->begin(); runner != GlobalKeySetList->end(); runner++) {
242 IndexKeySetList->insert( pair<int,KeySet>(runner->second.first,runner->first) );
243 }
244 return IndexKeySetList;
245};
246
247/** Inserts a (\a No, \a value) pair into the list, overwriting present one.
248 * Note if values are equal, No will decided on which is first
249 * \param *out output stream for debugging
250 * \param &AdaptiveCriteriaList list to insert into
251 * \param &IndexedKeySetList list to find key set for a given index \a No
252 * \param FragOrder current bond order of fragment
253 * \param No index of keyset
254 * \param value energy value
255 */
256void InsertIntoAdaptiveCriteriaList(std::map<int, pair<double,int> > *AdaptiveCriteriaList, std::map<int,KeySet> &IndexKeySetList, int FragOrder, int No, double Value)
257{
258 map<int,KeySet>::iterator marker = IndexKeySetList.find(No); // find keyset to Frag No.
259 if (marker != IndexKeySetList.end()) { // if found
260 Value *= 1 + MYEPSILON*(*((*marker).second.begin())); // in case of equal energies this makes them not equal without changing anything actually
261 // 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
262 pair <map<int, pair<double,int> >::iterator, bool> InsertedElement = AdaptiveCriteriaList->insert( make_pair(*((*marker).second.begin()), pair<double,int>( fabs(Value), FragOrder) ));
263 map<int, pair<double,int> >::iterator PresentItem = InsertedElement.first;
264 if (!InsertedElement.second) { // this root is already present
265 if ((*PresentItem).second.second < FragOrder) // if order there is lower, update entry with higher-order term
266 //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)
267 { // if value is smaller, update value and order
268 (*PresentItem).second.first = fabs(Value);
269 (*PresentItem).second.second = FragOrder;
270 DoLog(2) && (Log() << Verbose(2) << "Updated element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl);
271 } else {
272 DoLog(2) && (Log() << Verbose(2) << "Did not update element " << (*PresentItem).first << " as " << FragOrder << " is less than or equal to " << (*PresentItem).second.second << "." << endl);
273 }
274 } else {
275 DoLog(2) && (Log() << Verbose(2) << "Inserted element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl);
276 }
277 } else {
278 DoLog(1) && (Log() << Verbose(1) << "No Fragment under No. " << No << "found." << endl);
279 }
280};
281
282/** Counts lines in file.
283 * Note we are scanning lines from current position, not from beginning.
284 * \param InputFile file to be scanned.
285 */
286int CountLinesinFile(std::ifstream &InputFile)
287{
288 char *buffer = new char[MAXSTRINGSIZE];
289 int lines=0;
290
291 int PositionMarker = InputFile.tellg(); // not needed as Inputfile is copied, given by value, not by ref
292 // count the number of lines, i.e. the number of fragments
293 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
294 InputFile.getline(buffer, MAXSTRINGSIZE);
295 while(!InputFile.eof()) {
296 InputFile.getline(buffer, MAXSTRINGSIZE);
297 lines++;
298 }
299 InputFile.seekg(PositionMarker, ios::beg);
300 delete[](buffer);
301 return lines;
302};
303
304
305/** Scans the adaptive order file and insert (index, value) into map.
306 * \param &path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
307 * \param &IndexedKeySetList list to find key set for a given index \a No
308 * \return adaptive criteria list from file
309 */
310std::map<int, std::pair<double,int> > * ScanAdaptiveFileIntoMap(std::string &path, std::map<int,KeySet> &IndexKeySetList)
311{
312 map<int, pair<double,int> > *AdaptiveCriteriaList = new map<int, pair<double,int> >;
313 int No = 0, FragOrder = 0;
314 double Value = 0.;
315 char buffer[MAXSTRINGSIZE];
316 string filename = path + ENERGYPERFRAGMENT;
317 ifstream InputFile(filename.c_str());
318
319 if (InputFile.fail()) {
320 DoeLog(1) && (eLog() << Verbose(1) << "Cannot find file " << filename << "." << endl);
321 return AdaptiveCriteriaList;
322 }
323
324 if (CountLinesinFile(InputFile) > 0) {
325 // each line represents a fragment root (Atom::Nr) id and its energy contribution
326 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
327 InputFile.getline(buffer, MAXSTRINGSIZE);
328 while(!InputFile.eof()) {
329 InputFile.getline(buffer, MAXSTRINGSIZE);
330 if (strlen(buffer) > 2) {
331 //Log() << Verbose(2) << "Scanning: " << buffer << endl;
332 stringstream line(buffer);
333 line >> FragOrder;
334 line >> ws >> No;
335 line >> ws >> Value; // skip time entry
336 line >> ws >> Value;
337 No -= 1; // indices start at 1 in file, not 0
338 //Log() << Verbose(2) << " - yields (" << No << "," << Value << ", " << FragOrder << ")" << endl;
339
340 // clean the list of those entries that have been superceded by higher order terms already
341 InsertIntoAdaptiveCriteriaList(AdaptiveCriteriaList, IndexKeySetList, FragOrder, No, Value);
342 }
343 }
344 // close and done
345 InputFile.close();
346 InputFile.clear();
347 }
348
349 return AdaptiveCriteriaList;
350};
351
352/** Maps adaptive criteria list back onto (Value, (Root Nr., Order))
353 * (i.e. sorted by value to pick the highest ones)
354 * \param *out output stream for debugging
355 * \param &AdaptiveCriteriaList list to insert into
356 * \param *mol molecule with atoms
357 * \return remapped list
358 */
359std::map<double, std::pair<int,int> > * ReMapAdaptiveCriteriaListToValue(std::map<int, std::pair<double,int> > *AdaptiveCriteriaList, molecule *mol)
360{
361 atom *Walker = NULL;
362 map<double, pair<int,int> > *FinalRootCandidates = new map<double, pair<int,int> > ;
363 DoLog(1) && (Log() << Verbose(1) << "Root candidate list is: " << endl);
364 for(map<int, pair<double,int> >::iterator runner = AdaptiveCriteriaList->begin(); runner != AdaptiveCriteriaList->end(); runner++) {
365 Walker = mol->FindAtom((*runner).first);
366 if (Walker != NULL) {
367 //if ((*runner).second.second >= Walker->AdaptiveOrder) { // only insert if this is an "active" root site for the current order
368 if (!Walker->MaxOrder) {
369 DoLog(2) && (Log() << Verbose(2) << "(" << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "])" << endl);
370 FinalRootCandidates->insert( make_pair( (*runner).second.first, pair<int,int>((*runner).first, (*runner).second.second) ) );
371 } else {
372 DoLog(2) && (Log() << Verbose(2) << "Excluding (" << *Walker << ", " << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "]), as it has reached its maximum order." << endl);
373 }
374 } else {
375 DoeLog(0) && (eLog()<< Verbose(0) << "Atom No. " << (*runner).second.first << " was not found in this molecule." << endl);
376 performCriticalExit();
377 }
378 }
379 return FinalRootCandidates;
380};
381
382/** Marks all candidate sites for update if below adaptive threshold.
383 * Picks a given number of highest values and set *AtomMask to true.
384 * \param *out output stream for debugging
385 * \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
386 * \param FinalRootCandidates list candidates to check
387 * \param Order desired order
388 * \param *mol molecule with atoms
389 * \return true - if update is necessary, false - not
390 */
391bool MarkUpdateCandidates(bool *AtomMask, std::map<double, std::pair<int,int> > &FinalRootCandidates, int Order, molecule *mol)
392{
393 atom *Walker = NULL;
394 int No = -1;
395 bool status = false;
396 for(map<double, pair<int,int> >::iterator runner = FinalRootCandidates.upper_bound(pow(10.,Order)); runner != FinalRootCandidates.end(); runner++) {
397 No = (*runner).second.first;
398 Walker = mol->FindAtom(No);
399 //if (Walker->AdaptiveOrder < MinimumRingSize[Walker->getNr()]) {
400 DoLog(2) && (Log() << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", setting entry " << No << " of Atom mask to true." << endl);
401 AtomMask[No] = true;
402 status = true;
403 //} else
404 //Log() << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", however MinimumRingSize of " << MinimumRingSize[Walker->getNr()] << " does not allow further adaptive increase." << endl;
405 }
406 return status;
407};
408
409/** print atom mask for debugging.
410 * \param *out output stream for debugging
411 * \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
412 * \param AtomCount number of entries in \a *AtomMask
413 */
414void PrintAtomMask(bool *AtomMask, int AtomCount)
415{
416 DoLog(2) && (Log() << Verbose(2) << " ");
417 for(int i=0;i<AtomCount;i++)
418 DoLog(0) && (Log() << Verbose(0) << (i % 10));
419 DoLog(0) && (Log() << Verbose(0) << endl);
420 DoLog(2) && (Log() << Verbose(2) << "Atom mask is: ");
421 for(int i=0;i<AtomCount;i++)
422 DoLog(0) && (Log() << Verbose(0) << (AtomMask[i] ? "t" : "f"));
423 DoLog(0) && (Log() << Verbose(0) << endl);
424};
425
426
427
428/** Clears the touched list
429 * \param *out output stream for debugging
430 * \param verbosity verbosity level
431 * \param *&TouchedList touched list
432 * \param SubOrder current suborder
433 * \param TouchedIndex currently touched
434 */
435void SPFragmentGenerator_ClearingTouched(int verbosity, int *&TouchedList, int SubOrder, int &TouchedIndex)
436{
437 Log() << Verbose(1+verbosity) << "Clearing touched list." << endl;
438 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
439 TouchedList[TouchedIndex] = -1;
440 TouchedIndex = 0;
441
442}
443
444/** Adds the current combination of the power set to the snake stack.
445 * \param *out output stream for debugging
446 * \param verbosity verbosity level
447 * \param CurrentCombination
448 * \param SetDimension maximum number of bits in power set
449 * \param *FragmentSet snake stack to remove from
450 * \param &BondsSet set of bonds
451 * \param *&TouchedList touched list
452 * \param TouchedIndex currently touched
453 * \return number of set bits
454 */
455int AddPowersetToSnakeStack(int verbosity, int CurrentCombination, int SetDimension, KeySet *FragmentSet, std::vector<bond *> &BondsSet, int *&TouchedList, int &TouchedIndex)
456{
457 atom *OtherWalker = NULL;
458 bool bit = false;
459 KeySetTestPair TestKeySetInsert;
460
461 int Added = 0;
462 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
463 bit = ((CurrentCombination & (1 << j)) != 0); // mask the bit for the j-th bond
464 if (bit) { // if bit is set, we add this bond partner
465 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
466 //Log() << Verbose(1+verbosity) << "Current Bond is " << BondsSet[j] << ", checking on " << *OtherWalker << "." << endl;
467 Log() << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->getNr() << "." << endl;
468 TestKeySetInsert = FragmentSet->insert(OtherWalker->getNr());
469 if (TestKeySetInsert.second) {
470 TouchedList[TouchedIndex++] = OtherWalker->getNr(); // note as added
471 Added++;
472 } else {
473 Log() << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
474 }
475 } else {
476 Log() << Verbose(2+verbosity) << "Not adding." << endl;
477 }
478 }
479 return Added;
480};
481
482/** Counts the number of elements in a power set.
483 * \param SetFirst begin iterator first bond
484 * \param SetLast end iterator
485 * \param *&TouchedList touched list
486 * \param TouchedIndex currently touched
487 * \return number of elements
488 */
489int CountSetMembers(std::list<bond *>::const_iterator SetFirst, std::list<bond *>::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
490{
491 int SetDimension = 0;
492 for( std::list<bond *>::const_iterator Binder = SetFirst;
493 Binder != SetLast;
494 ++Binder) {
495 for (int k=TouchedIndex;k--;) {
496 if ((*Binder)->Contains(TouchedList[k])) // if we added this very endpiece
497 SetDimension++;
498 }
499 }
500 return SetDimension;
501};
502
503/** Fills a list of bonds from another
504 * \param *BondsList bonds array/vector to fill
505 * \param SetFirst begin iterator first bond
506 * \param SetLast end iterator
507 * \param *&TouchedList touched list
508 * \param TouchedIndex currently touched
509 * \return number of elements
510 */
511int FillBondsList(std::vector<bond *> &BondsList, std::list<bond *>::const_iterator SetFirst, std::list<bond *>::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
512{
513 int SetDimension = 0;
514 for( std::list<bond *>::const_iterator Binder = SetFirst;
515 Binder != SetLast;
516 ++Binder) {
517 for (int k=0;k<TouchedIndex;k++) {
518 if ((*Binder)->leftatom->getNr() == TouchedList[k]) // leftatom is always the closer one
519 BondsList[SetDimension++] = (*Binder);
520 }
521 }
522 return SetDimension;
523};
524
525/** Remove all items that were added on this SP level.
526 * \param *out output stream for debugging
527 * \param verbosity verbosity level
528 * \param *FragmentSet snake stack to remove from
529 * \param *&TouchedList touched list
530 * \param TouchedIndex currently touched
531 */
532void RemoveAllTouchedFromSnakeStack(int verbosity, KeySet *FragmentSet, int *&TouchedList, int &TouchedIndex)
533{
534 int Removal = 0;
535 for(int j=0;j<TouchedIndex;j++) {
536 Removal = TouchedList[j];
537 Log() << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
538 FragmentSet->erase(Removal);
539 TouchedList[j] = -1;
540 }
541 DoLog(2) && (Log() << Verbose(2) << "Remaining local nr.s on snake stack are: ");
542 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
543 DoLog(0) && (Log() << Verbose(0) << (*runner) << " ");
544 DoLog(0) && (Log() << Verbose(0) << endl);
545 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
546};
547
548/** Allocates memory for UniqueFragments::BondsPerSPList.
549 * \param *out output stream
550 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
551 * \param FragmentSearch UniqueFragments
552 * \sa FreeSPList()
553 */
554void InitialiseSPList(int Order, struct UniqueFragments &FragmentSearch)
555{
556 FragmentSearch.BondsPerSPList.resize(Order);
557 FragmentSearch.BondsPerSPCount = new int[Order];
558 for (int i=Order;i--;) {
559 FragmentSearch.BondsPerSPCount[i] = 0;
560 }
561};
562
563/** Free's memory for for UniqueFragments::BondsPerSPList.
564 * \param *out output stream
565 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
566 * \param FragmentSearch UniqueFragments\
567 * \sa InitialiseSPList()
568 */
569void FreeSPList(int Order, struct UniqueFragments &FragmentSearch)
570{
571 delete[](FragmentSearch.BondsPerSPCount);
572};
573
574/** Sets FragmenSearch to initial value.
575 * Sets UniqueFragments::ShortestPathList entries to zero, UniqueFragments::BondsPerSPCount to zero (except zero level to 1) and
576 * adds initial bond UniqueFragments::Root to UniqueFragments::Root to UniqueFragments::BondsPerSPList
577 * \param *out output stream
578 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
579 * \param FragmentSearch UniqueFragments
580 * \sa FreeSPList()
581 */
582void SetSPList(int Order, struct UniqueFragments &FragmentSearch)
583{
584 // prepare Label and SP arrays of the BFS search
585 FragmentSearch.ShortestPathList[FragmentSearch.Root->getNr()] = 0;
586
587 // prepare root level (SP = 0) and a loop bond denoting Root
588 for (int i=Order;i--;)
589 FragmentSearch.BondsPerSPCount[i] = 0;
590 FragmentSearch.BondsPerSPCount[0] = 1;
591 bond *Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
592 FragmentSearch.BondsPerSPList[0].push_back(Binder);
593};
594
595/** Resets UniqueFragments::ShortestPathList and cleans bonds from UniqueFragments::BondsPerSPList.
596 * \param *out output stream
597 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
598 * \param FragmentSearch UniqueFragments
599 * \sa InitialiseSPList()
600 */
601void ResetSPList(int Order, struct UniqueFragments &FragmentSearch)
602{
603 DoLog(0) && (Log() << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl);
604 for(int i=Order;i--;) {
605 DoLog(1) && (Log() << Verbose(1) << "Current SP level is " << i << ": ");
606 for (UniqueFragments::BondsPerSP::const_iterator iter = FragmentSearch.BondsPerSPList[i].begin();
607 iter != FragmentSearch.BondsPerSPList[i].end();
608 ++iter) {
609 // Log() << Verbose(0) << "Removing atom " << Binder->leftatom->getNr() << " and " << Binder->rightatom->getNr() << "." << endl; // make sure numbers are local
610 FragmentSearch.ShortestPathList[(*iter)->leftatom->getNr()] = -1;
611 FragmentSearch.ShortestPathList[(*iter)->rightatom->getNr()] = -1;
612 }
613 // delete added bonds
614 for (UniqueFragments::BondsPerSP::iterator iter = FragmentSearch.BondsPerSPList[i].begin();
615 iter != FragmentSearch.BondsPerSPList[i].end();
616 ++iter) {
617 delete(*iter);
618 }
619 FragmentSearch.BondsPerSPList[i].clear();
620 // also start and end node
621 DoLog(0) && (Log() << Verbose(0) << "cleaned." << endl);
622 }
623};
624
625
626/** Fills the Bonds per Shortest Path List and set the vertex labels.
627 * \param *out output stream
628 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
629 * \param FragmentSearch UniqueFragments
630 * \param *mol molecule with atoms and bonds
631 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
632 */
633void FillSPListandLabelVertices(int Order, struct UniqueFragments &FragmentSearch, molecule *mol, KeySet RestrictedKeySet)
634{
635 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into
636 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning
637 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth
638 // (EdgeinSPLevel) of this tree ...
639 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence
640 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction.
641 int AtomKeyNr = -1;
642 atom *Walker = NULL;
643 atom *OtherWalker = NULL;
644 atom *Predecessor = NULL;
645 bond *Binder = NULL;
646 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->getNr();
647 int RemainingWalkers = -1;
648 int SP = -1;
649
650 DoLog(0) && (Log() << Verbose(0) << "Starting BFS analysis ..." << endl);
651 for (SP = 0; SP < (Order-1); SP++) {
652 DoLog(1) && (Log() << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)");
653 if (SP > 0) {
654 DoLog(0) && (Log() << Verbose(0) << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl);
655 FragmentSearch.BondsPerSPCount[SP] = 0;
656 } else
657 DoLog(0) && (Log() << Verbose(0) << "." << endl);
658
659 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
660 for (UniqueFragments::BondsPerSP::const_iterator CurrentEdge = FragmentSearch.BondsPerSPList[SP].begin();
661 CurrentEdge != FragmentSearch.BondsPerSPList[SP].end();
662 ++CurrentEdge) { /// start till end of this SP level's list
663 RemainingWalkers--;
664 Walker = (*CurrentEdge)->rightatom; // rightatom is always the one more distant
665 Predecessor = (*CurrentEdge)->leftatom; // ... and leftatom is predecessor
666 AtomKeyNr = Walker->getNr();
667 DoLog(0) && (Log() << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->getNr() << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl);
668 // check for new sp level
669 // go through all its bonds
670 DoLog(1) && (Log() << Verbose(1) << "Going through all bonds of Walker." << endl);
671 const BondList& ListOfBonds = Walker->getListOfBonds();
672 for (BondList::const_iterator Runner = ListOfBonds.begin();
673 Runner != ListOfBonds.end();
674 ++Runner) {
675 OtherWalker = (*Runner)->GetOtherAtom(Walker);
676 if ((RestrictedKeySet.find(OtherWalker->getNr()) != RestrictedKeySet.end())
677 #ifdef ADDHYDROGEN
678 && (OtherWalker->getType()->getAtomicNumber() != 1)
679 #endif
680 ) { // skip hydrogens and restrict to fragment
681 DoLog(2) && (Log() << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->getNr() << " in bond " << *(*Runner) << "." << endl);
682 // set the label if not set (and push on root stack as well)
683 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->getNr() > RootKeyNr)) { // only pass through those with label bigger than Root's
684 FragmentSearch.ShortestPathList[OtherWalker->getNr()] = SP+1;
685 DoLog(3) && (Log() << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->getNr()] << "." << endl);
686 // add the bond in between to the SP list
687 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
688 FragmentSearch.BondsPerSPList[SP+1].push_back(Binder);
689 FragmentSearch.BondsPerSPCount[SP+1]++;
690 DoLog(3) && (Log() << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl);
691 } else {
692 if (OtherWalker != Predecessor)
693 DoLog(3) && (Log() << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->getNr() << " is smaller than that of Root " << RootKeyNr << "." << endl);
694 else
695 DoLog(3) && (Log() << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl);
696 }
697 } else Log() << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
698 }
699 }
700 }
701};
702
703/** prints the Bonds per Shortest Path list in UniqueFragments.
704 * \param *out output stream
705 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
706 * \param FragmentSearch UniqueFragments
707 */
708void OutputSPList(int Order, struct UniqueFragments &FragmentSearch)
709{
710 DoLog(0) && (Log() << Verbose(0) << "Printing all found lists." << endl);
711 for(int i=1;i<Order;i++) { // skip the root edge in the printing
712 DoLog(1) && (Log() << Verbose(1) << "Current SP level is " << i << "." << endl);
713 for (UniqueFragments::BondsPerSP::const_iterator Binder = FragmentSearch.BondsPerSPList[i].begin();
714 Binder != FragmentSearch.BondsPerSPList[i].end();
715 ++Binder) {
716 DoLog(2) && (Log() << Verbose(2) << *Binder << endl);
717 }
718 }
719};
720
721/** Simply counts all bonds in all UniqueFragments::BondsPerSPList lists.
722 * \param *out output stream
723 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
724 * \param FragmentSearch UniqueFragments
725 */
726int CountNumbersInBondsList(int Order, struct UniqueFragments &FragmentSearch)
727{
728 int SP = -1; // the Root <-> Root edge must be subtracted!
729 for(int i=Order;i--;) { // sum up all found edges
730 for (UniqueFragments::BondsPerSP::const_iterator Binder = FragmentSearch.BondsPerSPList[i].begin();
731 Binder != FragmentSearch.BondsPerSPList[i].end();
732 ++Binder) {
733 SP++;
734 }
735 }
736 return SP;
737};
738
739bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
740{
741 //Log() << Verbose(0) << "my check is used." << endl;
742 if (SubgraphA.size() < SubgraphB.size()) {
743 return true;
744 } else {
745 if (SubgraphA.size() > SubgraphB.size()) {
746 return false;
747 } else {
748 KeySet::iterator IteratorA = SubgraphA.begin();
749 KeySet::iterator IteratorB = SubgraphB.begin();
750 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
751 if ((*IteratorA) < (*IteratorB))
752 return true;
753 else if ((*IteratorA) > (*IteratorB)) {
754 return false;
755 } // else, go on to next index
756 IteratorA++;
757 IteratorB++;
758 } // end of while loop
759 }// end of check in case of equal sizes
760 }
761 return false; // if we reach this point, they are equal
762};
763
764/** Combines all KeySets from all orders into single ones (with just unique entries).
765 * \param *out output stream for debugging
766 * \param *&FragmentList list to fill
767 * \param ***FragmentLowerOrdersList
768 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
769 * \param *mol molecule with atoms and bonds
770 */
771int CombineAllOrderListIntoOne(Graph *&FragmentList, Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol)
772{
773 int RootNr = 0;
774 int RootKeyNr = 0;
775 int StartNr = 0;
776 int counter = 0;
777 int NumLevels = 0;
778 atom *Walker = NULL;
779
780 DoLog(0) && (Log() << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl);
781 if (FragmentList == NULL) {
782 FragmentList = new Graph;
783 counter = 0;
784 } else {
785 counter = FragmentList->size();
786 }
787
788 StartNr = RootStack.back();
789 do {
790 RootKeyNr = RootStack.front();
791 RootStack.pop_front();
792 Walker = mol->FindAtom(RootKeyNr);
793 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
794 for(int i=0;i<NumLevels;i++) {
795 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
796 InsertGraphIntoGraph(*FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
797 }
798 }
799 RootStack.push_back(Walker->getNr());
800 RootNr++;
801 } while (RootKeyNr != StartNr);
802 return counter;
803};
804
805/** Free's memory allocated for all KeySets from all orders.
806 * \param *out output stream for debugging
807 * \param ***FragmentLowerOrdersList
808 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
809 * \param *mol molecule with atoms and bonds
810 */
811void FreeAllOrdersList(Graph ***FragmentLowerOrdersList, KeyStack &RootStack, molecule *mol)
812{
813 DoLog(1) && (Log() << Verbose(1) << "Free'ing the lists of all orders per order." << endl);
814 int RootNr = 0;
815 int RootKeyNr = 0;
816 int NumLevels = 0;
817 atom *Walker = NULL;
818 while (!RootStack.empty()) {
819 RootKeyNr = RootStack.front();
820 RootStack.pop_front();
821 Walker = mol->FindAtom(RootKeyNr);
822 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
823 for(int i=0;i<NumLevels;i++) {
824 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
825 delete(FragmentLowerOrdersList[RootNr][i]);
826 }
827 }
828 delete[](FragmentLowerOrdersList[RootNr]);
829 RootNr++;
830 }
831 delete[](FragmentLowerOrdersList);
832};
833
Note: See TracBrowser for help on using the repository browser.