source: src/Fragmentation/Fragmentation.cpp@ 945797

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator 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_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions 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 GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 945797 was 0f5956, checked in by Frederik Heber <heber@…>, 9 years ago

Added "parse-state-files" option to fragment-molecule which is off by default.

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