source: src/Fragmentation/Fragmentation.cpp@ 246e13

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 Candidate_v1.7.0 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 246e13 was 246e13, checked in by Frederik Heber <heber@…>, 14 years ago

Placed FragmentMolecule, FragmentBOSSANOVA and subfunctions into own class Fragmentation.

  • Property mode set to 100644
File size: 30.8 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * Fragmentation.cpp
10 *
11 * Created on: Oct 18, 2011
12 * Author: heber
13 */
14
15#ifdef HAVE_CONFIG_H
16#include <config.h>
17#endif
18
19#include "CodePatterns/MemDebug.hpp"
20
21#include "Fragmentation.hpp"
22
23#include "CodePatterns/Assert.hpp"
24#include "CodePatterns/Log.hpp"
25
26#include "atom.hpp"
27#include "Bond/bond.hpp"
28#include "Element/element.hpp"
29#include "Element/periodentafel.hpp"
30#include "Fragmentation/fragmentation_helpers.hpp"
31#include "Fragmentation/PowerSetGenerator.hpp"
32#include "Fragmentation/UniqueFragments.hpp"
33#include "graph.hpp"
34#include "Graph/BondGraph.hpp"
35#include "Graph/CheckAgainstAdjacencyFile.hpp"
36#include "molecule.hpp"
37#include "World.hpp"
38
39
40/** Constructor of class Fragmentation.
41 *
42 */
43Fragmentation::Fragmentation(molecule *_mol) :
44 mol(_mol)
45{}
46
47/** Destructor of class Fragmentation.
48 *
49 */
50Fragmentation::~Fragmentation()
51{}
52
53
54/** Performs a many-body bond order analysis for a given bond order.
55 * -# parses adjacency, keysets and orderatsite files
56 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
57 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
58y contribution", and that's why this consciously not done in the following loop)
59 * -# in a loop over all subgraphs
60 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
61 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
62 * -# combines the generated molecule lists from all subgraphs
63 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
64 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
65 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
66 * subgraph in the MoleculeListClass.
67 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
68 * \param &prefix path and prefix of the bond order configs to be written
69 * \param &DFS contains bond structure analysis data
70 * \return 1 - continue, 2 - stop (no fragmentation occured)
71 */
72int Fragmentation::FragmentMolecule(int Order, std::string &prefix, DepthFirstSearchAnalysis &DFS)
73{
74 MoleculeListClass *BondFragments = NULL;
75 int FragmentCounter;
76 MoleculeLeafClass *MolecularWalker = NULL;
77 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
78 fstream File;
79 bool FragmentationToDo = true;
80 bool CheckOrder = false;
81 Graph **FragmentList = NULL;
82 Graph *ParsedFragmentList = NULL;
83 Graph TotalGraph; // graph with all keysets however local numbers
84 int TotalNumberOfKeySets = 0;
85 atom ***ListOfLocalAtoms = NULL;
86 bool *AtomMask = NULL;
87
88 DoLog(0) && (Log() << Verbose(0) << endl);
89#ifdef ADDHYDROGEN
90 DoLog(0) && (Log() << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl);
91#else
92 DoLog(0) && (Log() << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl);
93#endif
94
95 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
96
97 // ===== 1. Check whether bond structure is same as stored in files ====
98
99 // === compare it with adjacency file ===
100 {
101 std::ifstream File;
102 std::string filename;
103 filename = prefix + ADJACENCYFILE;
104 File.open(filename.c_str(), ios::out);
105 DoLog(1) && (Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl);
106
107 CheckAgainstAdjacencyFile FileChecker(World::getInstance().beginAtomSelection(), World::getInstance().endAtomSelection());
108 FragmentationToDo = FragmentationToDo && FileChecker(File);
109 }
110
111 // === reset bond degree and perform CorrectBondDegree ===
112 for(World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
113 iter != World::getInstance().moleculeEnd();
114 ++iter) {
115 // correct bond degree
116 World::AtomComposite Set = (*iter)->getAtomSet();
117 World::getInstance().getBondGraph()->CorrectBondDegree(Set);
118 }
119
120 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
121 // NOTE: We assume here that DFS has been performed and molecule structure is current.
122 Subgraphs = DFS.getMoleculeStructure();
123
124 // ===== 3. if structure still valid, parse key set file and others =====
125 FragmentationToDo = FragmentationToDo && ParseKeySetFile(prefix, ParsedFragmentList);
126
127 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
128 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(prefix);
129
130 // =================================== Begin of FRAGMENTATION ===============================
131 // ===== 6a. assign each keyset to its respective subgraph =====
132 const int MolCount = World::getInstance().numMolecules();
133 ListOfLocalAtoms = new atom **[MolCount];
134 for (int i=0;i<MolCount;i++)
135 ListOfLocalAtoms[i] = NULL;
136 FragmentCounter = 0;
137 Subgraphs->next->AssignKeySetsToFragment(mol, ParsedFragmentList, ListOfLocalAtoms, FragmentList, FragmentCounter, true);
138 delete[](ListOfLocalAtoms);
139
140 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
141 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
142 AtomMask = new bool[mol->getAtomCount()+1];
143 AtomMask[mol->getAtomCount()] = false;
144 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
145 while ((CheckOrder = CheckOrderAtSite(AtomMask, ParsedFragmentList, Order, prefix))) {
146 FragmentationToDo = FragmentationToDo || CheckOrder;
147 AtomMask[mol->getAtomCount()] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
148 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
149 Subgraphs->next->FillRootStackForSubgraphs(RootStack, AtomMask, (FragmentCounter = 0));
150
151 // ===== 7. fill the bond fragment list =====
152 FragmentCounter = 0;
153 MolecularWalker = Subgraphs;
154 while (MolecularWalker->next != NULL) {
155 MolecularWalker = MolecularWalker->next;
156 DoLog(1) && (Log() << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl);
157 if (MolecularWalker->Leaf->hasBondStructure()) {
158 // call BOSSANOVA method
159 DoLog(0) && (Log() << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl);
160 FragmentBOSSANOVA(MolecularWalker->Leaf, FragmentList[FragmentCounter], RootStack[FragmentCounter]);
161 } else {
162 DoeLog(1) && (eLog()<< Verbose(1) << "Subgraph " << MolecularWalker << " has no atoms!" << endl);
163 }
164 FragmentCounter++; // next fragment list
165 }
166 }
167 DoLog(2) && (Log() << Verbose(2) << "CheckOrder is " << CheckOrder << "." << endl);
168 delete[](RootStack);
169 delete[](AtomMask);
170 delete(ParsedFragmentList);
171
172 // ==================================== End of FRAGMENTATION ============================================
173
174 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
175 Subgraphs->next->TranslateIndicesToGlobalIDs(FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
176
177 // free subgraph memory again
178 FragmentCounter = 0;
179 while (Subgraphs != NULL) {
180 // remove entry in fragment list
181 // remove subgraph fragment
182 MolecularWalker = Subgraphs->next;
183 Subgraphs->Leaf = NULL;
184 delete(Subgraphs);
185 Subgraphs = MolecularWalker;
186 }
187 // free fragment list
188 for (int i=0; i< FragmentCounter; ++i )
189 delete(FragmentList[i]);
190 delete[](FragmentList);
191
192 DoLog(0) && (Log() << Verbose(0) << FragmentCounter << " subgraph fragments have been removed." << std::endl);
193
194 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
195 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
196 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
197 BondFragments = new MoleculeListClass(World::getPointer());
198 int k=0;
199 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
200 KeySet test = (*runner).first;
201 DoLog(0) && (Log() << Verbose(0) << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl);
202 BondFragments->insert(StoreFragmentFromKeySet(test, World::getInstance().getConfig()));
203 k++;
204 }
205 DoLog(0) && (Log() << Verbose(0) << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl);
206
207 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
208 if (BondFragments->ListOfMolecules.size() != 0) {
209 // create the SortIndex from BFS labels to order in the config file
210 int *SortIndex = NULL;
211 CreateMappingLabelsToConfigSequence(SortIndex);
212
213 DoLog(1) && (Log() << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl);
214 if (BondFragments->OutputConfigForListOfFragments(prefix, SortIndex))
215 DoLog(1) && (Log() << Verbose(1) << "All configs written." << endl);
216 else
217 DoLog(1) && (Log() << Verbose(1) << "Some config writing failed." << endl);
218
219 // store force index reference file
220 BondFragments->StoreForcesFile(prefix, SortIndex);
221
222 // store keysets file
223 StoreKeySetFile(TotalGraph, prefix);
224
225 {
226 // store Adjacency file
227 std::string filename = prefix + ADJACENCYFILE;
228 mol->StoreAdjacencyToFile(filename);
229 }
230
231 // store Hydrogen saturation correction file
232 BondFragments->AddHydrogenCorrection(prefix);
233
234 // store adaptive orders into file
235 StoreOrderAtSiteFile(prefix);
236
237 // restore orbital and Stop values
238 //CalculateOrbitals(*configuration);
239
240 // free memory for bond part
241 DoLog(1) && (Log() << Verbose(1) << "Freeing bond memory" << endl);
242 delete[](SortIndex);
243 } else {
244 DoLog(1) && (Log() << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl);
245 }
246 // remove all create molecules again from the World including their atoms
247 for (MoleculeList::iterator iter = BondFragments->ListOfMolecules.begin();
248 !BondFragments->ListOfMolecules.empty();
249 iter = BondFragments->ListOfMolecules.begin()) {
250 // remove copied atoms and molecule again
251 molecule *mol = *iter;
252 mol->removeAtomsinMolecule();
253 World::getInstance().destroyMolecule(mol);
254 BondFragments->ListOfMolecules.erase(iter);
255 }
256 delete(BondFragments);
257 DoLog(0) && (Log() << Verbose(0) << "End of bond fragmentation." << endl);
258
259 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
260};
261
262
263/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
264 * -# constructs a complete keyset of the molecule
265 * -# In a loop over all possible roots from the given rootstack
266 * -# increases order of root site
267 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
268 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
269as the restricted one and each site in the set as the root)
270 * -# these are merged into a fragment list of keysets
271 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
272 * Important only is that we create all fragments, it is not important if we create them more than once
273 * as these copies are filtered out via use of the hash table (KeySet).
274 * \param *out output stream for debugging
275 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
276 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
277 * \return pointer to Graph list
278 */
279void Fragmentation::FragmentBOSSANOVA(molecule *mol, Graph *&FragmentList, KeyStack &RootStack)
280{
281 Graph ***FragmentLowerOrdersList = NULL;
282 int NumLevels = 0;
283 int NumMolecules = 0;
284 int TotalNumMolecules = 0;
285 int *NumMoleculesOfOrder = NULL;
286 int Order = 0;
287 int UpgradeCount = RootStack.size();
288 KeyStack FragmentRootStack;
289 int RootKeyNr = 0;
290 int RootNr = 0;
291 UniqueFragments FragmentSearch;
292
293 DoLog(0) && (Log() << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl);
294
295 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
296 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
297 NumMoleculesOfOrder = new int[UpgradeCount];
298 FragmentLowerOrdersList = new Graph**[UpgradeCount];
299
300 for(int i=0;i<UpgradeCount;i++) {
301 NumMoleculesOfOrder[i] = 0;
302 FragmentLowerOrdersList[i] = NULL;
303 }
304
305 FragmentSearch.Init(mol->FindAtom(RootKeyNr));
306
307 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
308 KeySet CompleteMolecule;
309 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
310 CompleteMolecule.insert((*iter)->GetTrueFather()->getNr());
311 }
312
313 // 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
314 // 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),
315 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
316 // 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)
317 RootNr = 0; // counts through the roots in RootStack
318 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
319 RootKeyNr = RootStack.front();
320 RootStack.pop_front();
321 atom *Walker = mol->FindAtom(RootKeyNr);
322 // check cyclic lengths
323 //if ((MinimumRingSize[Walker->GetTrueFather()->getNr()] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->getNr()])) {
324 // 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;
325 //} else
326 {
327 // increase adaptive order by one
328 Walker->GetTrueFather()->AdaptiveOrder++;
329 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
330
331 // initialise Order-dependent entries of UniqueFragments structure
332 class PowerSetGenerator PSG(&FragmentSearch, Walker->AdaptiveOrder);
333
334 // allocate memory for all lower level orders in this 1D-array of ptrs
335 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
336 FragmentLowerOrdersList[RootNr] = new Graph*[NumLevels];
337 for (int i=0;i<NumLevels;i++)
338 FragmentLowerOrdersList[RootNr][i] = NULL;
339
340 // create top order where nothing is reduced
341 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
342 DoLog(0) && (Log() << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl); // , NumLevels is " << NumLevels << "
343
344 // Create list of Graphs of current Bond Order (i.e. F_{ij})
345 FragmentLowerOrdersList[RootNr][0] = new Graph;
346 FragmentSearch.PrepareForPowersetGeneration(1., FragmentLowerOrdersList[RootNr][0], Walker);
347 NumMoleculesOfOrder[RootNr] = PSG(CompleteMolecule);
348
349 // output resulting number
350 DoLog(1) && (Log() << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl);
351 if (NumMoleculesOfOrder[RootNr] != 0) {
352 NumMolecules = 0;
353 } else {
354 Walker->GetTrueFather()->MaxOrder = true;
355 }
356 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
357 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
358 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
359// Log() << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
360 RootStack.push_back(RootKeyNr); // put back on stack
361 RootNr++;
362 }
363 }
364 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
365 DoLog(1) && (Log() << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl);
366 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
367
368 // cleanup FragmentSearch structure
369 FragmentSearch.Cleanup();
370
371 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
372 // 5433222211111111
373 // 43221111
374 // 3211
375 // 21
376 // 1
377
378 // Subsequently, we combine all into a single list (FragmentList)
379 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, mol);
380 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, mol);
381 delete[](NumMoleculesOfOrder);
382
383 DoLog(0) && (Log() << Verbose(0) << "End of FragmentBOSSANOVA." << endl);
384};
385
386/** Stores a fragment from \a KeySet into \a molecule.
387 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
388 * molecule and adds missing hydrogen where bonds were cut.
389 * \param *out output stream for debugging messages
390 * \param &Leaflet pointer to KeySet structure
391 * \param IsAngstroem whether we have Ansgtroem or bohrradius
392 * \return pointer to constructed molecule
393 */
394molecule * Fragmentation::StoreFragmentFromKeySet(KeySet &Leaflet, bool IsAngstroem)
395{
396 atom **SonList = new atom*[mol->getAtomCount()];
397 molecule *Leaf = World::getInstance().createMolecule();
398
399 for(int i=0;i<mol->getAtomCount();i++)
400 SonList[i] = NULL;
401
402// Log() << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
403 StoreFragmentFromKeySet_Init(mol, Leaf, Leaflet, SonList);
404 // create the bonds between all: Make it an induced subgraph and add hydrogen
405// Log() << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
406 CreateInducedSubgraphOfFragment(mol, Leaf, SonList, IsAngstroem);
407
408 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
409 delete[](SonList);
410// Log() << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
411 return Leaf;
412};
413
414
415/** Estimates by educated guessing (using upper limit) the expected number of fragments.
416 * The upper limit is
417 * \f[
418 * n = N \cdot C^k
419 * \f]
420 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
421 * \param *out output stream for debugging
422 * \param order bond order k
423 * \return number n of fragments
424 */
425int Fragmentation::GuesstimateFragmentCount(int order)
426{
427 size_t c = 0;
428 int FragmentCount;
429 // get maximum bond degree
430 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
431 const BondList& ListOfBonds = (*iter)->getListOfBonds();
432 c = (ListOfBonds.size() > c) ? ListOfBonds.size() : c;
433 }
434 FragmentCount = mol->NoNonHydrogen*(1 << (c*order));
435 DoLog(1) && (Log() << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << mol->NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl);
436 return FragmentCount;
437};
438
439
440/** Checks whether the OrderAtSite is still below \a Order at some site.
441 * \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
442 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
443 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
444 * \param path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
445 * \return true - needs further fragmentation, false - does not need fragmentation
446 */
447bool Fragmentation::CheckOrderAtSite(bool *AtomMask, Graph *GlobalKeySetList, int Order, std::string path)
448{
449 bool status = false;
450
451 // initialize mask list
452 for(int i=mol->getAtomCount();i--;)
453 AtomMask[i] = false;
454
455 if (Order < 0) { // adaptive increase of BondOrder per site
456 if (AtomMask[mol->getAtomCount()] == true) // break after one step
457 return false;
458
459 // transmorph graph keyset list into indexed KeySetList
460 if (GlobalKeySetList == NULL) {
461 DoeLog(1) && (eLog()<< Verbose(1) << "Given global key set list (graph) is NULL!" << endl);
462 return false;
463 }
464 map<int,KeySet> *IndexKeySetList = GraphToIndexedKeySet(GlobalKeySetList);
465
466 // parse the EnergyPerFragment file
467 map<int, pair<double,int> > *AdaptiveCriteriaList = ScanAdaptiveFileIntoMap(path, *IndexKeySetList); // (Root No., (Value, Order)) !
468 if (AdaptiveCriteriaList->empty()) {
469 DoeLog(2) && (eLog()<< Verbose(2) << "Unable to parse file, incrementing all." << endl);
470 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
471 #ifdef ADDHYDROGEN
472 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
473 #endif
474 {
475 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
476 status = true;
477 }
478 }
479 }
480 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
481 map<double, pair<int,int> > *FinalRootCandidates = ReMapAdaptiveCriteriaListToValue(AdaptiveCriteriaList, mol);
482
483 // pick the ones still below threshold and mark as to be adaptively updated
484 MarkUpdateCandidates(AtomMask, *FinalRootCandidates, Order, mol);
485
486 delete[](IndexKeySetList);
487 delete[](AdaptiveCriteriaList);
488 delete[](FinalRootCandidates);
489 } else { // global increase of Bond Order
490 for(molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
491 #ifdef ADDHYDROGEN
492 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
493 #endif
494 {
495 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
496 if ((Order != 0) && ((*iter)->AdaptiveOrder < Order)) // && ((*iter)->AdaptiveOrder < MinimumRingSize[(*iter)->getNr()]))
497 status = true;
498 }
499 }
500 if ((!Order) && (!AtomMask[mol->getAtomCount()])) // single stepping, just check
501 status = true;
502
503 if (!status) {
504 if (Order == 0)
505 DoLog(1) && (Log() << Verbose(1) << "Single stepping done." << endl);
506 else
507 DoLog(1) && (Log() << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl);
508 }
509 }
510
511 PrintAtomMask(AtomMask, mol->getAtomCount()); // for debugging
512
513 return status;
514};
515
516/** Stores pairs (Atom::Nr, Atom::AdaptiveOrder) into file.
517 * Atoms not present in the file get "-1".
518 * \param &path path to file ORDERATSITEFILE
519 * \return true - file writable, false - not writable
520 */
521bool Fragmentation::StoreOrderAtSiteFile(std::string &path)
522{
523 string line;
524 ofstream file;
525
526 line = path + ORDERATSITEFILE;
527 file.open(line.c_str());
528 DoLog(1) && (Log() << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl);
529 if (file.good()) {
530 for_each(mol->begin(),mol->end(),bind2nd(mem_fun(&atom::OutputOrder), &file));
531 file.close();
532 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
533 return true;
534 } else {
535 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line << "." << endl);
536 return false;
537 }
538};
539
540
541/** Parses pairs(Atom::Nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
542 * Atoms not present in the file get "0".
543 * \param &path path to file ORDERATSITEFILEe
544 * \return true - file found and scanned, false - file not found
545 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
546 */
547bool Fragmentation::ParseOrderAtSiteFromFile(std::string &path)
548{
549 unsigned char *OrderArray = new unsigned char[mol->getAtomCount()];
550 bool *MaxArray = new bool[mol->getAtomCount()];
551 bool status;
552 int AtomNr, value;
553 string line;
554 ifstream file;
555
556 for(int i=0;i<mol->getAtomCount();i++) {
557 OrderArray[i] = 0;
558 MaxArray[i] = false;
559 }
560
561 DoLog(1) && (Log() << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl);
562 line = path + ORDERATSITEFILE;
563 file.open(line.c_str());
564 if (file.good()) {
565 while (!file.eof()) { // parse from file
566 AtomNr = -1;
567 file >> AtomNr;
568 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
569 file >> value;
570 OrderArray[AtomNr] = value;
571 file >> value;
572 MaxArray[AtomNr] = value;
573 //Log() << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
574 }
575 }
576 file.close();
577
578 // set atom values
579 for(molecule::const_iterator iter=mol->begin();iter!=mol->end();++iter){
580 (*iter)->AdaptiveOrder = OrderArray[(*iter)->getNr()];
581 (*iter)->MaxOrder = MaxArray[(*iter)->getNr()];
582 }
583 //SetAtomValueToIndexedArray( OrderArray, &atom::getNr(), &atom::AdaptiveOrder );
584 //SetAtomValueToIndexedArray( MaxArray, &atom::getNr(), &atom::MaxOrder );
585
586 DoLog(1) && (Log() << Verbose(1) << "\t ... done." << endl);
587 status = true;
588 } else {
589 DoLog(1) && (Log() << Verbose(1) << "\t ... failed to open file " << line << "." << endl);
590 status = false;
591 }
592 delete[](OrderArray);
593 delete[](MaxArray);
594
595 DoLog(1) && (Log() << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl);
596 return status;
597};
598
599/** Create a SortIndex to map from atomic labels to the sequence in which the atoms are given in the config file.
600 * \param *out output stream for debugging
601 * \param *&SortIndex Mapping array of size molecule::AtomCount
602 * \return true - success, false - failure of SortIndex alloc
603 */
604bool Fragmentation::CreateMappingLabelsToConfigSequence(int *&SortIndex)
605{
606 if (SortIndex != NULL) {
607 DoLog(1) && (Log() << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl);
608 return false;
609 }
610 SortIndex = new int[mol->getAtomCount()];
611 for(int i=mol->getAtomCount();i--;)
612 SortIndex[i] = -1;
613
614 int AtomNo = 0;
615 for(molecule::const_iterator iter=mol->begin();iter!=mol->end();++iter){
616 ASSERT(SortIndex[(*iter)->getNr()]==-1,"Same SortIndex set twice");
617 SortIndex[(*iter)->getNr()] = AtomNo++;
618 }
619
620 return true;
621};
622
623
624/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
625 * \param *mol total molecule
626 * \param *Leaf fragment molecule
627 * \param &Leaflet pointer to KeySet structure
628 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
629 * \return number of atoms in fragment
630 */
631int Fragmentation::StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
632{
633 atom *FatherOfRunner = NULL;
634
635 // first create the minimal set of atoms from the KeySet
636 int size = 0;
637 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
638 FatherOfRunner = mol->FindAtom((*runner)); // find the id
639 SonList[FatherOfRunner->getNr()] = Leaf->AddCopyAtom(FatherOfRunner);
640 size++;
641 }
642 return size;
643};
644
645
646/** Creates an induced subgraph out of a fragmental key set, adding bonds and hydrogens (if treated specially).
647 * \param *out output stream for debugging messages
648 * \param *mol total molecule
649 * \param *Leaf fragment molecule
650 * \param IsAngstroem whether we have Ansgtroem or bohrradius
651 * \param **SonList list which atom of \a *Leaf is a son of which atom in \a *mol
652 */
653void Fragmentation::CreateInducedSubgraphOfFragment(molecule *mol, molecule *Leaf, atom **SonList, bool IsAngstroem)
654{
655 bool LonelyFlag = false;
656 atom *OtherFather = NULL;
657 atom *FatherOfRunner = NULL;
658
659#ifdef ADDHYDROGEN
660 molecule::const_iterator runner;
661#endif
662 // we increment the iter just before skipping the hydrogen
663 for (molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end();) {
664 LonelyFlag = true;
665 FatherOfRunner = (*iter)->father;
666 ASSERT(FatherOfRunner,"Atom without father found");
667 if (SonList[FatherOfRunner->getNr()] != NULL) { // check if this, our father, is present in list
668 // create all bonds
669 const BondList& ListOfBonds = FatherOfRunner->getListOfBonds();
670 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
671 BondRunner != ListOfBonds.end();
672 ++BondRunner) {
673 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
674// Log() << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->getNr()] << " is bound to " << *OtherFather;
675 if (SonList[OtherFather->getNr()] != NULL) {
676// Log() << Verbose(0) << ", whose son is " << *SonList[OtherFather->getNr()] << "." << endl;
677 if (OtherFather->getNr() > FatherOfRunner->getNr()) { // add bond (Nr check is for adding only one of both variants: ab, ba)
678// Log() << Verbose(3) << "Adding Bond: ";
679// Log() << Verbose(0) <<
680 Leaf->AddBond((*iter), SonList[OtherFather->getNr()], (*BondRunner)->BondDegree);
681// Log() << Verbose(0) << "." << endl;
682 //NumBonds[(*iter)->getNr()]++;
683 } else {
684// Log() << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
685 }
686 LonelyFlag = false;
687 } else {
688// Log() << Verbose(0) << ", who has no son in this fragment molecule." << endl;
689#ifdef ADDHYDROGEN
690 //Log() << Verbose(3) << "Adding Hydrogen to " << (*iter)->Name << " and a bond in between." << endl;
691 if(!Leaf->AddHydrogenReplacementAtom((*BondRunner), (*iter), FatherOfRunner, OtherFather, IsAngstroem))
692 exit(1);
693#endif
694 //NumBonds[(*iter)->getNr()] += Binder->BondDegree;
695 }
696 }
697 } else {
698 DoeLog(1) && (eLog()<< Verbose(1) << "Son " << (*iter)->getName() << " has father " << FatherOfRunner->getName() << " but its entry in SonList is " << SonList[FatherOfRunner->getNr()] << "!" << endl);
699 }
700 if ((LonelyFlag) && (Leaf->getAtomCount() > 1)) {
701 DoLog(0) && (Log() << Verbose(0) << **iter << "has got bonds only to hydrogens!" << endl);
702 }
703 ++iter;
704#ifdef ADDHYDROGEN
705 while ((iter != Leaf->end()) && ((*iter)->getType()->getAtomicNumber() == 1)){ // skip added hydrogen
706 iter++;
707 }
708#endif
709 }
710};
711
Note: See TracBrowser for help on using the repository browser.