source: src/molecule_fragmentation.cpp@ ba1823

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

Moved all helpers fragmentation functions into folder src/Fragmentation.

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