source: src/Fragmentation/Fragmentation.cpp@ 2a0eb0

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 2a0eb0 was 2a0eb0, checked in by Frederik Heber <heber@…>, 12 years ago

FragmentationAction now works on selected atoms, split into molecules.

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