source: src/Fragmentation/Fragmentation.cpp@ f96874

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 Candidate_v1.7.0 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 f96874 was f96874, checked in by Frederik Heber <heber@…>, 13 years ago

AtomMask is now a set, inherited into own class.

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