source: src/molecule_fragmentation.cpp@ d0b375b

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

Removed ShortestPathList.

  • there have been references in the code that ShortestPathList is probably obsolete meanwhile (seemingly it is).
  • Property mode set to 100644
File size: 37.3 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/** Initializes some value for putting fragment of \a *mol into \a *Leaf.
520 * \param *mol total molecule
521 * \param *Leaf fragment molecule
522 * \param &Leaflet pointer to KeySet structure
523 * \param **SonList calloc'd list which atom of \a *Leaf is a son of which atom in \a *mol
524 * \return number of atoms in fragment
525 */
526int StoreFragmentFromKeySet_Init(molecule *mol, molecule *Leaf, KeySet &Leaflet, atom **SonList)
527{
528 atom *FatherOfRunner = NULL;
529
530 // first create the minimal set of atoms from the KeySet
531 int size = 0;
532 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
533 FatherOfRunner = mol->FindAtom((*runner)); // find the id
534 SonList[FatherOfRunner->getNr()] = Leaf->AddCopyAtom(FatherOfRunner);
535 size++;
536 }
537 return size;
538};
539
540/** Creates an induced subgraph out of a fragmental key set, adding bonds and hydrogens (if treated specially).
541 * \param *out output stream for debugging messages
542 * \param *mol total molecule
543 * \param *Leaf fragment molecule
544 * \param IsAngstroem whether we have Ansgtroem or bohrradius
545 * \param **SonList list which atom of \a *Leaf is a son of which atom in \a *mol
546 */
547void CreateInducedSubgraphOfFragment(molecule *mol, molecule *Leaf, atom **SonList, bool IsAngstroem)
548{
549 bool LonelyFlag = false;
550 atom *OtherFather = NULL;
551 atom *FatherOfRunner = NULL;
552
553#ifdef ADDHYDROGEN
554 molecule::const_iterator runner;
555#endif
556 // we increment the iter just before skipping the hydrogen
557 for (molecule::const_iterator iter = Leaf->begin(); iter != Leaf->end();) {
558 LonelyFlag = true;
559 FatherOfRunner = (*iter)->father;
560 ASSERT(FatherOfRunner,"Atom without father found");
561 if (SonList[FatherOfRunner->getNr()] != NULL) { // check if this, our father, is present in list
562 // create all bonds
563 const BondList& ListOfBonds = FatherOfRunner->getListOfBonds();
564 for (BondList::const_iterator BondRunner = ListOfBonds.begin();
565 BondRunner != ListOfBonds.end();
566 ++BondRunner) {
567 OtherFather = (*BondRunner)->GetOtherAtom(FatherOfRunner);
568// Log() << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->getNr()] << " is bound to " << *OtherFather;
569 if (SonList[OtherFather->getNr()] != NULL) {
570// Log() << Verbose(0) << ", whose son is " << *SonList[OtherFather->getNr()] << "." << endl;
571 if (OtherFather->getNr() > FatherOfRunner->getNr()) { // add bond (Nr check is for adding only one of both variants: ab, ba)
572// Log() << Verbose(3) << "Adding Bond: ";
573// Log() << Verbose(0) <<
574 Leaf->AddBond((*iter), SonList[OtherFather->getNr()], (*BondRunner)->BondDegree);
575// Log() << Verbose(0) << "." << endl;
576 //NumBonds[(*iter)->getNr()]++;
577 } else {
578// Log() << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
579 }
580 LonelyFlag = false;
581 } else {
582// Log() << Verbose(0) << ", who has no son in this fragment molecule." << endl;
583#ifdef ADDHYDROGEN
584 //Log() << Verbose(3) << "Adding Hydrogen to " << (*iter)->Name << " and a bond in between." << endl;
585 if(!Leaf->AddHydrogenReplacementAtom((*BondRunner), (*iter), FatherOfRunner, OtherFather, IsAngstroem))
586 exit(1);
587#endif
588 //NumBonds[(*iter)->getNr()] += Binder->BondDegree;
589 }
590 }
591 } else {
592 DoeLog(1) && (eLog()<< Verbose(1) << "Son " << (*iter)->getName() << " has father " << FatherOfRunner->getName() << " but its entry in SonList is " << SonList[FatherOfRunner->getNr()] << "!" << endl);
593 }
594 if ((LonelyFlag) && (Leaf->getAtomCount() > 1)) {
595 DoLog(0) && (Log() << Verbose(0) << **iter << "has got bonds only to hydrogens!" << endl);
596 }
597 ++iter;
598#ifdef ADDHYDROGEN
599 while ((iter != Leaf->end()) && ((*iter)->getType()->getAtomicNumber() == 1)){ // skip added hydrogen
600 iter++;
601 }
602#endif
603 }
604};
605
606/** Stores a fragment from \a KeySet into \a molecule.
607 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
608 * molecule and adds missing hydrogen where bonds were cut.
609 * \param *out output stream for debugging messages
610 * \param &Leaflet pointer to KeySet structure
611 * \param IsAngstroem whether we have Ansgtroem or bohrradius
612 * \return pointer to constructed molecule
613 */
614molecule * molecule::StoreFragmentFromKeySet(KeySet &Leaflet, bool IsAngstroem)
615{
616 atom **SonList = new atom*[getAtomCount()];
617 molecule *Leaf = World::getInstance().createMolecule();
618
619 for(int i=0;i<getAtomCount();i++)
620 SonList[i] = NULL;
621
622// Log() << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
623 StoreFragmentFromKeySet_Init(this, Leaf, Leaflet, SonList);
624 // create the bonds between all: Make it an induced subgraph and add hydrogen
625// Log() << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
626 CreateInducedSubgraphOfFragment(this, Leaf, SonList, IsAngstroem);
627
628 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
629 delete[](SonList);
630// Log() << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
631 return Leaf;
632};
633
634/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
635 * -# constructs a complete keyset of the molecule
636 * -# In a loop over all possible roots from the given rootstack
637 * -# increases order of root site
638 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
639 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
640as the restricted one and each site in the set as the root)
641 * -# these are merged into a fragment list of keysets
642 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
643 * Important only is that we create all fragments, it is not important if we create them more than once
644 * as these copies are filtered out via use of the hash table (KeySet).
645 * \param *out output stream for debugging
646 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
647 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
648 * \return pointer to Graph list
649 */
650void molecule::FragmentBOSSANOVA(Graph *&FragmentList, KeyStack &RootStack)
651{
652 Graph ***FragmentLowerOrdersList = NULL;
653 int NumLevels = 0;
654 int NumMolecules = 0;
655 int TotalNumMolecules = 0;
656 int *NumMoleculesOfOrder = NULL;
657 int Order = 0;
658 int UpgradeCount = RootStack.size();
659 KeyStack FragmentRootStack;
660 int RootKeyNr = 0;
661 int RootNr = 0;
662 struct UniqueFragments FragmentSearch;
663 class PowerSetGenerator PSG;
664
665 DoLog(0) && (Log() << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl);
666
667 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
668 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
669 NumMoleculesOfOrder = new int[UpgradeCount];
670 FragmentLowerOrdersList = new Graph**[UpgradeCount];
671
672 for(int i=0;i<UpgradeCount;i++) {
673 NumMoleculesOfOrder[i] = 0;
674 FragmentLowerOrdersList[i] = NULL;
675 }
676
677 FragmentSearch.Init(FindAtom(RootKeyNr));
678
679 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
680 KeySet CompleteMolecule;
681 for (molecule::const_iterator iter = begin(); iter != end(); ++iter) {
682 CompleteMolecule.insert((*iter)->GetTrueFather()->getNr());
683 }
684
685 // 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
686 // 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),
687 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
688 // 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)
689 RootNr = 0; // counts through the roots in RootStack
690 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
691 RootKeyNr = RootStack.front();
692 RootStack.pop_front();
693 atom *Walker = FindAtom(RootKeyNr);
694 // check cyclic lengths
695 //if ((MinimumRingSize[Walker->GetTrueFather()->getNr()] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->getNr()])) {
696 // 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;
697 //} else
698 {
699 // increase adaptive order by one
700 Walker->GetTrueFather()->AdaptiveOrder++;
701 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
702
703 // initialise Order-dependent entries of UniqueFragments structure
704 FragmentSearch.InitialiseSPList(Order);
705
706 // allocate memory for all lower level orders in this 1D-array of ptrs
707 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
708 FragmentLowerOrdersList[RootNr] = new Graph*[NumLevels];
709 for (int i=0;i<NumLevels;i++)
710 FragmentLowerOrdersList[RootNr][i] = NULL;
711
712 // create top order where nothing is reduced
713 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
714 DoLog(0) && (Log() << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl); // , NumLevels is " << NumLevels << "
715
716 // Create list of Graphs of current Bond Order (i.e. F_{ij})
717 FragmentLowerOrdersList[RootNr][0] = new Graph;
718 FragmentSearch.TEFactor = 1.;
719 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
720 FragmentSearch.setRoot(Walker);
721 NumMoleculesOfOrder[RootNr] = PSG(&FragmentSearch, Walker->AdaptiveOrder, CompleteMolecule);
722
723 // output resulting number
724 DoLog(1) && (Log() << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl);
725 if (NumMoleculesOfOrder[RootNr] != 0) {
726 NumMolecules = 0;
727 } else {
728 Walker->GetTrueFather()->MaxOrder = true;
729 }
730 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
731 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
732 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
733// Log() << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
734 RootStack.push_back(RootKeyNr); // put back on stack
735 RootNr++;
736
737 // free Order-dependent entries of UniqueFragments structure for next loop cycle
738 FragmentSearch.FreeSPList(Order);
739 }
740 }
741 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
742 DoLog(1) && (Log() << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl);
743 DoLog(0) && (Log() << Verbose(0) << "==============================================================================================================" << endl);
744
745 // cleanup FragmentSearch structure
746 FragmentSearch.Cleanup();
747
748 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
749 // 5433222211111111
750 // 43221111
751 // 3211
752 // 21
753 // 1
754
755 // Subsequently, we combine all into a single list (FragmentList)
756 CombineAllOrderListIntoOne(FragmentList, FragmentLowerOrdersList, RootStack, this);
757 FreeAllOrdersList(FragmentLowerOrdersList, RootStack, this);
758 delete[](NumMoleculesOfOrder);
759
760 DoLog(0) && (Log() << Verbose(0) << "End of FragmentBOSSANOVA." << endl);
761};
762
763/** Corrects the nuclei position if the fragment was created over the cell borders.
764 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
765 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
766 * and re-add the bond. Looping on the distance check.
767 * \param *out ofstream for debugging messages
768 */
769bool molecule::ScanForPeriodicCorrection()
770{
771 bond *Binder = NULL;
772 //bond *OtherBinder = NULL;
773 atom *Walker = NULL;
774 atom *OtherWalker = NULL;
775 RealSpaceMatrix matrix = World::getInstance().getDomain().getM();
776 enum GraphEdge::Shading *ColorList = NULL;
777 double tmp;
778 //bool LastBond = true; // only needed to due list construct
779 Vector Translationvector;
780 //std::deque<atom *> *CompStack = NULL;
781 std::deque<atom *> *AtomStack = new std::deque<atom *>; // (getAtomCount());
782 bool flag = true;
783 BondGraph *BG = World::getInstance().getBondGraph();
784
785 DoLog(2) && (Log() << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl);
786
787 ColorList = new enum GraphEdge::Shading[getAtomCount()];
788 for (int i=0;i<getAtomCount();i++)
789 ColorList[i] = (enum GraphEdge::Shading)0;
790 if (flag) {
791 // remove bonds that are beyond bonddistance
792 Translationvector.Zero();
793 // scan all bonds
794 flag = false;
795 for(molecule::iterator AtomRunner = begin(); (!flag) && (AtomRunner != end()); ++AtomRunner) {
796 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
797 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
798 (!flag) && (BondRunner != ListOfBonds.end());
799 ++BondRunner) {
800 Binder = (*BondRunner);
801 for (int i=NDIM;i--;) {
802 tmp = fabs(Binder->leftatom->at(i) - Binder->rightatom->at(i));
803 //Log() << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
804 const range<double> MinMaxDistance(
805 BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom));
806 if (!MinMaxDistance.isInRange(tmp)) {
807 DoLog(2) && (Log() << Verbose(2) << "Correcting at bond " << *Binder << "." << endl);
808 flag = true;
809 break;
810 }
811 }
812 }
813 }
814 //if (flag) {
815 if (0) {
816 // create translation vector from their periodically modified distance
817 for (int i=NDIM;i--;) {
818 tmp = Binder->leftatom->at(i) - Binder->rightatom->at(i);
819 const range<double> MinMaxDistance(
820 BG->getMinMaxDistance(Binder->leftatom, Binder->rightatom));
821 if (fabs(tmp) > MinMaxDistance.last) // check against Min is not useful for components
822 Translationvector[i] = (tmp < 0) ? +1. : -1.;
823 }
824 Translationvector *= matrix;
825 //Log() << Verbose(3) << "Translation vector is ";
826 Log() << Verbose(0) << Translationvector << endl;
827 // apply to all atoms of first component via BFS
828 for (int i=getAtomCount();i--;)
829 ColorList[i] = GraphEdge::white;
830 AtomStack->push_front(Binder->leftatom);
831 while (!AtomStack->empty()) {
832 Walker = AtomStack->front();
833 AtomStack->pop_front();
834 //Log() << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
835 ColorList[Walker->getNr()] = GraphEdge::black; // mark as explored
836 *Walker += Translationvector; // translate
837 const BondList& ListOfBonds = Walker->getListOfBonds();
838 for (BondList::const_iterator Runner = ListOfBonds.begin();
839 Runner != ListOfBonds.end();
840 ++Runner) {
841 if ((*Runner) != Binder) {
842 OtherWalker = (*Runner)->GetOtherAtom(Walker);
843 if (ColorList[OtherWalker->getNr()] == GraphEdge::white) {
844 AtomStack->push_front(OtherWalker); // push if yet unexplored
845 }
846 }
847 }
848 }
849// // re-add bond
850// if (OtherBinder == NULL) { // is the only bond?
851// //Do nothing
852// } else {
853// if (!LastBond) {
854// link(Binder, OtherBinder); // no more implemented bond::previous ...
855// } else {
856// link(OtherBinder, Binder); // no more implemented bond::previous ...
857// }
858// }
859 } else {
860 DoLog(3) && (Log() << Verbose(3) << "No corrections for this fragment." << endl);
861 }
862 //delete(CompStack);
863 }
864 // free allocated space from ReturnFullMatrixforSymmetric()
865 delete(AtomStack);
866 delete[](ColorList);
867 DoLog(2) && (Log() << Verbose(2) << "End of ScanForPeriodicCorrection." << endl);
868
869 return flag;
870};
Note: See TracBrowser for help on using the repository browser.