source: src/Fragmentation/Fragmentation.cpp@ ba94c5

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

Removed modules graph.[ch]pp.

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