source: src/molecule_fragmentation.cpp@ 23fb72

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

Encapsulated UniqueFragments::Root with getter/setter.

  • Property mode set to 100644
File size: 47.3 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * molecule_fragmentation.cpp
10 *
11 * Created on: Oct 5, 2009
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include <cstring>
23
24#include "atom.hpp"
25#include "Bond/bond.hpp"
26#include "Box.hpp"
27#include "CodePatterns/Verbose.hpp"
28#include "CodePatterns/Log.hpp"
29#include "config.hpp"
30#include "Element/element.hpp"
31#include "Element/periodentafel.hpp"
32#include "Fragmentation/fragmentation_helpers.hpp"
33#include "Fragmentation/UniqueFragments.hpp"
34#include "Graph/BondGraph.hpp"
35#include "Graph/CheckAgainstAdjacencyFile.hpp"
36#include "Graph/CyclicStructureAnalysis.hpp"
37#include "Graph/DepthFirstSearchAnalysis.hpp"
38#include "Helpers/helpers.hpp"
39#include "LinearAlgebra/RealSpaceMatrix.hpp"
40#include "molecule.hpp"
41#include "World.hpp"
42
43/************************************* Functions for class molecule *********************************/
44
45
46/** Estimates by educated guessing (using upper limit) the expected number of fragments.
47 * The upper limit is
48 * \f[
49 * n = N \cdot C^k
50 * \f]
51 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
52 * \param *out output stream for debugging
53 * \param order bond order k
54 * \return number n of fragments
55 */
56int molecule::GuesstimateFragmentCount(int order)
57{
58 size_t c = 0;
59 int FragmentCount;
60 // get maximum bond degree
61 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
62 const BondList& ListOfBonds = (*iter)->getListOfBonds();
63 c = (ListOfBonds.size() > c) ? ListOfBonds.size() : c;
64 }
65 FragmentCount = NoNonHydrogen*(1 << (c*order));
66 DoLog(1) && (Log() << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl);
67 return FragmentCount;
68};
69
70/** Checks whether the OrderAtSite is still below \a Order at some site.
71 * \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
72 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
73 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
74 * \param path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
75 * \return true - needs further fragmentation, false - does not need fragmentation
76 */
77bool molecule::CheckOrderAtSite(bool *AtomMask, Graph *GlobalKeySetList, int Order, std::string path)
78{
79 bool status = false;
80
81 // initialize mask list
82 for(int i=getAtomCount();i--;)
83 AtomMask[i] = false;
84
85 if (Order < 0) { // adaptive increase of BondOrder per site
86 if (AtomMask[getAtomCount()] == true) // break after one step
87 return false;
88
89 // transmorph graph keyset list into indexed KeySetList
90 if (GlobalKeySetList == NULL) {
91 DoeLog(1) && (eLog()<< Verbose(1) << "Given global key set list (graph) is NULL!" << endl);
92 return false;
93 }
94 map<int,KeySet> *IndexKeySetList = GraphToIndexedKeySet(GlobalKeySetList);
95
96 // parse the EnergyPerFragment file
97 map<int, pair<double,int> > *AdaptiveCriteriaList = ScanAdaptiveFileIntoMap(path, *IndexKeySetList); // (Root No., (Value, Order)) !
98 if (AdaptiveCriteriaList->empty()) {
99 DoeLog(2) && (eLog()<< Verbose(2) << "Unable to parse file, incrementing all." << endl);
100 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
101 #ifdef ADDHYDROGEN
102 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
103 #endif
104 {
105 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
106 status = true;
107 }
108 }
109 }
110 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
111 map<double, pair<int,int> > *FinalRootCandidates = ReMapAdaptiveCriteriaListToValue(AdaptiveCriteriaList, this);
112
113 // pick the ones still below threshold and mark as to be adaptively updated
114 MarkUpdateCandidates(AtomMask, *FinalRootCandidates, Order, this);
115
116 delete[](IndexKeySetList);
117 delete[](AdaptiveCriteriaList);
118 delete[](FinalRootCandidates);
119 } else { // global increase of Bond Order
120 for(molecule::const_iterator iter = begin(); iter != end(); ++iter) {
121 #ifdef ADDHYDROGEN
122 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
123 #endif
124 {
125 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
126 if ((Order != 0) && ((*iter)->AdaptiveOrder < Order)) // && ((*iter)->AdaptiveOrder < MinimumRingSize[(*iter)->getNr()]))
127 status = true;
128 }
129 }
130 if ((!Order) && (!AtomMask[getAtomCount()])) // single stepping, just check
131 status = true;
132
133 if (!status) {
134 if (Order == 0)
135 DoLog(1) && (Log() << Verbose(1) << "Single stepping done." << endl);
136 else
137 DoLog(1) && (Log() << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl);
138 }
139 }
140
141 PrintAtomMask(AtomMask, getAtomCount()); // for debugging
142
143 return status;
144};
145
146/** Create a SortIndex to map from atomic labels to the sequence in which the atoms are given in the config file.
147 * \param *out output stream for debugging
148 * \param *&SortIndex Mapping array of size molecule::AtomCount
149 * \return true - success, false - failure of SortIndex alloc
150 */
151bool molecule::CreateMappingLabelsToConfigSequence(int *&SortIndex)
152{
153 if (SortIndex != NULL) {
154 DoLog(1) && (Log() << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl);
155 return false;
156 }
157 SortIndex = new int[getAtomCount()];
158 for(int i=getAtomCount();i--;)
159 SortIndex[i] = -1;
160
161 int AtomNo = 0;
162 for(internal_iterator iter=atoms.begin();iter!=atoms.end();++iter){
163 ASSERT(SortIndex[(*iter)->getNr()]==-1,"Same SortIndex set twice");
164 SortIndex[(*iter)->getNr()] = AtomNo++;
165 }
166
167 return true;
168};
169
170
171
172/** Creates a lookup table for true father's Atom::Nr -> atom ptr.
173 * \param *start begin of list (STL iterator, i.e. first item)
174 * \paran *end end of list (STL iterator, i.e. one past last item)
175 * \param **Lookuptable pointer to return allocated lookup table (should be NULL on start)
176 * \param count optional predetermined size for table (otherwise we set the count to highest true father id)
177 * \return true - success, false - failure
178 */
179bool molecule::CreateFatherLookupTable(atom **&LookupTable, int count)
180{
181 bool status = true;
182 int AtomNo;
183
184 if (LookupTable != NULL) {
185 Log() << Verbose(0) << "Pointer for Lookup table is not NULL! Aborting ..." <<endl;
186 return false;
187 }
188
189 // count them
190 if (count == 0) {
191 for (molecule::iterator iter = begin(); iter != end(); ++iter) { // create a lookup table (Atom::Nr -> atom) used as a marker table lateron
192 count = (count < (*iter)->GetTrueFather()->getNr()) ? (*iter)->GetTrueFather()->getNr() : count;
193 }
194 }
195 if (count <= 0) {
196 Log() << Verbose(0) << "Count of lookup list is 0 or less." << endl;
197 return false;
198 }
199
200 // allocate and fill
201 LookupTable = new atom *[count];
202 if (LookupTable == NULL) {
203 eLog() << Verbose(0) << "LookupTable memory allocation failed!" << endl;
204 performCriticalExit();
205 status = false;
206 } else {
207 for (int i=0;i<count;i++)
208 LookupTable[i] = NULL;
209 for (molecule::iterator iter = begin(); iter != end(); ++iter) {
210 AtomNo = (*iter)->GetTrueFather()->getNr();
211 if ((AtomNo >= 0) && (AtomNo < count)) {
212 //*out << "Setting LookupTable[" << AtomNo << "] to " << *(*iter) << endl;
213 LookupTable[AtomNo] = (*iter);
214 } else {
215 Log() << Verbose(0) << "Walker " << *(*iter) << " exceeded range of nuclear ids [0, " << count << ")." << endl;
216 status = false;
217 break;
218 }
219 }
220 }
221
222 return status;
223};
224
225
226/** Performs a many-body bond order analysis for a given bond order.
227 * -# parses adjacency, keysets and orderatsite files
228 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
229 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
230y contribution", and that's why this consciously not done in the following loop)
231 * -# in a loop over all subgraphs
232 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
233 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
234 * -# combines the generated molecule lists from all subgraphs
235 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
236 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
237 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
238 * subgraph in the MoleculeListClass.
239 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
240 * \param &prefix path and prefix of the bond order configs to be written
241 * \param &DFS contains bond structure analysis data
242 * \return 1 - continue, 2 - stop (no fragmentation occured)
243 */
244int molecule::FragmentMolecule(int Order, std::string &prefix, DepthFirstSearchAnalysis &DFS)
245{
246 MoleculeListClass *BondFragments = NULL;
247 int FragmentCounter;
248 MoleculeLeafClass *MolecularWalker = NULL;
249 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
250 fstream File;
251 bool FragmentationToDo = true;
252 bool CheckOrder = false;
253 Graph **FragmentList = NULL;
254 Graph *ParsedFragmentList = NULL;
255 Graph TotalGraph; // graph with all keysets however local numbers
256 int TotalNumberOfKeySets = 0;
257 atom ***ListOfLocalAtoms = NULL;
258 bool *AtomMask = NULL;
259
260 DoLog(0) && (Log() << Verbose(0) << endl);
261#ifdef ADDHYDROGEN
262 DoLog(0) && (Log() << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl);
263#else
264 DoLog(0) && (Log() << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl);
265#endif
266
267 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
268
269 // ===== 1. Check whether bond structure is same as stored in files ====
270
271 // === compare it with adjacency file ===
272 {
273 std::ifstream File;
274 std::string filename;
275 filename = prefix + ADJACENCYFILE;
276 File.open(filename.c_str(), ios::out);
277 DoLog(1) && (Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl);
278
279 CheckAgainstAdjacencyFile FileChecker(World::getInstance().beginAtomSelection(), World::getInstance().endAtomSelection());
280 FragmentationToDo = FragmentationToDo && FileChecker(File);
281 }
282
283 // === reset bond degree and perform CorrectBondDegree ===
284 for(World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
285 iter != World::getInstance().moleculeEnd();
286 ++iter) {
287 // correct bond degree
288 World::AtomComposite Set = (*iter)->getAtomSet();
289 World::getInstance().getBondGraph()->CorrectBondDegree(Set);
290 }
291
292 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
293 // NOTE: We assume here that DFS has been performed and molecule structure is current.
294 Subgraphs = DFS.getMoleculeStructure();
295
296 // ===== 3. if structure still valid, parse key set file and others =====
297 FragmentationToDo = FragmentationToDo && ParseKeySetFile(prefix, ParsedFragmentList);
298
299 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
300 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(prefix);
301
302 // =================================== Begin of FRAGMENTATION ===============================
303 // ===== 6a. assign each keyset to its respective subgraph =====
304 const int MolCount = World::getInstance().numMolecules();
305 ListOfLocalAtoms = new atom **[MolCount];
306 for (int i=0;i<MolCount;i++)
307 ListOfLocalAtoms[i] = NULL;
308 FragmentCounter = 0;
309 Subgraphs->next->AssignKeySetsToFragment(this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, FragmentCounter, true);
310 delete[](ListOfLocalAtoms);
311
312 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
313 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
314 AtomMask = new bool[getAtomCount()+1];
315 AtomMask[getAtomCount()] = false;
316 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
317 while ((CheckOrder = CheckOrderAtSite(AtomMask, ParsedFragmentList, Order, prefix))) {
318 FragmentationToDo = FragmentationToDo || CheckOrder;
319 AtomMask[getAtomCount()] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
320 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
321 Subgraphs->next->FillRootStackForSubgraphs(RootStack, AtomMask, (FragmentCounter = 0));
322
323 // ===== 7. fill the bond fragment list =====
324 FragmentCounter = 0;
325 MolecularWalker = Subgraphs;
326 while (MolecularWalker->next != NULL) {
327 MolecularWalker = MolecularWalker->next;
328 DoLog(1) && (Log() << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl);
329 if (MolecularWalker->Leaf->hasBondStructure()) {
330 // call BOSSANOVA method
331 DoLog(0) && (Log() << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl);
332 MolecularWalker->Leaf->FragmentBOSSANOVA(FragmentList[FragmentCounter], RootStack[FragmentCounter]);
333 } else {
334 DoeLog(1) && (eLog()<< Verbose(1) << "Subgraph " << MolecularWalker << " has no atoms!" << endl);
335 }
336 FragmentCounter++; // next fragment list
337 }
338 }
339 DoLog(2) && (Log() << Verbose(2) << "CheckOrder is " << CheckOrder << "." << endl);
340 delete[](RootStack);
341 delete[](AtomMask);
342 delete(ParsedFragmentList);
343
344 // ==================================== End of FRAGMENTATION ============================================
345
346 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
347 Subgraphs->next->TranslateIndicesToGlobalIDs(FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
348
349 // free subgraph memory again
350 FragmentCounter = 0;
351 while (Subgraphs != NULL) {
352 // remove entry in fragment list
353 // remove subgraph fragment
354 MolecularWalker = Subgraphs->next;
355 Subgraphs->Leaf = NULL;
356 delete(Subgraphs);
357 Subgraphs = MolecularWalker;
358 }
359 // free fragment list
360 for (int i=0; i< FragmentCounter; ++i )
361 delete(FragmentList[i]);
362 delete[](FragmentList);
363
364 DoLog(0) && (Log() << Verbose(0) << FragmentCounter << " subgraph fragments have been removed." << std::endl);
365
366 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
367 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
368 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
369 BondFragments = new MoleculeListClass(World::getPointer());
370 int k=0;
371 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
372 KeySet test = (*runner).first;
373 DoLog(0) && (Log() << Verbose(0) << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl);
374 BondFragments->insert(StoreFragmentFromKeySet(test, World::getInstance().getConfig()));
375 k++;
376 }
377 DoLog(0) && (Log() << Verbose(0) << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl);
378
379 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
380 if (BondFragments->ListOfMolecules.size() != 0) {
381 // create the SortIndex from BFS labels to order in the config file
382 int *SortIndex = NULL;
383 CreateMappingLabelsToConfigSequence(SortIndex);
384
385 DoLog(1) && (Log() << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl);
386 if (BondFragments->OutputConfigForListOfFragments(prefix, SortIndex))
387 DoLog(1) && (Log() << Verbose(1) << "All configs written." << endl);
388 else
389 DoLog(1) && (Log() << Verbose(1) << "Some config writing failed." << endl);
390
391 // store force index reference file
392 BondFragments->StoreForcesFile(prefix, SortIndex);
393
394 // store keysets file
395 StoreKeySetFile(TotalGraph, prefix);
396
397 {
398 // store Adjacency file
399 std::string filename = prefix + ADJACENCYFILE;
400 StoreAdjacencyToFile(filename);
401 }
402
403 // store Hydrogen saturation correction file
404 BondFragments->AddHydrogenCorrection(prefix);
405
406 // store adaptive orders into file
407 StoreOrderAtSiteFile(prefix);
408
409 // restore orbital and Stop values
410 //CalculateOrbitals(*configuration);
411
412 // free memory for bond part
413 DoLog(1) && (Log() << Verbose(1) << "Freeing bond memory" << endl);
414 delete[](SortIndex);
415 } else {
416 DoLog(1) && (Log() << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl);
417 }
418 // remove all create molecules again from the World including their atoms
419 for (MoleculeList::iterator iter = BondFragments->ListOfMolecules.begin();
420 !BondFragments->ListOfMolecules.empty();
421 iter = BondFragments->ListOfMolecules.begin()) {
422 // remove copied atoms and molecule again
423 molecule *mol = *iter;
424 mol->removeAtomsinMolecule();
425 World::getInstance().destroyMolecule(mol);
426 BondFragments->ListOfMolecules.erase(iter);
427 }
428 delete(BondFragments);
429 DoLog(0) && (Log() << Verbose(0) << "End of bond fragmentation." << endl);
430
431 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
432};
433
434
435/** Stores pairs (Atom::Nr, Atom::AdaptiveOrder) into file.
436 * Atoms not present in the file get "-1".
437 * \param &path path to file ORDERATSITEFILE
438 * \return true - file writable, false - not writable
439 */
440bool molecule::StoreOrderAtSiteFile(std::string &path)
441{
442 string line;
443 ofstream file;
444
445 line = path + ORDERATSITEFILE;
446 file.open(line.c_str());
447 DoLog(1) && (Log() << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl);
448 if (file.good()) {
449 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputOrder), &file));
450 file.close();
451 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
452 return true;
453 } else {
454 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line << "." << endl);
455 return false;
456 }
457};
458
459/** Parses pairs(Atom::Nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
460 * Atoms not present in the file get "0".
461 * \param &path path to file ORDERATSITEFILEe
462 * \return true - file found and scanned, false - file not found
463 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
464 */
465bool molecule::ParseOrderAtSiteFromFile(std::string &path)
466{
467 unsigned char *OrderArray = new unsigned char[getAtomCount()];
468 bool *MaxArray = new bool[getAtomCount()];
469 bool status;
470 int AtomNr, value;
471 string line;
472 ifstream file;
473
474 for(int i=0;i<getAtomCount();i++) {
475 OrderArray[i] = 0;
476 MaxArray[i] = false;
477 }
478
479 DoLog(1) && (Log() << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl);
480 line = path + ORDERATSITEFILE;
481 file.open(line.c_str());
482 if (file.good()) {
483 while (!file.eof()) { // parse from file
484 AtomNr = -1;
485 file >> AtomNr;
486 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
487 file >> value;
488 OrderArray[AtomNr] = value;
489 file >> value;
490 MaxArray[AtomNr] = value;
491 //Log() << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
492 }
493 }
494 file.close();
495
496 // set atom values
497 for(internal_iterator iter=atoms.begin();iter!=atoms.end();++iter){
498 (*iter)->AdaptiveOrder = OrderArray[(*iter)->getNr()];
499 (*iter)->MaxOrder = MaxArray[(*iter)->getNr()];
500 }
501 //SetAtomValueToIndexedArray( OrderArray, &atom::getNr(), &atom::AdaptiveOrder );
502 //SetAtomValueToIndexedArray( MaxArray, &atom::getNr(), &atom::MaxOrder );
503
504 DoLog(1) && (Log() << Verbose(1) << "\t ... done." << endl);
505 status = true;
506 } else {
507 DoLog(1) && (Log() << Verbose(1) << "\t ... failed to open file " << line << "." << endl);
508 status = false;
509 }
510 delete[](OrderArray);
511 delete[](MaxArray);
512
513 DoLog(1) && (Log() << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl);
514 return status;
515};
516
517
518
519/** Looks through a std::deque<atom *> and returns the likeliest removal candiate.
520 * \param *out output stream for debugging messages
521 * \param *&Leaf KeySet to look through
522 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
523 * \param index of the atom suggested for removal
524 */
525int molecule::LookForRemovalCandidate(KeySet *&Leaf, int *&ShortestPathList)
526{
527 atom *Runner = NULL;
528 int SP, Removal;
529
530 DoLog(2) && (Log() << Verbose(2) << "Looking for removal candidate." << endl);
531 SP = -1; //0; // not -1, so that Root is never removed
532 Removal = -1;
533 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
534 Runner = FindAtom((*runner));
535 if (Runner->getType()->getAtomicNumber() != 1) { // skip all those added hydrogens when re-filling snake stack
536 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
537 SP = ShortestPathList[(*runner)];
538 Removal = (*runner);
539 }
540 }
541 }
542 return Removal;
543};
544
545/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
546 * \param *mol total molecule
547 * \param *Leaf fragment molecule
548 * \param &Leaflet pointer to KeySet structure
549 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
550 * \return number of atoms in fragment
551 */
552int StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
553{
554 atom *FatherOfRunner = NULL;
555
556 // first create the minimal set of atoms from the KeySet
557 int size = 0;
558 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
559 FatherOfRunner = mol->FindAtom((*runner)); // find the id
560 SonList[FatherOfRunner->getNr()] = Leaf->AddCopyAtom(FatherOfRunner);
561 size++;
562 }
563 return size;
564};
565
566/** Creates an induced subgraph out of a fragmental key set, adding bonds and hydrogens (if treated specially).
567 * \param *out output stream for debugging messages
568 * \param *mol total molecule
569 * \param *Leaf fragment molecule
570 * \param IsAngstroem whether we have Ansgtroem or bohrradius
571 * \param **SonList list which atom of \a *Leaf is a son of which atom in \a *mol
572 */
573void CreateInducedSubgraphOfFragment(molecule *mol, molecule *Leaf, atom **SonList, bool IsAngstroem)
574{
575 bool LonelyFlag = false;
576 atom *OtherFather = NULL;
577 atom *FatherOfRunner = NULL;
578
579#ifdef ADDHYDROGEN
580 molecule::const_iterator runner;
581#endif
582 // we increment the iter just before skipping the hydrogen
583 for (molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end();) {
584 LonelyFlag = true;
585 FatherOfRunner = (*iter)->father;
586 ASSERT(FatherOfRunner,"Atom without father found");
587 if (SonList[FatherOfRunner->getNr()] != NULL) { // check if this, our father, is present in list
588 // create all bonds
589 const BondList& ListOfBonds = FatherOfRunner->getListOfBonds();
590 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
591 BondRunner != ListOfBonds.end();
592 ++BondRunner) {
593 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
594// Log() << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->getNr()] << " is bound to " << *OtherFather;
595 if (SonList[OtherFather->getNr()] != NULL) {
596// Log() << Verbose(0) << ", whose son is " << *SonList[OtherFather->getNr()] << "." << endl;
597 if (OtherFather->getNr() > FatherOfRunner->getNr()) { // add bond (Nr check is for adding only one of both variants: ab, ba)
598// Log() << Verbose(3) << "Adding Bond: ";
599// Log() << Verbose(0) <<
600 Leaf->AddBond((*iter), SonList[OtherFather->getNr()], (*BondRunner)->BondDegree);
601// Log() << Verbose(0) << "." << endl;
602 //NumBonds[(*iter)->getNr()]++;
603 } else {
604// Log() << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
605 }
606 LonelyFlag = false;
607 } else {
608// Log() << Verbose(0) << ", who has no son in this fragment molecule." << endl;
609#ifdef ADDHYDROGEN
610 //Log() << Verbose(3) << "Adding Hydrogen to " << (*iter)->Name << " and a bond in between." << endl;
611 if(!Leaf->AddHydrogenReplacementAtom((*BondRunner), (*iter), FatherOfRunner, OtherFather, IsAngstroem))
612 exit(1);
613#endif
614 //NumBonds[(*iter)->getNr()] += Binder->BondDegree;
615 }
616 }
617 } else {
618 DoeLog(1) && (eLog()<< Verbose(1) << "Son " << (*iter)->getName() << " has father " << FatherOfRunner->getName() << " but its entry in SonList is " << SonList[FatherOfRunner->getNr()] << "!" << endl);
619 }
620 if ((LonelyFlag) && (Leaf->getAtomCount() > 1)) {
621 DoLog(0) && (Log() << Verbose(0) << **iter << "has got bonds only to hydrogens!" << endl);
622 }
623 ++iter;
624#ifdef ADDHYDROGEN
625 while ((iter != Leaf->end()) && ((*iter)->getType()->getAtomicNumber() == 1)){ // skip added hydrogen
626 iter++;
627 }
628#endif
629 }
630};
631
632/** Stores a fragment from \a KeySet into \a molecule.
633 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
634 * molecule and adds missing hydrogen where bonds were cut.
635 * \param *out output stream for debugging messages
636 * \param &Leaflet pointer to KeySet structure
637 * \param IsAngstroem whether we have Ansgtroem or bohrradius
638 * \return pointer to constructed molecule
639 */
640molecule * molecule::StoreFragmentFromKeySet(KeySet &Leaflet, bool IsAngstroem)
641{
642 atom **SonList = new atom*[getAtomCount()];
643 molecule *Leaf = World::getInstance().createMolecule();
644
645 for(int i=0;i<getAtomCount();i++)
646 SonList[i] = NULL;
647
648// Log() << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
649 StoreFragmentFromKeySet_Init(this, Leaf, Leaflet, SonList);
650 // create the bonds between all: Make it an induced subgraph and add hydrogen
651// Log() << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
652 CreateInducedSubgraphOfFragment(this, Leaf, SonList, IsAngstroem);
653
654 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
655 delete[](SonList);
656// Log() << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
657 return Leaf;
658};
659
660/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
661 * -# loops over every possible combination (2^dimension of edge set)
662 * -# inserts current set, if there's still space left
663 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
664ance+1
665 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
666 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
667distance) and current set
668 * \param FragmentSearch UniqueFragments structure with all values needed
669 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
670 * \param BondsSet array of bonds to check
671 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
672 * \param SubOrder remaining number of allowed vertices to add
673 */
674void molecule::SPFragmentGenerator(struct UniqueFragments *FragmentSearch, int RootDistance, std::vector<bond *> &BondsSet, int SetDimension, int SubOrder)
675{
676 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
677 int NumCombinations;
678 int bits, TouchedIndex, SubSetDimension, SP, Added;
679 int SpaceLeft;
680 int *TouchedList = new int[SubOrder + 1];
681 KeySetTestPair TestKeySetInsert;
682
683 NumCombinations = 1 << SetDimension;
684
685 // here for all bonds of Walker all combinations of end pieces (from the bonds)
686 // have to be added and for the remaining ANOVA order GraphCrawler be called
687 // recursively for the next level
688
689 Log() << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
690 Log() << Verbose(1+verbosity) << "We are " << RootDistance << " away from Root, which is " << *FragmentSearch->getRoot() << ", SubOrder is " << SubOrder << ", SetDimension is " << SetDimension << " and this means " << NumCombinations-1 << " combination(s)." << endl;
691
692 // initialised touched list (stores added atoms on this level)
693 SPFragmentGenerator_ClearingTouched(verbosity, TouchedList, SubOrder, TouchedIndex);
694
695 // create every possible combination of the endpieces
696 Log() << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
697 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
698 // count the set bit of i
699 bits = 0;
700 for (int j=SetDimension;j--;)
701 bits += (i & (1 << j)) >> j;
702
703 Log() << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
704 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
705 // --1-- add this set of the power set of bond partners to the snake stack
706 Added = AddPowersetToSnakeStack(verbosity, i, SetDimension, FragmentSearch->FragmentSet, BondsSet, TouchedList, TouchedIndex);
707
708 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
709 if (SpaceLeft > 0) {
710 Log() << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
711 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
712 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
713 SP = RootDistance+1; // this is the next level
714
715 // first count the members in the subset
716 SubSetDimension = CountSetMembers(FragmentSearch->BondsPerSPList[SP].begin(), FragmentSearch->BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
717
718 // then allocate and fill the list
719 std::vector<bond *> BondsList;
720 BondsList.resize(SubSetDimension);
721 SubSetDimension = FillBondsList(BondsList, FragmentSearch->BondsPerSPList[SP].begin(), FragmentSearch->BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
722
723 // then iterate
724 Log() << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->getRoot() << " with sub set dimension " << SubSetDimension << "." << endl;
725 SPFragmentGenerator(FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
726 }
727 } else {
728 // --2-- otherwise store the complete fragment
729 Log() << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
730 // store fragment as a KeySet
731 DoLog(2) && (Log() << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ");
732 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
733 DoLog(0) && (Log() << Verbose(0) << (*runner) << " ");
734 DoLog(0) && (Log() << Verbose(0) << endl);
735 FragmentSearch->InsertFragmentIntoGraph();
736 }
737
738 // --3-- remove all added items in this level from snake stack
739 Log() << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
740 RemoveAllTouchedFromSnakeStack(verbosity, FragmentSearch->FragmentSet, TouchedList, TouchedIndex);
741 } else {
742 Log() << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
743 }
744 }
745 delete[](TouchedList);
746 Log() << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->getRoot() << " and SubOrder is " << SubOrder << "." << endl;
747};
748
749
750/** 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.
751 * -# initialises UniqueFragments structure
752 * -# fills edge list via BFS
753 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
754 root distance, the edge set, its dimension and the current suborder
755 * -# Free'ing structure
756 * 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
757 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
758 * \param *out output stream for debugging
759 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
760 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
761 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
762 * \return number of inserted fragments
763 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
764 */
765int molecule::PowerSetGenerator(int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
766{
767 int Counter = FragmentSearch.FragmentCounter; // mark current value of counter
768
769 DoLog(0) && (Log() << Verbose(0) << endl);
770 DoLog(0) && (Log() << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.getRoot() << "." << endl);
771
772 FragmentSearch.SetSPList(Order);
773
774 // do a BFS search to fill the SP lists and label the found vertices
775 FragmentSearch.FillSPListandLabelVertices(Order, RestrictedKeySet);
776
777 // outputting all list for debugging
778 FragmentSearch.OutputSPList(Order);
779
780 // creating fragments with the found edge sets (may be done in reverse order, faster)
781 int SP = FragmentSearch.CountNumbersInBondsList(Order);
782 DoLog(0) && (Log() << Verbose(0) << "Total number of edges is " << SP << "." << endl);
783 if (SP >= (Order-1)) {
784 // start with root (push on fragment stack)
785 DoLog(0) && (Log() << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.getRoot() << ", local nr is " << FragmentSearch.getRoot()->getNr() << "." << endl);
786 FragmentSearch.FragmentSet->clear();
787 DoLog(0) && (Log() << Verbose(0) << "Preparing subset for this root and calling generator." << endl);
788
789 // prepare the subset and call the generator
790 std::vector<bond*> BondsList;
791 BondsList.resize(FragmentSearch.BondsPerSPCount[0]);
792 ASSERT(FragmentSearch.BondsPerSPList[0].size() != 0,
793 "molecule::PowerSetGenerator() - FragmentSearch.BondsPerSPList[0] contains no root bond.");
794 BondsList[0] = (*FragmentSearch.BondsPerSPList[0].begin()); // on SP level 0 there's only the root bond
795
796 SPFragmentGenerator(&FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
797 } else {
798 DoLog(0) && (Log() << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl);
799 }
800
801 // as FragmentSearch structure is used only once, we don't have to clean it anymore
802 // remove root from stack
803 DoLog(0) && (Log() << Verbose(0) << "Removing root again from stack." << endl);
804 FragmentSearch.FragmentSet->erase(FragmentSearch.getRoot()->getNr());
805
806 // free'ing the bonds lists
807 FragmentSearch.ResetSPList(Order);
808
809 // return list
810 DoLog(0) && (Log() << Verbose(0) << "End of PowerSetGenerator." << endl);
811 return (FragmentSearch.FragmentCounter - Counter);
812};
813
814
815
816
817/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
818 * -# constructs a complete keyset of the molecule
819 * -# In a loop over all possible roots from the given rootstack
820 * -# increases order of root site
821 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
822 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
823as the restricted one and each site in the set as the root)
824 * -# these are merged into a fragment list of keysets
825 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
826 * Important only is that we create all fragments, it is not important if we create them more than once
827 * as these copies are filtered out via use of the hash table (KeySet).
828 * \param *out output stream for debugging
829 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
830 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
831 * \return pointer to Graph list
832 */
833void molecule::FragmentBOSSANOVA(Graph *&FragmentList, KeyStack &RootStack)
834{
835 Graph ***FragmentLowerOrdersList = NULL;
836 int NumLevels = 0;
837 int NumMolecules = 0;
838 int TotalNumMolecules = 0;
839 int *NumMoleculesOfOrder = NULL;
840 int Order = 0;
841 int UpgradeCount = RootStack.size();
842 KeyStack FragmentRootStack;
843 int RootKeyNr = 0;
844 int RootNr = 0;
845 struct UniqueFragments FragmentSearch;
846
847 DoLog(0) && (Log() << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl);
848
849 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
850 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
851 NumMoleculesOfOrder = new int[UpgradeCount];
852 FragmentLowerOrdersList = new Graph**[UpgradeCount];
853
854 for(int i=0;i<UpgradeCount;i++) {
855 NumMoleculesOfOrder[i] = 0;
856 FragmentLowerOrdersList[i] = NULL;
857 }
858
859 FragmentSearch.Init(FindAtom(RootKeyNr), getAtomCount());
860
861 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
862 KeySet CompleteMolecule;
863 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
864 CompleteMolecule.insert((*iter)->GetTrueFather()->getNr());
865 }
866
867 // 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
868 // 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),
869 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
870 // 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)
871 RootNr = 0; // counts through the roots in RootStack
872 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
873 RootKeyNr = RootStack.front();
874 RootStack.pop_front();
875 atom *Walker = FindAtom(RootKeyNr);
876 // check cyclic lengths
877 //if ((MinimumRingSize[Walker->GetTrueFather()->getNr()] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->getNr()])) {
878 // 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;
879 //} else
880 {
881 // increase adaptive order by one
882 Walker->GetTrueFather()->AdaptiveOrder++;
883 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
884
885 // initialise Order-dependent entries of UniqueFragments structure
886 FragmentSearch.InitialiseSPList(Order);
887
888 // allocate memory for all lower level orders in this 1D-array of ptrs
889 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
890 FragmentLowerOrdersList[RootNr] = new Graph*[NumLevels];
891 for (int i=0;i<NumLevels;i++)
892 FragmentLowerOrdersList[RootNr][i] = NULL;
893
894 // create top order where nothing is reduced
895 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
896 DoLog(0) && (Log() << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl); // , NumLevels is " << NumLevels << "
897
898 // Create list of Graphs of current Bond Order (i.e. F_{ij})
899 FragmentLowerOrdersList[RootNr][0] = new Graph;
900 FragmentSearch.TEFactor = 1.;
901 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
902 FragmentSearch.setRoot(Walker);
903 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
904
905 // output resulting number
906 DoLog(1) && (Log() << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl);
907 if (NumMoleculesOfOrder[RootNr] != 0) {
908 NumMolecules = 0;
909 } else {
910 Walker->GetTrueFather()->MaxOrder = true;
911 }
912 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
913 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
914 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
915// Log() << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
916 RootStack.push_back(RootKeyNr); // put back on stack
917 RootNr++;
918
919 // free Order-dependent entries of UniqueFragments structure for next loop cycle
920 FragmentSearch.FreeSPList(Order);
921 }
922 }
923 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
924 DoLog(1) && (Log() << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl);
925 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
926
927 // cleanup FragmentSearch structure
928 FragmentSearch.Cleanup();
929
930 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
931 // 5433222211111111
932 // 43221111
933 // 3211
934 // 21
935 // 1
936
937 // Subsequently, we combine all into a single list (FragmentList)
938 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, this);
939 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, this);
940 delete[](NumMoleculesOfOrder);
941
942 DoLog(0) && (Log() << Verbose(0) << "End of FragmentBOSSANOVA." << endl);
943};
944
945/** Corrects the nuclei position if the fragment was created over the cell borders.
946 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
947 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
948 * and re-add the bond. Looping on the distance check.
949 * \param *out ofstream for debugging messages
950 */
951bool molecule::ScanForPeriodicCorrection()
952{
953 bond *Binder = NULL;
954 //bond *OtherBinder = NULL;
955 atom *Walker = NULL;
956 atom *OtherWalker = NULL;
957 RealSpaceMatrix matrix = World::getInstance().getDomain().getM();
958 enum GraphEdge::Shading *ColorList = NULL;
959 double tmp;
960 //bool LastBond = true; // only needed to due list construct
961 Vector Translationvector;
962 //std::deque<atom *> *CompStack = NULL;
963 std::deque<atom *> *AtomStack = new std::deque<atom *>; // (getAtomCount());
964 bool flag = true;
965 BondGraph *BG = World::getInstance().getBondGraph();
966
967 DoLog(2) && (Log() << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl);
968
969 ColorList = new enum GraphEdge::Shading[getAtomCount()];
970 for (int i=0;i<getAtomCount();i++)
971 ColorList[i] = (enum GraphEdge::Shading)0;
972 if (flag) {
973 // remove bonds that are beyond bonddistance
974 Translationvector.Zero();
975 // scan all bonds
976 flag = false;
977 for(molecule::iterator AtomRunner = begin(); (!flag) && (AtomRunner != end()); ++AtomRunner) {
978 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
979 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
980 (!flag) && (BondRunner != ListOfBonds.end());
981 ++BondRunner) {
982 Binder = (*BondRunner);
983 for (int i=NDIM;i--;) {
984 tmp = fabs(Binder->leftatom->at(i) - Binder->rightatom->at(i));
985 //Log() << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
986 const range<double> MinMaxDistance(
987 BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom));
988 if (!MinMaxDistance.isInRange(tmp)) {
989 DoLog(2) && (Log() << Verbose(2) << "Correcting at bond " << *Binder << "." << endl);
990 flag = true;
991 break;
992 }
993 }
994 }
995 }
996 //if (flag) {
997 if (0) {
998 // create translation vector from their periodically modified distance
999 for (int i=NDIM;i--;) {
1000 tmp = Binder->leftatom->at(i) - Binder->rightatom->at(i);
1001 const range<double> MinMaxDistance(
1002 BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom));
1003 if (fabs(tmp) > MinMaxDistance.last) // check against Min is not useful for components
1004 Translationvector[i] = (tmp < 0) ? +1. : -1.;
1005 }
1006 Translationvector *= matrix;
1007 //Log() << Verbose(3) << "Translation vector is ";
1008 Log() << Verbose(0) << Translationvector << endl;
1009 // apply to all atoms of first component via BFS
1010 for (int i=getAtomCount();i--;)
1011 ColorList[i] = GraphEdge::white;
1012 AtomStack->push_front(Binder->leftatom);
1013 while (!AtomStack->empty()) {
1014 Walker = AtomStack->front();
1015 AtomStack->pop_front();
1016 //Log() << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
1017 ColorList[Walker->getNr()] = GraphEdge::black; // mark as explored
1018 *Walker += Translationvector; // translate
1019 const BondList& ListOfBonds = Walker->getListOfBonds();
1020 for (BondList::const_iterator Runner = ListOfBonds.begin();
1021 Runner != ListOfBonds.end();
1022 ++Runner) {
1023 if ((*Runner) != Binder) {
1024 OtherWalker = (*Runner)->GetOtherAtom(Walker);
1025 if (ColorList[OtherWalker->getNr()] == GraphEdge::white) {
1026 AtomStack->push_front(OtherWalker); // push if yet unexplored
1027 }
1028 }
1029 }
1030 }
1031// // re-add bond
1032// if (OtherBinder == NULL) { // is the only bond?
1033// //Do nothing
1034// } else {
1035// if (!LastBond) {
1036// link(Binder, OtherBinder); // no more implemented bond::previous ...
1037// } else {
1038// link(OtherBinder, Binder); // no more implemented bond::previous ...
1039// }
1040// }
1041 } else {
1042 DoLog(3) && (Log() << Verbose(3) << "No corrections for this fragment." << endl);
1043 }
1044 //delete(CompStack);
1045 }
1046 // free allocated space from ReturnFullMatrixforSymmetric()
1047 delete(AtomStack);
1048 delete[](ColorList);
1049 DoLog(2) && (Log() << Verbose(2) << "End of ScanForPeriodicCorrection." << endl);
1050
1051 return flag;
1052};
Note: See TracBrowser for help on using the repository browser.