source: src/Fragmentation/Fragmentation.cpp@ caece4

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

Enhanced documentation significantly.

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