source: src/molecule_fragmentation.cpp@ f67817f

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

Extracted power set generation into own class PowerSetGenerator.

  • Property mode set to 100644
File size: 38.4 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * molecule_fragmentation.cpp
10 *
11 * Created on: Oct 5, 2009
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include <cstring>
23
24#include "atom.hpp"
25#include "Bond/bond.hpp"
26#include "Box.hpp"
27#include "CodePatterns/Verbose.hpp"
28#include "CodePatterns/Log.hpp"
29#include "config.hpp"
30#include "Element/element.hpp"
31#include "Element/periodentafel.hpp"
32#include "Fragmentation/fragmentation_helpers.hpp"
33#include "Fragmentation/PowerSetGenerator.hpp"
34#include "Fragmentation/UniqueFragments.hpp"
35#include "Graph/BondGraph.hpp"
36#include "Graph/CheckAgainstAdjacencyFile.hpp"
37#include "Graph/CyclicStructureAnalysis.hpp"
38#include "Graph/DepthFirstSearchAnalysis.hpp"
39#include "Helpers/helpers.hpp"
40#include "LinearAlgebra/RealSpaceMatrix.hpp"
41#include "molecule.hpp"
42#include "World.hpp"
43
44/************************************* Functions for class molecule *********************************/
45
46
47/** Estimates by educated guessing (using upper limit) the expected number of fragments.
48 * The upper limit is
49 * \f[
50 * n = N \cdot C^k
51 * \f]
52 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
53 * \param *out output stream for debugging
54 * \param order bond order k
55 * \return number n of fragments
56 */
57int molecule::GuesstimateFragmentCount(int order)
58{
59 size_t c = 0;
60 int FragmentCount;
61 // get maximum bond degree
62 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
63 const BondList& ListOfBonds = (*iter)->getListOfBonds();
64 c = (ListOfBonds.size() > c) ? ListOfBonds.size() : c;
65 }
66 FragmentCount = NoNonHydrogen*(1 << (c*order));
67 DoLog(1) && (Log() << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl);
68 return FragmentCount;
69};
70
71/** Checks whether the OrderAtSite is still below \a Order at some site.
72 * \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
73 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
74 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
75 * \param path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
76 * \return true - needs further fragmentation, false - does not need fragmentation
77 */
78bool molecule::CheckOrderAtSite(bool *AtomMask, Graph *GlobalKeySetList, int Order, std::string path)
79{
80 bool status = false;
81
82 // initialize mask list
83 for(int i=getAtomCount();i--;)
84 AtomMask[i] = false;
85
86 if (Order < 0) { // adaptive increase of BondOrder per site
87 if (AtomMask[getAtomCount()] == true) // break after one step
88 return false;
89
90 // transmorph graph keyset list into indexed KeySetList
91 if (GlobalKeySetList == NULL) {
92 DoeLog(1) && (eLog()<< Verbose(1) << "Given global key set list (graph) is NULL!" << endl);
93 return false;
94 }
95 map<int,KeySet> *IndexKeySetList = GraphToIndexedKeySet(GlobalKeySetList);
96
97 // parse the EnergyPerFragment file
98 map<int, pair<double,int> > *AdaptiveCriteriaList = ScanAdaptiveFileIntoMap(path, *IndexKeySetList); // (Root No., (Value, Order)) !
99 if (AdaptiveCriteriaList->empty()) {
100 DoeLog(2) && (eLog()<< Verbose(2) << "Unable to parse file, incrementing all." << endl);
101 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
102 #ifdef ADDHYDROGEN
103 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
104 #endif
105 {
106 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
107 status = true;
108 }
109 }
110 }
111 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
112 map<double, pair<int,int> > *FinalRootCandidates = ReMapAdaptiveCriteriaListToValue(AdaptiveCriteriaList, this);
113
114 // pick the ones still below threshold and mark as to be adaptively updated
115 MarkUpdateCandidates(AtomMask, *FinalRootCandidates, Order, this);
116
117 delete[](IndexKeySetList);
118 delete[](AdaptiveCriteriaList);
119 delete[](FinalRootCandidates);
120 } else { // global increase of Bond Order
121 for(molecule::const_iterator iter = begin(); iter != end(); ++iter) {
122 #ifdef ADDHYDROGEN
123 if ((*iter)->getType()->getAtomicNumber() != 1) // skip hydrogen
124 #endif
125 {
126 AtomMask[(*iter)->getNr()] = true; // include all (non-hydrogen) atoms
127 if ((Order != 0) && ((*iter)->AdaptiveOrder < Order)) // && ((*iter)->AdaptiveOrder < MinimumRingSize[(*iter)->getNr()]))
128 status = true;
129 }
130 }
131 if ((!Order) && (!AtomMask[getAtomCount()])) // single stepping, just check
132 status = true;
133
134 if (!status) {
135 if (Order == 0)
136 DoLog(1) && (Log() << Verbose(1) << "Single stepping done." << endl);
137 else
138 DoLog(1) && (Log() << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl);
139 }
140 }
141
142 PrintAtomMask(AtomMask, getAtomCount()); // for debugging
143
144 return status;
145};
146
147/** Create a SortIndex to map from atomic labels to the sequence in which the atoms are given in the config file.
148 * \param *out output stream for debugging
149 * \param *&SortIndex Mapping array of size molecule::AtomCount
150 * \return true - success, false - failure of SortIndex alloc
151 */
152bool molecule::CreateMappingLabelsToConfigSequence(int *&SortIndex)
153{
154 if (SortIndex != NULL) {
155 DoLog(1) && (Log() << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl);
156 return false;
157 }
158 SortIndex = new int[getAtomCount()];
159 for(int i=getAtomCount();i--;)
160 SortIndex[i] = -1;
161
162 int AtomNo = 0;
163 for(internal_iterator iter=atoms.begin();iter!=atoms.end();++iter){
164 ASSERT(SortIndex[(*iter)->getNr()]==-1,"Same SortIndex set twice");
165 SortIndex[(*iter)->getNr()] = AtomNo++;
166 }
167
168 return true;
169};
170
171
172
173/** Creates a lookup table for true father's Atom::Nr -> atom ptr.
174 * \param *start begin of list (STL iterator, i.e. first item)
175 * \paran *end end of list (STL iterator, i.e. one past last item)
176 * \param **Lookuptable pointer to return allocated lookup table (should be NULL on start)
177 * \param count optional predetermined size for table (otherwise we set the count to highest true father id)
178 * \return true - success, false - failure
179 */
180bool molecule::CreateFatherLookupTable(atom **&LookupTable, int count)
181{
182 bool status = true;
183 int AtomNo;
184
185 if (LookupTable != NULL) {
186 Log() << Verbose(0) << "Pointer for Lookup table is not NULL! Aborting ..." <<endl;
187 return false;
188 }
189
190 // count them
191 if (count == 0) {
192 for (molecule::iterator iter = begin(); iter != end(); ++iter) { // create a lookup table (Atom::Nr -> atom) used as a marker table lateron
193 count = (count < (*iter)->GetTrueFather()->getNr()) ? (*iter)->GetTrueFather()->getNr() : count;
194 }
195 }
196 if (count <= 0) {
197 Log() << Verbose(0) << "Count of lookup list is 0 or less." << endl;
198 return false;
199 }
200
201 // allocate and fill
202 LookupTable = new atom *[count];
203 if (LookupTable == NULL) {
204 eLog() << Verbose(0) << "LookupTable memory allocation failed!" << endl;
205 performCriticalExit();
206 status = false;
207 } else {
208 for (int i=0;i<count;i++)
209 LookupTable[i] = NULL;
210 for (molecule::iterator iter = begin(); iter != end(); ++iter) {
211 AtomNo = (*iter)->GetTrueFather()->getNr();
212 if ((AtomNo >= 0) && (AtomNo < count)) {
213 //*out << "Setting LookupTable[" << AtomNo << "] to " << *(*iter) << endl;
214 LookupTable[AtomNo] = (*iter);
215 } else {
216 Log() << Verbose(0) << "Walker " << *(*iter) << " exceeded range of nuclear ids [0, " << count << ")." << endl;
217 status = false;
218 break;
219 }
220 }
221 }
222
223 return status;
224};
225
226
227/** Performs a many-body bond order analysis for a given bond order.
228 * -# parses adjacency, keysets and orderatsite files
229 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
230 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
231y contribution", and that's why this consciously not done in the following loop)
232 * -# in a loop over all subgraphs
233 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
234 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
235 * -# combines the generated molecule lists from all subgraphs
236 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
237 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
238 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
239 * subgraph in the MoleculeListClass.
240 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
241 * \param &prefix path and prefix of the bond order configs to be written
242 * \param &DFS contains bond structure analysis data
243 * \return 1 - continue, 2 - stop (no fragmentation occured)
244 */
245int molecule::FragmentMolecule(int Order, std::string &prefix, DepthFirstSearchAnalysis &DFS)
246{
247 MoleculeListClass *BondFragments = NULL;
248 int FragmentCounter;
249 MoleculeLeafClass *MolecularWalker = NULL;
250 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
251 fstream File;
252 bool FragmentationToDo = true;
253 bool CheckOrder = false;
254 Graph **FragmentList = NULL;
255 Graph *ParsedFragmentList = NULL;
256 Graph TotalGraph; // graph with all keysets however local numbers
257 int TotalNumberOfKeySets = 0;
258 atom ***ListOfLocalAtoms = NULL;
259 bool *AtomMask = NULL;
260
261 DoLog(0) && (Log() << Verbose(0) << endl);
262#ifdef ADDHYDROGEN
263 DoLog(0) && (Log() << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl);
264#else
265 DoLog(0) && (Log() << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl);
266#endif
267
268 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
269
270 // ===== 1. Check whether bond structure is same as stored in files ====
271
272 // === compare it with adjacency file ===
273 {
274 std::ifstream File;
275 std::string filename;
276 filename = prefix + ADJACENCYFILE;
277 File.open(filename.c_str(), ios::out);
278 DoLog(1) && (Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl);
279
280 CheckAgainstAdjacencyFile FileChecker(World::getInstance().beginAtomSelection(), World::getInstance().endAtomSelection());
281 FragmentationToDo = FragmentationToDo && FileChecker(File);
282 }
283
284 // === reset bond degree and perform CorrectBondDegree ===
285 for(World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
286 iter != World::getInstance().moleculeEnd();
287 ++iter) {
288 // correct bond degree
289 World::AtomComposite Set = (*iter)->getAtomSet();
290 World::getInstance().getBondGraph()->CorrectBondDegree(Set);
291 }
292
293 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
294 // NOTE: We assume here that DFS has been performed and molecule structure is current.
295 Subgraphs = DFS.getMoleculeStructure();
296
297 // ===== 3. if structure still valid, parse key set file and others =====
298 FragmentationToDo = FragmentationToDo && ParseKeySetFile(prefix, ParsedFragmentList);
299
300 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
301 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(prefix);
302
303 // =================================== Begin of FRAGMENTATION ===============================
304 // ===== 6a. assign each keyset to its respective subgraph =====
305 const int MolCount = World::getInstance().numMolecules();
306 ListOfLocalAtoms = new atom **[MolCount];
307 for (int i=0;i<MolCount;i++)
308 ListOfLocalAtoms[i] = NULL;
309 FragmentCounter = 0;
310 Subgraphs->next->AssignKeySetsToFragment(this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, FragmentCounter, true);
311 delete[](ListOfLocalAtoms);
312
313 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
314 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
315 AtomMask = new bool[getAtomCount()+1];
316 AtomMask[getAtomCount()] = false;
317 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
318 while ((CheckOrder = CheckOrderAtSite(AtomMask, ParsedFragmentList, Order, prefix))) {
319 FragmentationToDo = FragmentationToDo || CheckOrder;
320 AtomMask[getAtomCount()] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
321 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
322 Subgraphs->next->FillRootStackForSubgraphs(RootStack, AtomMask, (FragmentCounter = 0));
323
324 // ===== 7. fill the bond fragment list =====
325 FragmentCounter = 0;
326 MolecularWalker = Subgraphs;
327 while (MolecularWalker->next != NULL) {
328 MolecularWalker = MolecularWalker->next;
329 DoLog(1) && (Log() << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl);
330 if (MolecularWalker->Leaf->hasBondStructure()) {
331 // call BOSSANOVA method
332 DoLog(0) && (Log() << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl);
333 MolecularWalker->Leaf->FragmentBOSSANOVA(FragmentList[FragmentCounter], RootStack[FragmentCounter]);
334 } else {
335 DoeLog(1) && (eLog()<< Verbose(1) << "Subgraph " << MolecularWalker << " has no atoms!" << endl);
336 }
337 FragmentCounter++; // next fragment list
338 }
339 }
340 DoLog(2) && (Log() << Verbose(2) << "CheckOrder is " << CheckOrder << "." << endl);
341 delete[](RootStack);
342 delete[](AtomMask);
343 delete(ParsedFragmentList);
344
345 // ==================================== End of FRAGMENTATION ============================================
346
347 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
348 Subgraphs->next->TranslateIndicesToGlobalIDs(FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
349
350 // free subgraph memory again
351 FragmentCounter = 0;
352 while (Subgraphs != NULL) {
353 // remove entry in fragment list
354 // remove subgraph fragment
355 MolecularWalker = Subgraphs->next;
356 Subgraphs->Leaf = NULL;
357 delete(Subgraphs);
358 Subgraphs = MolecularWalker;
359 }
360 // free fragment list
361 for (int i=0; i< FragmentCounter; ++i )
362 delete(FragmentList[i]);
363 delete[](FragmentList);
364
365 DoLog(0) && (Log() << Verbose(0) << FragmentCounter << " subgraph fragments have been removed." << std::endl);
366
367 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
368 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
369 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
370 BondFragments = new MoleculeListClass(World::getPointer());
371 int k=0;
372 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
373 KeySet test = (*runner).first;
374 DoLog(0) && (Log() << Verbose(0) << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl);
375 BondFragments->insert(StoreFragmentFromKeySet(test, World::getInstance().getConfig()));
376 k++;
377 }
378 DoLog(0) && (Log() << Verbose(0) << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl);
379
380 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
381 if (BondFragments->ListOfMolecules.size() != 0) {
382 // create the SortIndex from BFS labels to order in the config file
383 int *SortIndex = NULL;
384 CreateMappingLabelsToConfigSequence(SortIndex);
385
386 DoLog(1) && (Log() << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl);
387 if (BondFragments->OutputConfigForListOfFragments(prefix, SortIndex))
388 DoLog(1) && (Log() << Verbose(1) << "All configs written." << endl);
389 else
390 DoLog(1) && (Log() << Verbose(1) << "Some config writing failed." << endl);
391
392 // store force index reference file
393 BondFragments->StoreForcesFile(prefix, SortIndex);
394
395 // store keysets file
396 StoreKeySetFile(TotalGraph, prefix);
397
398 {
399 // store Adjacency file
400 std::string filename = prefix + ADJACENCYFILE;
401 StoreAdjacencyToFile(filename);
402 }
403
404 // store Hydrogen saturation correction file
405 BondFragments->AddHydrogenCorrection(prefix);
406
407 // store adaptive orders into file
408 StoreOrderAtSiteFile(prefix);
409
410 // restore orbital and Stop values
411 //CalculateOrbitals(*configuration);
412
413 // free memory for bond part
414 DoLog(1) && (Log() << Verbose(1) << "Freeing bond memory" << endl);
415 delete[](SortIndex);
416 } else {
417 DoLog(1) && (Log() << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl);
418 }
419 // remove all create molecules again from the World including their atoms
420 for (MoleculeList::iterator iter = BondFragments->ListOfMolecules.begin();
421 !BondFragments->ListOfMolecules.empty();
422 iter = BondFragments->ListOfMolecules.begin()) {
423 // remove copied atoms and molecule again
424 molecule *mol = *iter;
425 mol->removeAtomsinMolecule();
426 World::getInstance().destroyMolecule(mol);
427 BondFragments->ListOfMolecules.erase(iter);
428 }
429 delete(BondFragments);
430 DoLog(0) && (Log() << Verbose(0) << "End of bond fragmentation." << endl);
431
432 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
433};
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 molecule::StoreOrderAtSiteFile(std::string &path)
442{
443 string line;
444 ofstream file;
445
446 line = path + ORDERATSITEFILE;
447 file.open(line.c_str());
448 DoLog(1) && (Log() << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl);
449 if (file.good()) {
450 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputOrder), &file));
451 file.close();
452 DoLog(1) && (Log() << Verbose(1) << "done." << endl);
453 return true;
454 } else {
455 DoLog(1) && (Log() << Verbose(1) << "failed to open file " << line << "." << endl);
456 return false;
457 }
458};
459
460/** Parses pairs(Atom::Nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
461 * Atoms not present in the file get "0".
462 * \param &path path to file ORDERATSITEFILEe
463 * \return true - file found and scanned, false - file not found
464 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
465 */
466bool molecule::ParseOrderAtSiteFromFile(std::string &path)
467{
468 unsigned char *OrderArray = new unsigned char[getAtomCount()];
469 bool *MaxArray = new bool[getAtomCount()];
470 bool status;
471 int AtomNr, value;
472 string line;
473 ifstream file;
474
475 for(int i=0;i<getAtomCount();i++) {
476 OrderArray[i] = 0;
477 MaxArray[i] = false;
478 }
479
480 DoLog(1) && (Log() << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl);
481 line = path + ORDERATSITEFILE;
482 file.open(line.c_str());
483 if (file.good()) {
484 while (!file.eof()) { // parse from file
485 AtomNr = -1;
486 file >> AtomNr;
487 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
488 file >> value;
489 OrderArray[AtomNr] = value;
490 file >> value;
491 MaxArray[AtomNr] = value;
492 //Log() << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
493 }
494 }
495 file.close();
496
497 // set atom values
498 for(internal_iterator iter=atoms.begin();iter!=atoms.end();++iter){
499 (*iter)->AdaptiveOrder = OrderArray[(*iter)->getNr()];
500 (*iter)->MaxOrder = MaxArray[(*iter)->getNr()];
501 }
502 //SetAtomValueToIndexedArray( OrderArray, &atom::getNr(), &atom::AdaptiveOrder );
503 //SetAtomValueToIndexedArray( MaxArray, &atom::getNr(), &atom::MaxOrder );
504
505 DoLog(1) && (Log() << Verbose(1) << "\t ... done." << endl);
506 status = true;
507 } else {
508 DoLog(1) && (Log() << Verbose(1) << "\t ... failed to open file " << line << "." << endl);
509 status = false;
510 }
511 delete[](OrderArray);
512 delete[](MaxArray);
513
514 DoLog(1) && (Log() << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl);
515 return status;
516};
517
518
519
520/** Looks through a std::deque<atom *> and returns the likeliest removal candiate.
521 * \param *out output stream for debugging messages
522 * \param *&Leaf KeySet to look through
523 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
524 * \param index of the atom suggested for removal
525 */
526int molecule::LookForRemovalCandidate(KeySet *&Leaf, int *&ShortestPathList)
527{
528 atom *Runner = NULL;
529 int SP, Removal;
530
531 DoLog(2) && (Log() << Verbose(2) << "Looking for removal candidate." << endl);
532 SP = -1; //0; // not -1, so that Root is never removed
533 Removal = -1;
534 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
535 Runner = FindAtom((*runner));
536 if (Runner->getType()->getAtomicNumber() != 1) { // skip all those added hydrogens when re-filling snake stack
537 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
538 SP = ShortestPathList[(*runner)];
539 Removal = (*runner);
540 }
541 }
542 }
543 return Removal;
544};
545
546/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
547 * \param *mol total molecule
548 * \param *Leaf fragment molecule
549 * \param &Leaflet pointer to KeySet structure
550 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
551 * \return number of atoms in fragment
552 */
553int StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
554{
555 atom *FatherOfRunner = NULL;
556
557 // first create the minimal set of atoms from the KeySet
558 int size = 0;
559 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
560 FatherOfRunner = mol->FindAtom((*runner)); // find the id
561 SonList[FatherOfRunner->getNr()] = Leaf->AddCopyAtom(FatherOfRunner);
562 size++;
563 }
564 return size;
565};
566
567/** Creates an induced subgraph out of a fragmental key set, adding bonds and hydrogens (if treated specially).
568 * \param *out output stream for debugging messages
569 * \param *mol total molecule
570 * \param *Leaf fragment molecule
571 * \param IsAngstroem whether we have Ansgtroem or bohrradius
572 * \param **SonList list which atom of \a *Leaf is a son of which atom in \a *mol
573 */
574void CreateInducedSubgraphOfFragment(molecule *mol, molecule *Leaf, atom **SonList, bool IsAngstroem)
575{
576 bool LonelyFlag = false;
577 atom *OtherFather = NULL;
578 atom *FatherOfRunner = NULL;
579
580#ifdef ADDHYDROGEN
581 molecule::const_iterator runner;
582#endif
583 // we increment the iter just before skipping the hydrogen
584 for (molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end();) {
585 LonelyFlag = true;
586 FatherOfRunner = (*iter)->father;
587 ASSERT(FatherOfRunner,"Atom without father found");
588 if (SonList[FatherOfRunner->getNr()] != NULL) { // check if this, our father, is present in list
589 // create all bonds
590 const BondList& ListOfBonds = FatherOfRunner->getListOfBonds();
591 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
592 BondRunner != ListOfBonds.end();
593 ++BondRunner) {
594 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
595// Log() << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->getNr()] << " is bound to " << *OtherFather;
596 if (SonList[OtherFather->getNr()] != NULL) {
597// Log() << Verbose(0) << ", whose son is " << *SonList[OtherFather->getNr()] << "." << endl;
598 if (OtherFather->getNr() > FatherOfRunner->getNr()) { // add bond (Nr check is for adding only one of both variants: ab, ba)
599// Log() << Verbose(3) << "Adding Bond: ";
600// Log() << Verbose(0) <<
601 Leaf->AddBond((*iter), SonList[OtherFather->getNr()], (*BondRunner)->BondDegree);
602// Log() << Verbose(0) << "." << endl;
603 //NumBonds[(*iter)->getNr()]++;
604 } else {
605// Log() << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
606 }
607 LonelyFlag = false;
608 } else {
609// Log() << Verbose(0) << ", who has no son in this fragment molecule." << endl;
610#ifdef ADDHYDROGEN
611 //Log() << Verbose(3) << "Adding Hydrogen to " << (*iter)->Name << " and a bond in between." << endl;
612 if(!Leaf->AddHydrogenReplacementAtom((*BondRunner), (*iter), FatherOfRunner, OtherFather, IsAngstroem))
613 exit(1);
614#endif
615 //NumBonds[(*iter)->getNr()] += Binder->BondDegree;
616 }
617 }
618 } else {
619 DoeLog(1) && (eLog()<< Verbose(1) << "Son " << (*iter)->getName() << " has father " << FatherOfRunner->getName() << " but its entry in SonList is " << SonList[FatherOfRunner->getNr()] << "!" << endl);
620 }
621 if ((LonelyFlag) && (Leaf->getAtomCount() > 1)) {
622 DoLog(0) && (Log() << Verbose(0) << **iter << "has got bonds only to hydrogens!" << endl);
623 }
624 ++iter;
625#ifdef ADDHYDROGEN
626 while ((iter != Leaf->end()) && ((*iter)->getType()->getAtomicNumber() == 1)){ // skip added hydrogen
627 iter++;
628 }
629#endif
630 }
631};
632
633/** Stores a fragment from \a KeySet into \a molecule.
634 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
635 * molecule and adds missing hydrogen where bonds were cut.
636 * \param *out output stream for debugging messages
637 * \param &Leaflet pointer to KeySet structure
638 * \param IsAngstroem whether we have Ansgtroem or bohrradius
639 * \return pointer to constructed molecule
640 */
641molecule * molecule::StoreFragmentFromKeySet(KeySet &Leaflet, bool IsAngstroem)
642{
643 atom **SonList = new atom*[getAtomCount()];
644 molecule *Leaf = World::getInstance().createMolecule();
645
646 for(int i=0;i<getAtomCount();i++)
647 SonList[i] = NULL;
648
649// Log() << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
650 StoreFragmentFromKeySet_Init(this, Leaf, Leaflet, SonList);
651 // create the bonds between all: Make it an induced subgraph and add hydrogen
652// Log() << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
653 CreateInducedSubgraphOfFragment(this, Leaf, SonList, IsAngstroem);
654
655 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
656 delete[](SonList);
657// Log() << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
658 return Leaf;
659};
660
661/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
662 * -# constructs a complete keyset of the molecule
663 * -# In a loop over all possible roots from the given rootstack
664 * -# increases order of root site
665 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
666 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
667as the restricted one and each site in the set as the root)
668 * -# these are merged into a fragment list of keysets
669 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
670 * Important only is that we create all fragments, it is not important if we create them more than once
671 * as these copies are filtered out via use of the hash table (KeySet).
672 * \param *out output stream for debugging
673 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
674 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
675 * \return pointer to Graph list
676 */
677void molecule::FragmentBOSSANOVA(Graph *&FragmentList, KeyStack &RootStack)
678{
679 Graph ***FragmentLowerOrdersList = NULL;
680 int NumLevels = 0;
681 int NumMolecules = 0;
682 int TotalNumMolecules = 0;
683 int *NumMoleculesOfOrder = NULL;
684 int Order = 0;
685 int UpgradeCount = RootStack.size();
686 KeyStack FragmentRootStack;
687 int RootKeyNr = 0;
688 int RootNr = 0;
689 struct UniqueFragments FragmentSearch;
690 class PowerSetGenerator PSG;
691
692 DoLog(0) && (Log() << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl);
693
694 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
695 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
696 NumMoleculesOfOrder = new int[UpgradeCount];
697 FragmentLowerOrdersList = new Graph**[UpgradeCount];
698
699 for(int i=0;i<UpgradeCount;i++) {
700 NumMoleculesOfOrder[i] = 0;
701 FragmentLowerOrdersList[i] = NULL;
702 }
703
704 FragmentSearch.Init(FindAtom(RootKeyNr), getAtomCount());
705
706 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
707 KeySet CompleteMolecule;
708 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
709 CompleteMolecule.insert((*iter)->GetTrueFather()->getNr());
710 }
711
712 // 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
713 // 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),
714 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
715 // 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)
716 RootNr = 0; // counts through the roots in RootStack
717 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
718 RootKeyNr = RootStack.front();
719 RootStack.pop_front();
720 atom *Walker = FindAtom(RootKeyNr);
721 // check cyclic lengths
722 //if ((MinimumRingSize[Walker->GetTrueFather()->getNr()] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->getNr()])) {
723 // Log() << Verbose(0) << "Bond order " << Walker->GetTrueFather()->AdaptiveOrder << " of Root " << *Walker << " greater than or equal to Minimum Ring size of " << MinimumRingSize << " found is not allowed." << endl;
724 //} else
725 {
726 // increase adaptive order by one
727 Walker->GetTrueFather()->AdaptiveOrder++;
728 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
729
730 // initialise Order-dependent entries of UniqueFragments structure
731 FragmentSearch.InitialiseSPList(Order);
732
733 // allocate memory for all lower level orders in this 1D-array of ptrs
734 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
735 FragmentLowerOrdersList[RootNr] = new Graph*[NumLevels];
736 for (int i=0;i<NumLevels;i++)
737 FragmentLowerOrdersList[RootNr][i] = NULL;
738
739 // create top order where nothing is reduced
740 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
741 DoLog(0) && (Log() << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl); // , NumLevels is " << NumLevels << "
742
743 // Create list of Graphs of current Bond Order (i.e. F_{ij})
744 FragmentLowerOrdersList[RootNr][0] = new Graph;
745 FragmentSearch.TEFactor = 1.;
746 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
747 FragmentSearch.setRoot(Walker);
748 NumMoleculesOfOrder[RootNr] = PSG(&FragmentSearch, Walker->AdaptiveOrder, CompleteMolecule);
749
750 // output resulting number
751 DoLog(1) && (Log() << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl);
752 if (NumMoleculesOfOrder[RootNr] != 0) {
753 NumMolecules = 0;
754 } else {
755 Walker->GetTrueFather()->MaxOrder = true;
756 }
757 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
758 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
759 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
760// Log() << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
761 RootStack.push_back(RootKeyNr); // put back on stack
762 RootNr++;
763
764 // free Order-dependent entries of UniqueFragments structure for next loop cycle
765 FragmentSearch.FreeSPList(Order);
766 }
767 }
768 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
769 DoLog(1) && (Log() << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl);
770 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
771
772 // cleanup FragmentSearch structure
773 FragmentSearch.Cleanup();
774
775 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
776 // 5433222211111111
777 // 43221111
778 // 3211
779 // 21
780 // 1
781
782 // Subsequently, we combine all into a single list (FragmentList)
783 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, this);
784 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, this);
785 delete[](NumMoleculesOfOrder);
786
787 DoLog(0) && (Log() << Verbose(0) << "End of FragmentBOSSANOVA." << endl);
788};
789
790/** Corrects the nuclei position if the fragment was created over the cell borders.
791 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
792 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
793 * and re-add the bond. Looping on the distance check.
794 * \param *out ofstream for debugging messages
795 */
796bool molecule::ScanForPeriodicCorrection()
797{
798 bond *Binder = NULL;
799 //bond *OtherBinder = NULL;
800 atom *Walker = NULL;
801 atom *OtherWalker = NULL;
802 RealSpaceMatrix matrix = World::getInstance().getDomain().getM();
803 enum GraphEdge::Shading *ColorList = NULL;
804 double tmp;
805 //bool LastBond = true; // only needed to due list construct
806 Vector Translationvector;
807 //std::deque<atom *> *CompStack = NULL;
808 std::deque<atom *> *AtomStack = new std::deque<atom *>; // (getAtomCount());
809 bool flag = true;
810 BondGraph *BG = World::getInstance().getBondGraph();
811
812 DoLog(2) && (Log() << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl);
813
814 ColorList = new enum GraphEdge::Shading[getAtomCount()];
815 for (int i=0;i<getAtomCount();i++)
816 ColorList[i] = (enum GraphEdge::Shading)0;
817 if (flag) {
818 // remove bonds that are beyond bonddistance
819 Translationvector.Zero();
820 // scan all bonds
821 flag = false;
822 for(molecule::iterator AtomRunner = begin(); (!flag) && (AtomRunner != end()); ++AtomRunner) {
823 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
824 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
825 (!flag) && (BondRunner != ListOfBonds.end());
826 ++BondRunner) {
827 Binder = (*BondRunner);
828 for (int i=NDIM;i--;) {
829 tmp = fabs(Binder->leftatom->at(i) - Binder->rightatom->at(i));
830 //Log() << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
831 const range<double> MinMaxDistance(
832 BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom));
833 if (!MinMaxDistance.isInRange(tmp)) {
834 DoLog(2) && (Log() << Verbose(2) << "Correcting at bond " << *Binder << "." << endl);
835 flag = true;
836 break;
837 }
838 }
839 }
840 }
841 //if (flag) {
842 if (0) {
843 // create translation vector from their periodically modified distance
844 for (int i=NDIM;i--;) {
845 tmp = Binder->leftatom->at(i) - Binder->rightatom->at(i);
846 const range<double> MinMaxDistance(
847 BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom));
848 if (fabs(tmp) > MinMaxDistance.last) // check against Min is not useful for components
849 Translationvector[i] = (tmp < 0) ? +1. : -1.;
850 }
851 Translationvector *= matrix;
852 //Log() << Verbose(3) << "Translation vector is ";
853 Log() << Verbose(0) << Translationvector << endl;
854 // apply to all atoms of first component via BFS
855 for (int i=getAtomCount();i--;)
856 ColorList[i] = GraphEdge::white;
857 AtomStack->push_front(Binder->leftatom);
858 while (!AtomStack->empty()) {
859 Walker = AtomStack->front();
860 AtomStack->pop_front();
861 //Log() << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
862 ColorList[Walker->getNr()] = GraphEdge::black; // mark as explored
863 *Walker += Translationvector; // translate
864 const BondList& ListOfBonds = Walker->getListOfBonds();
865 for (BondList::const_iterator Runner = ListOfBonds.begin();
866 Runner != ListOfBonds.end();
867 ++Runner) {
868 if ((*Runner) != Binder) {
869 OtherWalker = (*Runner)->GetOtherAtom(Walker);
870 if (ColorList[OtherWalker->getNr()] == GraphEdge::white) {
871 AtomStack->push_front(OtherWalker); // push if yet unexplored
872 }
873 }
874 }
875 }
876// // re-add bond
877// if (OtherBinder == NULL) { // is the only bond?
878// //Do nothing
879// } else {
880// if (!LastBond) {
881// link(Binder, OtherBinder); // no more implemented bond::previous ...
882// } else {
883// link(OtherBinder, Binder); // no more implemented bond::previous ...
884// }
885// }
886 } else {
887 DoLog(3) && (Log() << Verbose(3) << "No corrections for this fragment." << endl);
888 }
889 //delete(CompStack);
890 }
891 // free allocated space from ReturnFullMatrixforSymmetric()
892 delete(AtomStack);
893 delete[](ColorList);
894 DoLog(2) && (Log() << Verbose(2) << "End of ScanForPeriodicCorrection." << endl);
895
896 return flag;
897};
Note: See TracBrowser for help on using the repository browser.