source: src/Fragmentation/Fragmentation.cpp@ 851be8

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

Moved functions that deal with adaptivity from fragmentation_helpers into AdaptivityMap.

  • 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/AdaptivityMap.hpp"
31#include "Fragmentation/fragmentation_helpers.hpp"
32#include "Fragmentation/Graph.hpp"
33#include "Fragmentation/KeySet.hpp"
34#include "Fragmentation/PowerSetGenerator.hpp"
35#include "Fragmentation/UniqueFragments.hpp"
36#include "Graph/BondGraph.hpp"
37#include "Graph/CheckAgainstAdjacencyFile.hpp"
38#include "molecule.hpp"
39#include "MoleculeLeafClass.hpp"
40#include "MoleculeListClass.hpp"
41#include "World.hpp"
42
43
44/** Constructor of class Fragmentation.
45 *
46 */
47Fragmentation::Fragmentation(molecule *_mol) :
48 mol(_mol)
49{}
50
51/** Destructor of class Fragmentation.
52 *
53 */
54Fragmentation::~Fragmentation()
55{}
56
57
58/** Performs a many-body bond order analysis for a given bond order.
59 * -# parses adjacency, keysets and orderatsite files
60 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
61 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
62y contribution", and that's why this consciously not done in the following loop)
63 * -# in a loop over all subgraphs
64 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
65 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
66 * -# combines the generated molecule lists from all subgraphs
67 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
68 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
69 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
70 * subgraph in the MoleculeListClass.
71 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
72 * \param &prefix path and prefix of the bond order configs to be written
73 * \param &DFS contains bond structure analysis data
74 * \return 1 - continue, 2 - stop (no fragmentation occured)
75 */
76int Fragmentation::FragmentMolecule(int Order, std::string &prefix, DepthFirstSearchAnalysis &DFS)
77{
78 MoleculeListClass *BondFragments = NULL;
79 int FragmentCounter;
80 MoleculeLeafClass *MolecularWalker = NULL;
81 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
82 fstream File;
83 bool FragmentationToDo = true;
84 bool CheckOrder = false;
85 Graph **FragmentList = NULL;
86 Graph TotalGraph; // graph with all keysets however local numbers
87 int TotalNumberOfKeySets = 0;
88 atom ***ListOfLocalAtoms = NULL;
89 bool *AtomMask = NULL;
90
91 DoLog(0) && (Log() << Verbose(0) << endl);
92#ifdef ADDHYDROGEN
93 DoLog(0) && (Log() << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl);
94#else
95 DoLog(0) && (Log() << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl);
96#endif
97
98 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
99
100 // ===== 1. Check whether bond structure is same as stored in files ====
101
102 // === compare it with adjacency file ===
103 {
104 std::ifstream File;
105 std::string filename;
106 filename = prefix + ADJACENCYFILE;
107 File.open(filename.c_str(), ios::out);
108 DoLog(1) && (Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl);
109
110 CheckAgainstAdjacencyFile FileChecker(World::getInstance().beginAtomSelection(), World::getInstance().endAtomSelection());
111 FragmentationToDo = FragmentationToDo && FileChecker(File);
112 }
113
114 // === reset bond degree and perform CorrectBondDegree ===
115 for(World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
116 iter != World::getInstance().moleculeEnd();
117 ++iter) {
118 // correct bond degree
119 World::AtomComposite Set = (*iter)->getAtomSet();
120 World::getInstance().getBondGraph()->CorrectBondDegree(Set);
121 }
122
123 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
124 // NOTE: We assume here that DFS has been performed and molecule structure is current.
125 Subgraphs = DFS.getMoleculeStructure();
126
127 // ===== 3. if structure still valid, parse key set file and others =====
128 Graph ParsedFragmentList;
129 FragmentationToDo = FragmentationToDo && ParsedFragmentList.ParseKeySetFile(prefix);
130
131 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
132 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(prefix);
133
134 // =================================== Begin of FRAGMENTATION ===============================
135 // ===== 6a. assign each keyset to its respective subgraph =====
136 const int MolCount = World::getInstance().numMolecules();
137 ListOfLocalAtoms = new atom **[MolCount];
138 for (int i=0;i<MolCount;i++)
139 ListOfLocalAtoms[i] = NULL;
140 FragmentCounter = 0;
141 Subgraphs->next->AssignKeySetsToFragment(mol, &ParsedFragmentList, ListOfLocalAtoms, FragmentList, FragmentCounter, true);
142 delete[](ListOfLocalAtoms);
143
144 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
145 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
146 AtomMask = new bool[mol->getAtomCount()+1];
147 AtomMask[mol->getAtomCount()] = false;
148 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
149 while ((CheckOrder = CheckOrderAtSite(AtomMask, &ParsedFragmentList, Order, prefix))) {
150 FragmentationToDo = FragmentationToDo || CheckOrder;
151 AtomMask[mol->getAtomCount()] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
152 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
153 Subgraphs->next->FillRootStackForSubgraphs(RootStack, AtomMask, (FragmentCounter = 0));
154
155 // ===== 7. fill the bond fragment list =====
156 FragmentCounter = 0;
157 MolecularWalker = Subgraphs;
158 while (MolecularWalker->next != NULL) {
159 MolecularWalker = MolecularWalker->next;
160 DoLog(1) && (Log() << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl);
161 if (MolecularWalker->Leaf->hasBondStructure()) {
162 // call BOSSANOVA method
163 DoLog(0) && (Log() << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl);
164 FragmentBOSSANOVA(MolecularWalker->Leaf, FragmentList[FragmentCounter], RootStack[FragmentCounter]);
165 } else {
166 DoeLog(1) && (eLog()<< Verbose(1) << "Subgraph " << MolecularWalker << " has no atoms!" << endl);
167 }
168 FragmentCounter++; // next fragment list
169 }
170 }
171 DoLog(2) && (Log() << Verbose(2) << "CheckOrder is " << CheckOrder << "." << endl);
172 delete[](RootStack);
173 delete[](AtomMask);
174
175 // ==================================== End of FRAGMENTATION ============================================
176
177 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
178 Subgraphs->next->TranslateIndicesToGlobalIDs(FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
179
180 // free subgraph memory again
181 FragmentCounter = 0;
182 while (Subgraphs != NULL) {
183 // remove entry in fragment list
184 // remove subgraph fragment
185 MolecularWalker = Subgraphs->next;
186 Subgraphs->Leaf = NULL;
187 delete(Subgraphs);
188 Subgraphs = MolecularWalker;
189 }
190 // free fragment list
191 for (int i=0; i< FragmentCounter; ++i )
192 delete(FragmentList[i]);
193 delete[](FragmentList);
194
195 DoLog(0) && (Log() << Verbose(0) << FragmentCounter << " subgraph fragments have been removed." << std::endl);
196
197 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
198 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
199 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
200 BondFragments = new MoleculeListClass(World::getPointer());
201 int k=0;
202 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
203 KeySet test = (*runner).first;
204 DoLog(0) && (Log() << Verbose(0) << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl);
205 BondFragments->insert(StoreFragmentFromKeySet(test, World::getInstance().getConfig()));
206 k++;
207 }
208 DoLog(0) && (Log() << Verbose(0) << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl);
209
210 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
211 if (BondFragments->ListOfMolecules.size() != 0) {
212 // create the SortIndex from BFS labels to order in the config file
213 int *SortIndex = NULL;
214 CreateMappingLabelsToConfigSequence(SortIndex);
215
216 DoLog(1) && (Log() << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl);
217 if (BondFragments->OutputConfigForListOfFragments(prefix, SortIndex))
218 DoLog(1) && (Log() << Verbose(1) << "All configs written." << endl);
219 else
220 DoLog(1) && (Log() << Verbose(1) << "Some config writing failed." << endl);
221
222 // store force index reference file
223 BondFragments->StoreForcesFile(prefix, SortIndex);
224
225 // store keysets file
226 TotalGraph.StoreKeySetFile(prefix);
227
228 {
229 // store Adjacency file
230 std::string filename = prefix + ADJACENCYFILE;
231 mol->StoreAdjacencyToFile(filename);
232 }
233
234 // store Hydrogen saturation correction file
235 BondFragments->AddHydrogenCorrection(prefix);
236
237 // store adaptive orders into file
238 StoreOrderAtSiteFile(prefix);
239
240 // restore orbital and Stop values
241 //CalculateOrbitals(*configuration);
242
243 // free memory for bond part
244 DoLog(1) && (Log() << Verbose(1) << "Freeing bond memory" << endl);
245 delete[](SortIndex);
246 } else {
247 DoLog(1) && (Log() << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl);
248 }
249 // remove all create molecules again from the World including their atoms
250 for (MoleculeList::iterator iter = BondFragments->ListOfMolecules.begin();
251 !BondFragments->ListOfMolecules.empty();
252 iter = BondFragments->ListOfMolecules.begin()) {
253 // remove copied atoms and molecule again
254 molecule *mol = *iter;
255 mol->removeAtomsinMolecule();
256 World::getInstance().destroyMolecule(mol);
257 BondFragments->ListOfMolecules.erase(iter);
258 }
259 delete(BondFragments);
260 DoLog(0) && (Log() << Verbose(0) << "End of bond fragmentation." << endl);
261
262 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
263};
264
265
266/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
267 * -# constructs a complete keyset of the molecule
268 * -# In a loop over all possible roots from the given rootstack
269 * -# increases order of root site
270 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
271 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
272as the restricted one and each site in the set as the root)
273 * -# these are merged into a fragment list of keysets
274 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
275 * Important only is that we create all fragments, it is not important if we create them more than once
276 * as these copies are filtered out via use of the hash table (KeySet).
277 * \param *out output stream for debugging
278 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
279 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
280 * \return pointer to Graph list
281 */
282void Fragmentation::FragmentBOSSANOVA(molecule *mol, Graph *&FragmentList, KeyStack &RootStack)
283{
284 Graph ***FragmentLowerOrdersList = NULL;
285 int NumLevels = 0;
286 int NumMolecules = 0;
287 int TotalNumMolecules = 0;
288 int *NumMoleculesOfOrder = NULL;
289 int Order = 0;
290 int UpgradeCount = RootStack.size();
291 KeyStack FragmentRootStack;
292 int RootKeyNr = 0;
293 int RootNr = 0;
294 UniqueFragments FragmentSearch;
295
296 DoLog(0) && (Log() << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl);
297
298 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
299 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
300 NumMoleculesOfOrder = new int[UpgradeCount];
301 FragmentLowerOrdersList = new Graph**[UpgradeCount];
302
303 for(int i=0;i<UpgradeCount;i++) {
304 NumMoleculesOfOrder[i] = 0;
305 FragmentLowerOrdersList[i] = NULL;
306 }
307
308 FragmentSearch.Init(mol->FindAtom(RootKeyNr));
309
310 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
311 KeySet CompleteMolecule;
312 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
313 CompleteMolecule.insert((*iter)->GetTrueFather()->getNr());
314 }
315
316 // 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
317 // 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),
318 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
319 // 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)
320 RootNr = 0; // counts through the roots in RootStack
321 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
322 RootKeyNr = RootStack.front();
323 RootStack.pop_front();
324 atom *Walker = mol->FindAtom(RootKeyNr);
325 // check cyclic lengths
326 //if ((MinimumRingSize[Walker->GetTrueFather()->getNr()] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->getNr()])) {
327 // 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;
328 //} else
329 {
330 // increase adaptive order by one
331 Walker->GetTrueFather()->AdaptiveOrder++;
332 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
333
334 // initialise Order-dependent entries of UniqueFragments structure
335 class PowerSetGenerator PSG(&FragmentSearch, Walker->AdaptiveOrder);
336
337 // allocate memory for all lower level orders in this 1D-array of ptrs
338 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
339 FragmentLowerOrdersList[RootNr] = new Graph*[NumLevels];
340 for (int i=0;i<NumLevels;i++)
341 FragmentLowerOrdersList[RootNr][i] = NULL;
342
343 // create top order where nothing is reduced
344 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
345 DoLog(0) && (Log() << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl); // , NumLevels is " << NumLevels << "
346
347 // Create list of Graphs of current Bond Order (i.e. F_{ij})
348 FragmentLowerOrdersList[RootNr][0] = new Graph;
349 FragmentSearch.PrepareForPowersetGeneration(1., FragmentLowerOrdersList[RootNr][0], Walker);
350 NumMoleculesOfOrder[RootNr] = PSG(CompleteMolecule);
351
352 // output resulting number
353 DoLog(1) && (Log() << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl);
354 if (NumMoleculesOfOrder[RootNr] != 0) {
355 NumMolecules = 0;
356 } else {
357 Walker->GetTrueFather()->MaxOrder = true;
358 }
359 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
360 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
361 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
362// Log() << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
363 RootStack.push_back(RootKeyNr); // put back on stack
364 RootNr++;
365 }
366 }
367 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
368 DoLog(1) && (Log() << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl);
369 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
370
371 // cleanup FragmentSearch structure
372 FragmentSearch.Cleanup();
373
374 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
375 // 5433222211111111
376 // 43221111
377 // 3211
378 // 21
379 // 1
380
381 // Subsequently, we combine all into a single list (FragmentList)
382 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, mol);
383 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, mol);
384 delete[](NumMoleculesOfOrder);
385
386 DoLog(0) && (Log() << Verbose(0) << "End of FragmentBOSSANOVA." << endl);
387};
388
389/** Stores a fragment from \a KeySet into \a molecule.
390 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
391 * molecule and adds missing hydrogen where bonds were cut.
392 * \param *out output stream for debugging messages
393 * \param &Leaflet pointer to KeySet structure
394 * \param IsAngstroem whether we have Ansgtroem or bohrradius
395 * \return pointer to constructed molecule
396 */
397molecule * Fragmentation::StoreFragmentFromKeySet(KeySet &Leaflet, bool IsAngstroem)
398{
399 atom **SonList = new atom*[mol->getAtomCount()];
400 molecule *Leaf = World::getInstance().createMolecule();
401
402 for(int i=0;i<mol->getAtomCount();i++)
403 SonList[i] = NULL;
404
405// Log() << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
406 StoreFragmentFromKeySet_Init(mol, Leaf, Leaflet, SonList);
407 // create the bonds between all: Make it an induced subgraph and add hydrogen
408// Log() << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
409 CreateInducedSubgraphOfFragment(mol, Leaf, SonList, IsAngstroem);
410
411 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
412 delete[](SonList);
413// Log() << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
414 return Leaf;
415};
416
417
418/** Estimates by educated guessing (using upper limit) the expected number of fragments.
419 * The upper limit is
420 * \f[
421 * n = N \cdot C^k
422 * \f]
423 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
424 * \param *out output stream for debugging
425 * \param order bond order k
426 * \return number n of fragments
427 */
428int Fragmentation::GuesstimateFragmentCount(int order)
429{
430 size_t c = 0;
431 int FragmentCount;
432 // get maximum bond degree
433 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
434 const BondList& ListOfBonds = (*iter)->getListOfBonds();
435 c = (ListOfBonds.size() > c) ? ListOfBonds.size() : c;
436 }
437 FragmentCount = mol->NoNonHydrogen*(1 << (c*order));
438 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);
439 return FragmentCount;
440};
441
442
443/** Checks whether the OrderAtSite is still below \a Order at some site.
444 * \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
445 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
446 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
447 * \param path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
448 * \return true - needs further fragmentation, false - does not need fragmentation
449 */
450bool Fragmentation::CheckOrderAtSite(bool *AtomMask, Graph *GlobalKeySetList, int Order, std::string path)
451{
452 bool status = false;
453
454 // initialize mask list
455 for(int i=mol->getAtomCount();i--;)
456 AtomMask[i] = false;
457
458 if (Order < 0) { // adaptive increase of BondOrder per site
459 if (AtomMask[mol->getAtomCount()] == true) // break after one step
460 return false;
461
462 // transmorph graph keyset list into indexed KeySetList
463 if (GlobalKeySetList == NULL) {
464 DoeLog(1) && (eLog()<< Verbose(1) << "Given global key set list (graph) is NULL!" << endl);
465 return false;
466 }
467 AdaptivityMap * IndexKeySetList = GlobalKeySetList->GraphToAdaptivityMap();
468
469 // parse the EnergyPerFragment file
470 IndexKeySetList->ScanAdaptiveFileIntoMap(path); // (Root No., (Value, Order)) !
471 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
472 IndexKeySetList->ReMapAdaptiveCriteriaListToValue(mol);
473
474 // pick the ones still below threshold and mark as to be adaptively updated
475 if (IndexKeySetList->IsAdaptiveCriteriaListEmpty()) {
476 DoeLog(2) && (eLog()<< Verbose(2) << "Unable to parse file, incrementing all." << endl);
477 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
478 #ifdef ADDHYDROGEN
479 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
480 #endif
481 {
482 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
483 status = true;
484 }
485 }
486 } else {
487 IndexKeySetList->MarkUpdateCandidates(AtomMask, Order, mol);
488 }
489
490 delete[](IndexKeySetList);
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.