source: src/Fragmentation/Fragmentation.cpp@ 58952a

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 58952a was fe0cb8, checked in by Frederik Heber <heber@…>, 11 years ago

Added option DoCyclesFull to FragmentationAction.

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