source: src/Fragmentation/Fragmentation.cpp@ f73351

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

FIX: Fixed new copyright line since start of 2013 in CodeChecks test.

  • we must look for either Uni Bonn or myself.
  • added second copyright line since from 1st of Jan 2013 I am not employed by University of Bonn anymore, hence changes to the code are my own copyright.
  • Property mode set to 100644
File size: 23.7 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.
[5aaa43]5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
[94d5ac6]6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
[bcf653]22 */
23
[cee0b57]24/*
[246e13]25 * Fragmentation.cpp
[cee0b57]26 *
[246e13]27 * Created on: Oct 18, 2011
[cee0b57]28 * Author: heber
29 */
30
[bf3817]31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
[ad011c]35#include "CodePatterns/MemDebug.hpp"
[112b09]36
[246e13]37#include "Fragmentation.hpp"
38
39#include "CodePatterns/Assert.hpp"
[47d041]40#include "CodePatterns/Info.hpp"
[246e13]41#include "CodePatterns/Log.hpp"
[49e1ae]42
[6f0841]43#include "Atom/atom.hpp"
[129204]44#include "Bond/bond.hpp"
[8e1f901]45#include "Descriptors/MoleculeDescriptor.hpp"
[3bdb6d]46#include "Element/element.hpp"
[ba1823]47#include "Element/periodentafel.hpp"
[730d7a]48#include "Fragmentation/AdaptivityMap.hpp"
[f96874]49#include "Fragmentation/AtomMask.hpp"
[ba1823]50#include "Fragmentation/fragmentation_helpers.hpp"
[dadc74]51#include "Fragmentation/Graph.hpp"
[06f41f3]52#include "Fragmentation/helpers.hpp"
[f0674a]53#include "Fragmentation/KeySet.hpp"
[f67817f]54#include "Fragmentation/PowerSetGenerator.hpp"
[a03d25]55#include "Fragmentation/UniqueFragments.hpp"
[129204]56#include "Graph/BondGraph.hpp"
[0fad93]57#include "Graph/AdjacencyList.hpp"
[6d551c]58#include "Graph/ListOfLocalAtoms.hpp"
[cee0b57]59#include "molecule.hpp"
[b34306]60#include "World.hpp"
[cee0b57]61
62
[246e13]63/** Constructor of class Fragmentation.
64 *
[07a47e]65 * \param _mol molecule for internal use (looking up atoms)
[9511c7]66 * \param _FileChecker instance contains adjacency parsed from elsewhere
[9291d04]67 * \param _treatment whether to treat hydrogen special and saturate dangling bonds or not
[cee0b57]68 */
[9291d04]69Fragmentation::Fragmentation(molecule *_mol, AdjacencyList &_FileChecker, const enum HydrogenTreatment _treatment) :
[07a47e]70 mol(_mol),
[9291d04]71 treatment(_treatment),
[9511c7]72 FileChecker(_FileChecker)
[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.
[91207d]94 * \param atomids atomic ids (local to Fragmentation::mol) 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 */
[e71325]100int Fragmentation::FragmentMolecule(
101 const std::vector<atomId_t> &atomids,
102 int Order,
103 const std::string &prefix,
[bfbd4a]104 DepthFirstSearchAnalysis &DFS,
105 const Graph &ParsedFragmentList)
[cee0b57]106{
[339910]107 std::fstream File;
[cee0b57]108 bool CheckOrder = false;
109 int TotalNumberOfKeySets = 0;
110
[339910]111 LOG(0, std::endl);
[9291d04]112 switch (treatment) {
113 case ExcludeHydrogen:
[8ac66b4]114 LOG(1, "INFO: I will treat hydrogen special.");
[07a47e]115 break;
[9291d04]116 case IncludeHydrogen:
[8ac66b4]117 LOG(1, "INFO: Hydrogen is treated just like the rest of the lot.");
[07a47e]118 break;
119 default:
[9291d04]120 ASSERT(0, "Fragmentation::FragmentMolecule() - there is a HydrogenTreatment setting which I have no idea about.");
[07a47e]121 break;
122 }
[cee0b57]123
124 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
[3aa8a5]125 bool FragmentationToDo = true;
[cee0b57]126
127 // ===== 1. Check whether bond structure is same as stored in files ====
128
129 // === compare it with adjacency file ===
[13a953]130 {
[06f41f3]131 const std::vector<atomId_t> globalids = getGlobalIdsFromLocalIds(*mol, atomids);
[3aa8a5]132 AdjacencyList WorldAdjacency(globalids);
133 FragmentationToDo = FragmentationToDo && (FileChecker > WorldAdjacency);
[13a953]134 }
[cee0b57]135
[91207d]136 // ===== 2. create AtomMask that takes Saturation condition into account
137 AtomMask_t AtomMask(atomids);
138 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
139 // remove in hydrogen and we do saturate
[9291d04]140 if ((treatment == ExcludeHydrogen) && ((*iter)->getType()->getAtomicNumber() == 1)) // skip hydrogen
[91207d]141 AtomMask.setFalse((*iter)->getNr());
142 }
143
[cee0b57]144 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
[2a0eb0]145 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(atomids, prefix);
[cee0b57]146
147 // =================================== Begin of FRAGMENTATION ===============================
148 // ===== 6a. assign each keyset to its respective subgraph =====
[339910]149 ListOfLocalAtoms_t ListOfLocalAtoms;
150 Graph FragmentList;
151 AssignKeySetsToFragment(ParsedFragmentList, ListOfLocalAtoms, FragmentList, true);
[cee0b57]152
153 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
[339910]154 KeyStack RootStack;
[cee0b57]155 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
[f96874]156 bool LoopDoneAlready = false;
[339910]157 while ((CheckOrder = CheckOrderAtSite(AtomMask, ParsedFragmentList, Order, prefix, LoopDoneAlready))) {
[cee0b57]158 FragmentationToDo = FragmentationToDo || CheckOrder;
[f96874]159 LoopDoneAlready = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
[cee0b57]160 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
[339910]161 FillRootStackForSubgraphs(RootStack, AtomMask);
162
163 // call BOSSANOVA method
164 FragmentBOSSANOVA(mol, FragmentList, RootStack);
[cee0b57]165 }
[8ac66b4]166 LOG(3, "DEBUG: CheckOrder is " << CheckOrder << ".");
[cee0b57]167
168 // ==================================== End of FRAGMENTATION ============================================
169
[5a4955]170 // if hydrogen is not treated special, we may have single hydrogens and other
171 // fragments which are note single-determinant. These need to be removed
172 if (treatment == IncludeHydrogen) {
173 // remove all single atom fragments from FragmentList
174 Graph::iterator iter = FragmentList.begin();
175 while ( iter != FragmentList.end()) {
176 if ((*iter).first.size() == 1) {
177 LOG(1, "INFO: Removing KeySet " << (*iter).first << " as is not single-determinant.");
178 Graph::iterator eraseiter = iter++;
179 FragmentList.erase(eraseiter);
180 } else
181 ++iter;
182 }
183 }
184
[cee0b57]185 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
[339910]186 TranslateIndicesToGlobalIDs(FragmentList, TotalNumberOfKeySets, TotalGraph);
[00b59d5]187
[ca8bea]188 LOG(1, "STATUS: We have created " << TotalGraph.size() << " fragments.");
[cee0b57]189
[b4f72c]190
[ca8bea]191 // store adaptive orders into file
192 StoreOrderAtSiteFile(prefix);
[cee0b57]193
194 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
195};
196
197
[246e13]198/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
199 * -# constructs a complete keyset of the molecule
200 * -# In a loop over all possible roots from the given rootstack
201 * -# increases order of root site
202 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
203 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
204as the restricted one and each site in the set as the root)
205 * -# these are merged into a fragment list of keysets
206 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
207 * Important only is that we create all fragments, it is not important if we create them more than once
208 * as these copies are filtered out via use of the hash table (KeySet).
209 * \param *out output stream for debugging
210 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
211 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
212 * \return pointer to Graph list
[cee0b57]213 */
[339910]214void Fragmentation::FragmentBOSSANOVA(molecule *mol, Graph &FragmentList, KeyStack &RootStack)
[cee0b57]215{
[339910]216 Info FunctionInfo(__func__);
[d760bb]217 std::vector<Graph*> *FragmentLowerOrdersList = NULL;
[246e13]218 int NumLevels = 0;
219 int NumMolecules = 0;
220 int TotalNumMolecules = 0;
221 int *NumMoleculesOfOrder = NULL;
222 int Order = 0;
223 int UpgradeCount = RootStack.size();
224 KeyStack FragmentRootStack;
225 int RootKeyNr = 0;
226 int RootNr = 0;
[cee0b57]227
[246e13]228 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
229 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
230 NumMoleculesOfOrder = new int[UpgradeCount];
[d760bb]231 FragmentLowerOrdersList = new std::vector<Graph*>[UpgradeCount];
[cee0b57]232
[d760bb]233 for(int i=0;i<UpgradeCount;i++)
[246e13]234 NumMoleculesOfOrder[i] = 0;
[5034e1]235
[246e13]236 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
237 KeySet CompleteMolecule;
238 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
239 CompleteMolecule.insert((*iter)->GetTrueFather()->getNr());
[cee0b57]240 }
241
[246e13]242 // 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
243 // 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),
244 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
245 // 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)
246 RootNr = 0; // counts through the roots in RootStack
247 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
248 RootKeyNr = RootStack.front();
249 RootStack.pop_front();
250 atom *Walker = mol->FindAtom(RootKeyNr);
251 // check cyclic lengths
252 //if ((MinimumRingSize[Walker->GetTrueFather()->getNr()] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->getNr()])) {
[47d041]253 // 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]254 //} else
255 {
[d760bb]256 // set adaptive order to desired max order
257 Walker->GetTrueFather()->AdaptiveOrder = Walker->GetTrueFather()->MaxOrder;
[246e13]258 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
[cee0b57]259
[d760bb]260 // allocate memory for all lower level orders
261 NumLevels = Order;
262 FragmentLowerOrdersList[RootNr].resize(NumLevels, NULL);
263 for( size_t i=0;i<NumLevels;++i)
264 FragmentLowerOrdersList[RootNr][i] = new Graph;
[cee0b57]265
[d760bb]266 // initialise Order-dependent entries of UniqueFragments structure
267 UniqueFragments FragmentSearch(1., FragmentLowerOrdersList[RootNr], Walker);
268 PowerSetGenerator PSG(&FragmentSearch, Walker->AdaptiveOrder);
[246e13]269
270 // create top order where nothing is reduced
[47d041]271 LOG(0, "==============================================================================================================");
[d760bb]272 LOG(0, "Creating KeySets up till Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining."); // , NumLevels is " << NumLevels << "
[246e13]273
274 // Create list of Graphs of current Bond Order (i.e. F_{ij})
[9291d04]275 NumMoleculesOfOrder[RootNr] = PSG(CompleteMolecule, treatment);
[246e13]276
277 // output resulting number
[8ac66b4]278 LOG(1, "INFO: Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << ".");
[246e13]279 if (NumMoleculesOfOrder[RootNr] != 0) {
280 NumMolecules = 0;
281 }
282 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
283 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
284 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
[47d041]285// LOG(1, "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << ".");
[246e13]286 RootStack.push_back(RootKeyNr); // put back on stack
287 RootNr++;
288 }
289 }
[47d041]290 LOG(0, "==============================================================================================================");
[8ac66b4]291 LOG(0, "\tTotal number of resulting fragments is: " << TotalNumMolecules << ".");
[47d041]292 LOG(0, "==============================================================================================================");
[246e13]293
294 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
295 // 5433222211111111
296 // 43221111
297 // 3211
298 // 21
299 // 1
300
301 // Subsequently, we combine all into a single list (FragmentList)
302 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, mol);
303 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, mol);
304 delete[](NumMoleculesOfOrder);
305};
306
307/** Estimates by educated guessing (using upper limit) the expected number of fragments.
308 * The upper limit is
309 * \f[
310 * n = N \cdot C^k
311 * \f]
312 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
313 * \param *out output stream for debugging
314 * \param order bond order k
315 * \return number n of fragments
316 */
317int Fragmentation::GuesstimateFragmentCount(int order)
318{
319 size_t c = 0;
320 int FragmentCount;
321 // get maximum bond degree
322 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
323 const BondList& ListOfBonds = (*iter)->getListOfBonds();
324 c = (ListOfBonds.size() > c) ? ListOfBonds.size() : c;
325 }
[9291d04]326 FragmentCount = (treatment == ExcludeHydrogen ? mol->getNoNonHydrogen() : mol->getAtomCount()) *(1 << (c*order));
[8ac66b4]327 LOG(1, "INFO: Upper limit for this subgraph is " << FragmentCount << " for "
[e791dc]328 << mol->getNoNonHydrogen() << " non-H atoms with maximum bond degree of " << c << ".");
[246e13]329 return FragmentCount;
330};
331
332
333/** Checks whether the OrderAtSite is still below \a Order at some site.
[f96874]334 * \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]335 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
336 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
337 * \param path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
[f96874]338 * \param LoopDoneAlready indicate whether we have done a fragmentation loop already
[246e13]339 * \return true - needs further fragmentation, false - does not need fragmentation
340 */
[e71325]341bool Fragmentation::CheckOrderAtSite(AtomMask_t &AtomMask, const Graph &GlobalKeySetList, int Order, const std::string &path, bool LoopDoneAlready)
[246e13]342{
343 bool status = false;
344
345 if (Order < 0) { // adaptive increase of BondOrder per site
[f96874]346 if (LoopDoneAlready) // break after one step
[246e13]347 return false;
348
349 // transmorph graph keyset list into indexed KeySetList
[339910]350 AdaptivityMap * IndexKeySetList = GlobalKeySetList.GraphToAdaptivityMap();
[246e13]351
352 // parse the EnergyPerFragment file
[851be8]353 IndexKeySetList->ScanAdaptiveFileIntoMap(path); // (Root No., (Value, Order)) !
354 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
355 IndexKeySetList->ReMapAdaptiveCriteriaListToValue(mol);
356
357 // pick the ones still below threshold and mark as to be adaptively updated
358 if (IndexKeySetList->IsAdaptiveCriteriaListEmpty()) {
[47d041]359 ELOG(2, "Unable to parse file, incrementing all.");
[91207d]360 status = true;
[851be8]361 } else {
[91207d]362 // mark as false all sites that are below threshold already
363 status = IndexKeySetList->MarkUpdateCandidates(AtomMask, Order, mol);
[246e13]364 }
365
366 delete[](IndexKeySetList);
367 } else { // global increase of Bond Order
[d760bb]368 for(molecule::iterator iter = mol->begin(); iter != mol->end(); ++iter) {
[863456]369 atom * const Walker = *iter;
370 if (AtomMask.isTrue(Walker->getNr())) { // skip masked out
371 Walker->MaxOrder = (Order != 0 ? Order : Walker->MaxOrder+1);
[91207d]372 // remove all that have reached desired order
[863456]373 if (Walker->AdaptiveOrder >= Walker->MaxOrder) // && (Walker->AdaptiveOrder < MinimumRingSize[Walker->getNr()]))
374 AtomMask.setFalse(Walker->getNr());
[91207d]375 else
[246e13]376 status = true;
377 }
378 }
[f96874]379 if ((!Order) && (!LoopDoneAlready)) // single stepping, just check
[246e13]380 status = true;
381
382 if (!status) {
383 if (Order == 0)
[8ac66b4]384 LOG(1, "INFO: Single stepping done.");
[246e13]385 else
[8ac66b4]386 LOG(1, "INFO: Order at every site is already equal or above desired order " << Order << ".");
[246e13]387 }
388 }
389
[863456]390 PrintAtomMask(AtomMask, *(--mol->getAtomIds().end())); // for debugging
[246e13]391
392 return status;
393};
394
395/** Stores pairs (Atom::Nr, Atom::AdaptiveOrder) into file.
396 * Atoms not present in the file get "-1".
397 * \param &path path to file ORDERATSITEFILE
398 * \return true - file writable, false - not writable
399 */
[e71325]400bool Fragmentation::StoreOrderAtSiteFile(const std::string &path)
[246e13]401{
402 string line;
403 ofstream file;
404
405 line = path + ORDERATSITEFILE;
406 file.open(line.c_str());
[8ac66b4]407 std::stringstream output;
408 output << "INFO: Writing OrderAtSite " << ORDERATSITEFILE << " ... ";
[246e13]409 if (file.good()) {
410 for_each(mol->begin(),mol->end(),bind2nd(mem_fun(&atom::OutputOrder), &file));
411 file.close();
[8ac66b4]412 output << "done.";
[246e13]413 return true;
414 } else {
[8ac66b4]415 output << "failed to open file " << line << ".";
[246e13]416 return false;
417 }
[8ac66b4]418 LOG(1, output.str());
[246e13]419};
420
421
422/** Parses pairs(Atom::Nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
423 * Atoms not present in the file get "0".
[2a0eb0]424 * \param atomids atoms to fragment, used in AtomMask
[246e13]425 * \param &path path to file ORDERATSITEFILEe
426 * \return true - file found and scanned, false - file not found
427 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
428 */
[e71325]429bool Fragmentation::ParseOrderAtSiteFromFile(const std::vector<atomId_t> &atomids, const std::string &path)
[246e13]430{
[8ac66b4]431// Info FunctionInfo(__func__);
[ed9da4]432 typedef unsigned char order_t;
433 typedef std::map<atomId_t, order_t> OrderArray_t;
434 OrderArray_t OrderArray;
[2a0eb0]435 AtomMask_t MaxArray(atomids);
[246e13]436 bool status;
437 int AtomNr, value;
438 string line;
439 ifstream file;
440
441 line = path + ORDERATSITEFILE;
442 file.open(line.c_str());
443 if (file.good()) {
444 while (!file.eof()) { // parse from file
445 AtomNr = -1;
446 file >> AtomNr;
447 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
448 file >> value;
449 OrderArray[AtomNr] = value;
450 file >> value;
[ed9da4]451 MaxArray.setValue(AtomNr, (bool)value);
[47d041]452 //LOG(2, "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << ".");
[246e13]453 }
454 }
455 file.close();
456
457 // set atom values
[59fff1]458 for(molecule::iterator iter=mol->begin();iter!=mol->end();++iter){
[246e13]459 (*iter)->AdaptiveOrder = OrderArray[(*iter)->getNr()];
[d760bb]460 (*iter)->MaxOrder = OrderArray[(*iter)->getNr()]; //MaxArray.isTrue((*iter)->getNr());
[246e13]461 }
462 //SetAtomValueToIndexedArray( OrderArray, &atom::getNr(), &atom::AdaptiveOrder );
463 //SetAtomValueToIndexedArray( MaxArray, &atom::getNr(), &atom::MaxOrder );
464
465 status = true;
466 } else {
[8ac66b4]467 ELOG(1, "Failed to open OrdersAtSite file " << line << ".");
[246e13]468 status = false;
469 }
470
471 return status;
472};
473
[339910]474/** Fills the root stack for sites to be used as root in fragmentation depending on order or adaptivity criteria
475 * Again, as in \sa FillBondStructureFromReference steps recursively through each Leaf in this chain list of molecule's.
476 * \param &RootStack stack to be filled
477 * \param AtomMask defines true/false per global Atom::Nr to mask in/out each nuclear site
478 * \return true - stack is non-empty, fragmentation necessary, false - stack is empty, no more sites to update
479 */
480void Fragmentation::FillRootStackForSubgraphs(KeyStack &RootStack, const AtomMask_t &AtomMask)
481{
482 for(molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
483 const atom * const Father = (*iter)->GetTrueFather();
484 if (AtomMask.isTrue(Father->getNr())) // apply mask
[9291d04]485 if ((treatment == IncludeHydrogen) || ((*iter)->getType()->getAtomicNumber() != 1)) // skip hydrogen
[339910]486 RootStack.push_front((*iter)->getNr());
487 }
488}
489
490/** The indices per keyset are compared to the respective father's Atom::Nr in each subgraph and thus put into \a **&FragmentList.
491 * \param *KeySetList list with all keysets
492 * \param ListOfLocalAtoms Lookup table for each subgraph and index of each atom in global molecule, may be NULL on start, then it is filled
493 * \param **&FragmentList list to be allocated and returned
494 * \param FreeList true - ***ListOfLocalAtoms is free'd before return, false - it is not
495 * \retuen true - success, false - failure
496 */
[bfbd4a]497bool Fragmentation::AssignKeySetsToFragment(const Graph &KeySetList, ListOfLocalAtoms_t &ListOfLocalAtoms, Graph &FragmentList, bool FreeList)
[339910]498{
[8ac66b4]499// Info FunctionInfo(__func__);
[339910]500 bool status = true;
501 size_t KeySetCounter = 0;
502
503 // fill ListOfLocalAtoms if NULL was given
504 if (!mol->FillListOfLocalAtoms(ListOfLocalAtoms, mol->getAtomCount())) {
[8ac66b4]505 ELOG(1, "Filling of ListOfLocalAtoms failed.");
[339910]506 return false;
507 }
508
509 if (KeySetList.size() != 0) { // if there are some scanned keysets at all
510 // assign scanned keysets
511 KeySet TempSet;
[bfbd4a]512 for (Graph::const_iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) { // key sets contain global numbers!
[339910]513 if (ListOfLocalAtoms[mol->FindAtom(*((*runner).first.begin()))->getNr()] != NULL) {// as we may assume that that bond structure is unchanged, we only test the first key in each set
514 // translate keyset to local numbers
515 for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
516 TempSet.insert(ListOfLocalAtoms[mol->FindAtom(*sprinter)->getNr()]->getNr());
517 // insert into FragmentList
518 FragmentList.insert(GraphPair(TempSet, pair<int, double> (KeySetCounter++, (*runner).second.second)));
519 }
520 TempSet.clear();
521 }
522 } else
[8ac66b4]523 ELOG(2, "KeySetList is NULL or empty.");
[339910]524
525 if (FreeList) {
526 // free the index lookup list
527 ListOfLocalAtoms.clear();
528 }
529 return status;
530}
531
532/** Translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
533 * \param &FragmentList Graph with local numbers per fragment
534 * \param &TotalNumberOfKeySets global key set counter
535 * \param &TotalGraph Graph to be filled with global numbers
536 */
537void Fragmentation::TranslateIndicesToGlobalIDs(Graph &FragmentList, int &TotalNumberOfKeySets, Graph &TotalGraph)
538{
[8ac66b4]539// Info FunctionInfo(__func__);
[339910]540 for (Graph::iterator runner = FragmentList.begin(); runner != FragmentList.end(); runner++) {
541 KeySet TempSet;
542 for (KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
[2ab6b6]543 TempSet.insert((mol->FindAtom(*sprinter))->GetTrueFather()->getId());
[339910]544 TotalGraph.insert(GraphPair(TempSet, pair<int, double> (TotalNumberOfKeySets++, (*runner).second.second)));
545 }
546}
547
Note: See TracBrowser for help on using the repository browser.