source: src/Fragmentation/PowerSetGenerator.cpp@ 39a07a

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 39a07a was 9291d04, checked in by Frederik Heber <heber@…>, 12 years ago

Split saturation with hydrogen of treatment of hydrogen.

  • Property mode set to 100644
File size: 14.3 KB
RevLine 
[f67817f]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
[0aa122]4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
[94d5ac6]5 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
[f67817f]21 */
22
23/*
24 * PowerSetGenerator.cpp
25 *
26 * Created on: Oct 18, 2011
27 * Author: heber
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include "CodePatterns/MemDebug.hpp"
36
37#include "PowerSetGenerator.hpp"
38
[47d041]39#include <sstream>
40
41#include "CodePatterns/Info.hpp"
[f67817f]42#include "CodePatterns/Log.hpp"
43
[6f0841]44#include "Atom/atom.hpp"
[f67817f]45#include "Bond/bond.hpp"
[f0674a]46#include "Fragmentation/KeySet.hpp"
[f67817f]47#include "Fragmentation/UniqueFragments.hpp"
48
49/** Constructor of class PowerSetGenerator.
50 *
51 */
[d760bb]52PowerSetGenerator::PowerSetGenerator(UniqueFragments *_FragmentSearch, int _Order) :
53 BondsPerSPList(_Order),
[212c179]54 FragmentSearch(_FragmentSearch)
[f67817f]55{}
56
57/** Destructor of class PowerSetGenerator.
58 *
59 */
60PowerSetGenerator::~PowerSetGenerator()
61{
62 FragmentSearch = NULL;
63}
64
65/** Clears the touched list
66 * \param verbosity verbosity level
67 * \param *&TouchedList touched list
68 * \param SubOrder current suborder
69 * \param TouchedIndex currently touched
70 */
71void PowerSetGenerator::ClearingTouched(int verbosity, int *&TouchedList, int SubOrder, int &TouchedIndex)
72{
[47d041]73 LOG(1+verbosity, "Clearing touched list.");
[f67817f]74 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
75 TouchedList[TouchedIndex] = -1;
76 TouchedIndex = 0;
77
78}
79
80/** Adds the current combination of the power set to the snake stack.
81 * \param verbosity verbosity level
82 * \param CurrentCombination
83 * \param SetDimension maximum number of bits in power set
84 * \param *FragmentSet snake stack to remove from
85 * \param &BondsSet set of bonds
86 * \param *&TouchedList touched list
87 * \param TouchedIndex currently touched
88 * \return number of set bits
89 */
[88c8ec]90int PowerSetGenerator::AddPowersetToSnakeStack(int verbosity, int CurrentCombination, int SetDimension, KeySet *FragmentSet, std::vector<bond::ptr > &BondsSet, int *&TouchedList, int &TouchedIndex)
[f67817f]91{
92 atom *OtherWalker = NULL;
93 bool bit = false;
94 KeySetTestPair TestKeySetInsert;
95
96 int Added = 0;
97 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
98 bit = ((CurrentCombination & (1 << j)) != 0); // mask the bit for the j-th bond
99 if (bit) { // if bit is set, we add this bond partner
100 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
[47d041]101 //LOG(1+verbosity, "Current Bond is " << BondsSet[j] << ", checking on " << *OtherWalker << ".");
102 LOG(2+verbosity, "Adding " << *OtherWalker << " with nr " << OtherWalker->getNr() << ".");
[f67817f]103 TestKeySetInsert = FragmentSet->insert(OtherWalker->getNr());
104 if (TestKeySetInsert.second) {
105 TouchedList[TouchedIndex++] = OtherWalker->getNr(); // note as added
106 Added++;
107 } else {
[47d041]108 LOG(2+verbosity, "This was item was already present in the keyset.");
[f67817f]109 }
110 } else {
[47d041]111 LOG(2+verbosity, "Not adding.");
[f67817f]112 }
113 }
114 return Added;
115};
116
117/** Counts the number of elements in a power set.
118 * \param SetFirst begin iterator first bond
119 * \param SetLast end iterator
120 * \param *&TouchedList touched list
121 * \param TouchedIndex currently touched
122 * \return number of elements
123 */
[88c8ec]124int PowerSetGenerator::CountSetMembers(std::list<bond::ptr >::const_iterator SetFirst, std::list<bond::ptr >::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
[f67817f]125{
126 int SetDimension = 0;
[88c8ec]127 for( std::list<bond::ptr >::const_iterator Binder = SetFirst;
[f67817f]128 Binder != SetLast;
129 ++Binder) {
130 for (int k=TouchedIndex;k--;) {
131 if ((*Binder)->Contains(TouchedList[k])) // if we added this very endpiece
132 SetDimension++;
133 }
134 }
135 return SetDimension;
136};
137
138/** Fills a list of bonds from another
139 * \param *BondsList bonds array/vector to fill
140 * \param SetFirst begin iterator first bond
141 * \param SetLast end iterator
142 * \param *&TouchedList touched list
143 * \param TouchedIndex currently touched
144 * \return number of elements
145 */
[88c8ec]146int PowerSetGenerator::FillBondsList(std::vector<bond::ptr > &BondsList, std::list<bond::ptr >::const_iterator SetFirst, std::list<bond::ptr >::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
[f67817f]147{
148 int SetDimension = 0;
[88c8ec]149 for( std::list<bond::ptr >::const_iterator Binder = SetFirst;
[f67817f]150 Binder != SetLast;
151 ++Binder) {
152 for (int k=0;k<TouchedIndex;k++) {
153 if ((*Binder)->leftatom->getNr() == TouchedList[k]) // leftatom is always the closer one
154 BondsList[SetDimension++] = (*Binder);
155 }
156 }
157 return SetDimension;
158};
159
160/** Remove all items that were added on this SP level.
161 * \param verbosity verbosity level
162 * \param *FragmentSet snake stack to remove from
163 * \param *&TouchedList touched list
164 * \param TouchedIndex currently touched
165 */
166void PowerSetGenerator::RemoveAllTouchedFromSnakeStack(int verbosity, KeySet *FragmentSet, int *&TouchedList, int &TouchedIndex)
167{
168 int Removal = 0;
169 for(int j=0;j<TouchedIndex;j++) {
170 Removal = TouchedList[j];
[47d041]171 LOG(2+verbosity, "Removing item nr. " << Removal << " from snake stack.");
[f67817f]172 FragmentSet->erase(Removal);
173 TouchedList[j] = -1;
174 }
[47d041]175 std::stringstream output;
176 output << "Remaining local nr.s on snake stack are: ";
[f67817f]177 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
[47d041]178 output << (*runner) << " ";
179 LOG(2, output.str());
[f67817f]180 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
181};
182
183
184/** Creates a list of all unique fragments of certain vertex size from a given graph \a Fragment for a given root vertex in the context of \a this molecule.
185 * -# initialises UniqueFragments structure
186 * -# fills edge list via BFS
187 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
188 root distance, the edge set, its dimension and the current suborder
189 * -# Free'ing structure
190 * Note that we may use the fact that the atoms are SP-ordered on the atomstack. I.e. when popping always the last, we first get all
191 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
192 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
[9291d04]193 * \param treatment whether to treat hydrogen special or not
[f67817f]194 * \return number of inserted fragments
195 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
196 */
[9291d04]197int PowerSetGenerator::operator()(KeySet &RestrictedKeySet, const enum HydrogenTreatment treatment)
[f67817f]198{
199 int Counter = FragmentSearch->FragmentCounter; // mark current value of counter
200
[47d041]201 LOG(0, std::endl);
202 LOG(0, "Begin of PowerSetGenerator with order " << BondsPerSPList.getOrder() << " at Root " << *FragmentSearch->getRoot() << ".");
[f67817f]203
[212c179]204 BondsPerSPList.SetSPList(FragmentSearch->getRoot());
[f67817f]205
206 // do a BFS search to fill the SP lists and label the found vertices
[9291d04]207 BondsPerSPList.FillSPListandLabelVertices(FragmentSearch->getRoot()->GetTrueFather()->getNr(), RestrictedKeySet, treatment);
[f67817f]208
209 // outputting all list for debugging
[212c179]210 BondsPerSPList.OutputSPList();
[f67817f]211
212 // creating fragments with the found edge sets (may be done in reverse order, faster)
[212c179]213 int SP = BondsPerSPList.CountNumbersInBondsList();
[47d041]214 LOG(0, "Total number of edges is " << SP << ".");
[d760bb]215 {
[f67817f]216 // start with root (push on fragment stack)
[47d041]217 LOG(0, "Starting fragment generation with " << *FragmentSearch->getRoot() << ", local nr is " << FragmentSearch->getRoot()->getNr() << ".");
[f67817f]218 FragmentSearch->FragmentSet->clear();
[47d041]219 LOG(0, "Preparing subset for this root and calling generator.");
[f67817f]220
221 // prepare the subset and call the generator
[7d82a5]222 std::vector<bond::ptr> BondsList;
[212c179]223 BondsList.resize(BondsPerSPList.BondsPerSPCount[0]);
224 ASSERT(BondsPerSPList.BondsPerSPList[0].size() != 0,
225 "molecule::PowerSetGenerator() - BondsPerSPList.BondsPerSPList[0] contains no root bond.");
226 BondsList[0] = (*BondsPerSPList.BondsPerSPList[0].begin()); // on SP level 0 there's only the root bond
[f67817f]227
[212c179]228 SPFragmentGenerator(0, BondsList, BondsPerSPList.BondsPerSPCount[0], BondsPerSPList.getOrder());
[f67817f]229 }
230
231 // as FragmentSearch structure is used only once, we don't have to clean it anymore
232 // remove root from stack
[47d041]233 LOG(0, "Removing root again from stack.");
[f67817f]234 FragmentSearch->FragmentSet->erase(FragmentSearch->getRoot()->getNr());
235
236 // free'ing the bonds lists
[212c179]237 BondsPerSPList.ResetSPList();
[f67817f]238
239 // return list
[47d041]240 LOG(0, "End of PowerSetGenerator.");
[f67817f]241 return (FragmentSearch->FragmentCounter - Counter);
242};
243
244/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
245 * -# loops over every possible combination (2^dimension of edge set)
246 * -# inserts current set, if there's still space left
247 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
248ance+1
249 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
250 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
251distance) and current set
252 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
253 * \param BondsSet array of bonds to check
254 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
255 * \param SubOrder remaining number of allowed vertices to add
256 */
[88c8ec]257void PowerSetGenerator::SPFragmentGenerator(int RootDistance, std::vector<bond::ptr > &BondsSet, int SetDimension, int SubOrder)
[f67817f]258{
[47d041]259 Info info(__func__);
[f67817f]260 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
[d760bb]261 int TouchedIndex, SubSetDimension, Added;
[f67817f]262 int SpaceLeft;
263 int *TouchedList = new int[SubOrder + 1];
264 KeySetTestPair TestKeySetInsert;
265
[d760bb]266 const int NumCombinations = 1 << SetDimension;
[f67817f]267
268 // here for all bonds of Walker all combinations of end pieces (from the bonds)
269 // have to be added and for the remaining ANOVA order GraphCrawler be called
270 // recursively for the next level
271
[47d041]272 LOG(1+verbosity, "We are " << RootDistance << " away from Root, which is " << *FragmentSearch->getRoot() << ", SubOrder is " << SubOrder << ", SetDimension is " << SetDimension << " and this means " << NumCombinations-1 << " combination(s).");
[f67817f]273
274 // initialised touched list (stores added atoms on this level)
275 ClearingTouched(verbosity, TouchedList, SubOrder, TouchedIndex);
276
277 // create every possible combination of the endpieces
[47d041]278 LOG(1+verbosity, "Going through all combinations of the power set.");
[f67817f]279 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
280 // count the set bit of i
[d760bb]281 const int bits = countBits(i, SetDimension);
[f67817f]282
[47d041]283 LOG(1+verbosity, "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << ".");
[f67817f]284 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
285 // --1-- add this set of the power set of bond partners to the snake stack
286 Added = AddPowersetToSnakeStack(verbosity, i, SetDimension, FragmentSearch->FragmentSet, BondsSet, TouchedList, TouchedIndex);
287
[d760bb]288 // --2-- store the fragment
289 const int order = BondsPerSPList.getOrder() - SubOrder + Added - 1;
290 LOG(1+verbosity, "Storing fragment as order " << order << ".");
291 // store fragment as a KeySet
292 if (DoLog(2)) {
293 std::stringstream output;
294 output << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
295 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
296 output << (*runner) << " ";
297 LOG(2, output.str());
298 }
299 FragmentSearch->InsertFragmentIntoGraph(order);
300
301 // --3-- if below SubOrder still, recurse
[f67817f]302 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
[d760bb]303 if ((SpaceLeft > 0) && (RootDistance < BondsPerSPList.getOrder())) {
[47d041]304 LOG(1+verbosity, "There's still some space left on stack: " << SpaceLeft << ".");
[f67817f]305 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
306 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
[d760bb]307 const int SP = RootDistance+1; // this is the next level
[f67817f]308
309 // first count the members in the subset
[212c179]310 SubSetDimension = CountSetMembers(BondsPerSPList.BondsPerSPList[SP].begin(), BondsPerSPList.BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
[f67817f]311
312 // then allocate and fill the list
[88c8ec]313 std::vector<bond::ptr > BondsList;
[f67817f]314 BondsList.resize(SubSetDimension);
[212c179]315 SubSetDimension = FillBondsList(BondsList, BondsPerSPList.BondsPerSPList[SP].begin(), BondsPerSPList.BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
[f67817f]316
317 // then iterate
[47d041]318 LOG(2+verbosity, "Calling subset generator " << SP << " away from root " << *FragmentSearch->getRoot() << " with sub set dimension " << SubSetDimension << ".");
[f67817f]319 SPFragmentGenerator(SP, BondsList, SubSetDimension, SubOrder-bits);
320 }
321 } else {
[d760bb]322 LOG(1+verbosity, "No more space or no shortest path levels, not recursing.");
[f67817f]323 }
324
325 // --3-- remove all added items in this level from snake stack
[47d041]326 LOG(1+verbosity, "Removing all items that were added on this SP level " << RootDistance << ".");
[f67817f]327 RemoveAllTouchedFromSnakeStack(verbosity, FragmentSearch->FragmentSet, TouchedList, TouchedIndex);
328 } else {
[47d041]329 LOG(2+verbosity, "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set.");
[f67817f]330 }
331 }
332 delete[](TouchedList);
[47d041]333 LOG(1+verbosity, "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->getRoot() << " and SubOrder is " << SubOrder << ".");
[f67817f]334};
Note: See TracBrowser for help on using the repository browser.