source: src/Fragmentation/Fragmentation.cpp@ 75363b

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

Extracted functions from fragmentation_helpers and placed them in KeySet or Graph class.

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