source: src/Fragmentation/Fragmentation.cpp@ d4d7a1

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 Candidate_v1.7.0 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since d4d7a1 was d4d7a1, checked in by Frederik Heber <heber@…>, 13 years ago

SortIndex is now a map.

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