source: src/Fragmentation/Fragmentation.cpp@ 9511c7

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

CheckAgainstAdjacencyFile is now instantiated in FragmentationAction not in Fragmentation.

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