source: src/Fragmentation/Fragmentation.cpp@ 06f41f3

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

CheckAgainstAdjacencyFile now works on given vector of atomids.

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