source: src/Fragmentation/Fragmentation.cpp@ b9401e

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 Candidate_v1.7.0 Candidate_v1.7.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 b9401e was b9401e, checked in by Frederik Heber <heber@…>, 13 years ago

Removed Correcting bond degree in Fragmentation::FragmentMolecule().

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