source: src/molecule_fragmentation.cpp@ f2bb0f

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 f2bb0f was 9879f6, checked in by Frederik Heber <heber@…>, 15 years ago

Huge Refactoring due to class molecule now being an STL container.

  • molecule::start and molecule::end were dropped. Hence, the usual construct Walker = start while (Walker->next != end) {

Walker = walker->next
...

}
was changed to
for (molecule::iterator iter = begin(); iter != end(); ++iter) {

...

}
and (*iter) used instead of Walker.

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