source: src/Fragmentation/Fragmentation.cpp@ 0cd8cf

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 0cd8cf was 8ac66b4, checked in by Frederik Heber <heber@…>, 12 years ago

VERBOSE: Lots of changes to verbosity of fragmentation process.

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