source: src/Fragmentation/Fragmentation.cpp@ 8b58ac

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 8b58ac was 94d5ac6, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: As we use GSL internally, we are as of now required to use GPL v2 license.

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