source: src/molecule_fragmentation.cpp@ 0d1ad0

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 0d1ad0 was 35b698, checked in by Frederik Heber <heber@…>, 15 years ago

BIG CHANGE: config::load and config::save in ParseCommandLineOptions() and main() replaced with FormatParser replacements.

Fragmentation:

  • FIX: MoleculeFillWithMoleculeAction: filler atoms have to be removed before the system can be stored to file.
  • FIX: PcpParser::load() - has to put the molecule also into World's MoleculeListClass (otherwise the name cannot be set right after loading)
  • new Libparser.a
  • all sources from PARSER subdir are compiled into libparser such that only ParserUnitTest is recompiled.

Testfixes:

  • testsuite-fragmentation - changes to due to different -f calling syntax.
  • most of the xyz files had to be replaced due to a single whitespace at the end of each entry: Domain/6, Simple_configuration/2, Simple_configuration/3, Simple_configuration/4, Simple_configuration/5, Simple_configuration/8
  • in many cases were the number orbitals (and thus MaxMinStopStep) wrong: Filling/1, Simple_configuration/4, Simple_configuration/5

Signed-off-by: Frederik Heber <heber@…>

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