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

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

Removed molecule::doCountAtom() and added molecule::doCountNoNonHydrogen().

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