source: src/Fragmentation/Fragmentation.cpp@ 50e4e5

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 50e4e5 was 07a47e, checked in by Frederik Heber <heber@…>, 13 years ago

Replaced enable/disable-hydrogen by internal switch.

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