source: src/Fragmentation/Fragmentation.cpp@ 730d7a

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

New class AdaptivityMap and moved some functions from fragmentation_helpers into it.

  • Property mode set to 100644
File size: 31.0 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 std::map<int, std::pair<double,int> > *AdaptiveCriteriaList = IndexKeySetList->ScanAdaptiveFileIntoMap(path); // (Root No., (Value, Order)) !
471 if (AdaptiveCriteriaList->empty()) {
472 DoeLog(2) && (eLog()<< Verbose(2) << "Unable to parse file, incrementing all." << endl);
473 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
474 #ifdef ADDHYDROGEN
475 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
476 #endif
477 {
478 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
479 status = true;
480 }
481 }
482 }
483 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
484 std::map<double, std::pair<int,int> > *FinalRootCandidates = IndexKeySetList->ReMapAdaptiveCriteriaListToValue(AdaptiveCriteriaList, mol);
485
486 // pick the ones still below threshold and mark as to be adaptively updated
487 MarkUpdateCandidates(AtomMask, *FinalRootCandidates, Order, mol);
488
489 delete[](IndexKeySetList);
490 delete[](AdaptiveCriteriaList);
491 delete[](FinalRootCandidates);
492 } else { // global increase of Bond Order
493 for(molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
494 #ifdef ADDHYDROGEN
495 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
496 #endif
497 {
498 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
499 if ((Order != 0) && ((*iter)->AdaptiveOrder < Order)) // && ((*iter)->AdaptiveOrder < MinimumRingSize[(*iter)->getNr()]))
500 status = true;
501 }
502 }
503 if ((!Order) && (!AtomMask[mol->getAtomCount()])) // single stepping, just check
504 status = true;
505
506 if (!status) {
507 if (Order == 0)
508 DoLog(1) && (Log() << Verbose(1) << "Single stepping done." << endl);
509 else
510 DoLog(1) && (Log() << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl);
511 }
512 }
513
514 PrintAtomMask(AtomMask, mol->getAtomCount()); // for debugging
515
516 return status;
517};
518
519/** Stores pairs (Atom::Nr, Atom::AdaptiveOrder) into file.
520 * Atoms not present in the file get "-1".
521 * \param &path path to file ORDERATSITEFILE
522 * \return true - file writable, false - not writable
523 */
524bool Fragmentation::StoreOrderAtSiteFile(std::string &path)
525{
526 string line;
527 ofstream file;
528
529 line = path + ORDERATSITEFILE;
530 file.open(line.c_str());
531 DoLog(1) && (Log() << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl);
532 if (file.good()) {
533 for_each(mol->begin(),mol->end(),bind2nd(mem_fun(&atom::OutputOrder), &file));
534 file.close();
535 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
536 return true;
537 } else {
538 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line << "." << endl);
539 return false;
540 }
541};
542
543
544/** Parses pairs(Atom::Nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
545 * Atoms not present in the file get "0".
546 * \param &path path to file ORDERATSITEFILEe
547 * \return true - file found and scanned, false - file not found
548 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
549 */
550bool Fragmentation::ParseOrderAtSiteFromFile(std::string &path)
551{
552 unsigned char *OrderArray = new unsigned char[mol->getAtomCount()];
553 bool *MaxArray = new bool[mol->getAtomCount()];
554 bool status;
555 int AtomNr, value;
556 string line;
557 ifstream file;
558
559 for(int i=0;i<mol->getAtomCount();i++) {
560 OrderArray[i] = 0;
561 MaxArray[i] = false;
562 }
563
564 DoLog(1) && (Log() << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl);
565 line = path + ORDERATSITEFILE;
566 file.open(line.c_str());
567 if (file.good()) {
568 while (!file.eof()) { // parse from file
569 AtomNr = -1;
570 file >> AtomNr;
571 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
572 file >> value;
573 OrderArray[AtomNr] = value;
574 file >> value;
575 MaxArray[AtomNr] = value;
576 //Log() << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
577 }
578 }
579 file.close();
580
581 // set atom values
582 for(molecule::const_iterator iter=mol->begin();iter!=mol->end();++iter){
583 (*iter)->AdaptiveOrder = OrderArray[(*iter)->getNr()];
584 (*iter)->MaxOrder = MaxArray[(*iter)->getNr()];
585 }
586 //SetAtomValueToIndexedArray( OrderArray, &atom::getNr(), &atom::AdaptiveOrder );
587 //SetAtomValueToIndexedArray( MaxArray, &atom::getNr(), &atom::MaxOrder );
588
589 DoLog(1) && (Log() << Verbose(1) << "\t ... done." << endl);
590 status = true;
591 } else {
592 DoLog(1) && (Log() << Verbose(1) << "\t ... failed to open file " << line << "." << endl);
593 status = false;
594 }
595 delete[](OrderArray);
596 delete[](MaxArray);
597
598 DoLog(1) && (Log() << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl);
599 return status;
600};
601
602/** Create a SortIndex to map from atomic labels to the sequence in which the atoms are given in the config file.
603 * \param *out output stream for debugging
604 * \param *&SortIndex Mapping array of size molecule::AtomCount
605 * \return true - success, false - failure of SortIndex alloc
606 */
607bool Fragmentation::CreateMappingLabelsToConfigSequence(int *&SortIndex)
608{
609 if (SortIndex != NULL) {
610 DoLog(1) && (Log() << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl);
611 return false;
612 }
613 SortIndex = new int[mol->getAtomCount()];
614 for(int i=mol->getAtomCount();i--;)
615 SortIndex[i] = -1;
616
617 int AtomNo = 0;
618 for(molecule::const_iterator iter=mol->begin();iter!=mol->end();++iter){
619 ASSERT(SortIndex[(*iter)->getNr()]==-1,"Same SortIndex set twice");
620 SortIndex[(*iter)->getNr()] = AtomNo++;
621 }
622
623 return true;
624};
625
626
627/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
628 * \param *mol total molecule
629 * \param *Leaf fragment molecule
630 * \param &Leaflet pointer to KeySet structure
631 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
632 * \return number of atoms in fragment
633 */
634int Fragmentation::StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
635{
636 atom *FatherOfRunner = NULL;
637
638 // first create the minimal set of atoms from the KeySet
639 int size = 0;
640 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
641 FatherOfRunner = mol->FindAtom((*runner)); // find the id
642 SonList[FatherOfRunner->getNr()] = Leaf->AddCopyAtom(FatherOfRunner);
643 size++;
644 }
645 return size;
646};
647
648
649/** Creates an induced subgraph out of a fragmental key set, adding bonds and hydrogens (if treated specially).
650 * \param *out output stream for debugging messages
651 * \param *mol total molecule
652 * \param *Leaf fragment molecule
653 * \param IsAngstroem whether we have Ansgtroem or bohrradius
654 * \param **SonList list which atom of \a *Leaf is a son of which atom in \a *mol
655 */
656void Fragmentation::CreateInducedSubgraphOfFragment(molecule *mol, molecule *Leaf, atom **SonList, bool IsAngstroem)
657{
658 bool LonelyFlag = false;
659 atom *OtherFather = NULL;
660 atom *FatherOfRunner = NULL;
661
662#ifdef ADDHYDROGEN
663 molecule::const_iterator runner;
664#endif
665 // we increment the iter just before skipping the hydrogen
666 for (molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end();) {
667 LonelyFlag = true;
668 FatherOfRunner = (*iter)->father;
669 ASSERT(FatherOfRunner,"Atom without father found");
670 if (SonList[FatherOfRunner->getNr()] != NULL) { // check if this, our father, is present in list
671 // create all bonds
672 const BondList& ListOfBonds = FatherOfRunner->getListOfBonds();
673 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
674 BondRunner != ListOfBonds.end();
675 ++BondRunner) {
676 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
677// Log() << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->getNr()] << " is bound to " << *OtherFather;
678 if (SonList[OtherFather->getNr()] != NULL) {
679// Log() << Verbose(0) << ", whose son is " << *SonList[OtherFather->getNr()] << "." << endl;
680 if (OtherFather->getNr() > FatherOfRunner->getNr()) { // add bond (Nr check is for adding only one of both variants: ab, ba)
681// Log() << Verbose(3) << "Adding Bond: ";
682// Log() << Verbose(0) <<
683 Leaf->AddBond((*iter), SonList[OtherFather->getNr()], (*BondRunner)->BondDegree);
684// Log() << Verbose(0) << "." << endl;
685 //NumBonds[(*iter)->getNr()]++;
686 } else {
687// Log() << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
688 }
689 LonelyFlag = false;
690 } else {
691// Log() << Verbose(0) << ", who has no son in this fragment molecule." << endl;
692#ifdef ADDHYDROGEN
693 //Log() << Verbose(3) << "Adding Hydrogen to " << (*iter)->Name << " and a bond in between." << endl;
694 if(!Leaf->AddHydrogenReplacementAtom((*BondRunner), (*iter), FatherOfRunner, OtherFather, IsAngstroem))
695 exit(1);
696#endif
697 //NumBonds[(*iter)->getNr()] += Binder->BondDegree;
698 }
699 }
700 } else {
701 DoeLog(1) && (eLog()<< Verbose(1) << "Son " << (*iter)->getName() << " has father " << FatherOfRunner->getName() << " but its entry in SonList is " << SonList[FatherOfRunner->getNr()] << "!" << endl);
702 }
703 if ((LonelyFlag) && (Leaf->getAtomCount() > 1)) {
704 DoLog(0) && (Log() << Verbose(0) << **iter << "has got bonds only to hydrogens!" << endl);
705 }
706 ++iter;
707#ifdef ADDHYDROGEN
708 while ((iter != Leaf->end()) && ((*iter)->getType()->getAtomicNumber() == 1)){ // skip added hydrogen
709 iter++;
710 }
711#endif
712 }
713};
714
Note: See TracBrowser for help on using the repository browser.