source: src/Fragmentation/Fragmentation.cpp@ 8dbcaf

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

FIX: Fragmentation's OrderAtSite was written per molecule and with local ids.

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