source: src/Fragmentation/Fragmentation.cpp@ 4694df

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 4694df was 3aa8a5, checked in by Frederik Heber <heber@…>, 12 years ago

REFACTOR: AdjacencyList now just contains a single internal map.

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