source: src/Fragmentation/PowerSetGenerator.cpp@ 105b72

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 105b72 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
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
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/>.
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
39#include <sstream>
40
41#include "CodePatterns/Info.hpp"
42#include "CodePatterns/Log.hpp"
43
44#include "Atom/atom.hpp"
45#include "Bond/bond.hpp"
46#include "Fragmentation/KeySet.hpp"
47#include "Fragmentation/UniqueFragments.hpp"
48
49/** Constructor of class PowerSetGenerator.
50 *
51 */
52PowerSetGenerator::PowerSetGenerator(UniqueFragments *_FragmentSearch, int _Order) :
53 BondsPerSPList(_Order),
54 FragmentSearch(_FragmentSearch)
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{
73 LOG(1+verbosity, "Clearing touched list.");
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 */
90int PowerSetGenerator::AddPowersetToSnakeStack(int verbosity, int CurrentCombination, int SetDimension, KeySet *FragmentSet, std::vector<bond::ptr > &BondsSet, int *&TouchedList, int &TouchedIndex)
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
101 //LOG(1+verbosity, "Current Bond is " << BondsSet[j] << ", checking on " << *OtherWalker << ".");
102 LOG(2+verbosity, "Adding " << *OtherWalker << " with nr " << OtherWalker->getNr() << ".");
103 TestKeySetInsert = FragmentSet->insert(OtherWalker->getNr());
104 if (TestKeySetInsert.second) {
105 TouchedList[TouchedIndex++] = OtherWalker->getNr(); // note as added
106 Added++;
107 } else {
108 LOG(2+verbosity, "This was item was already present in the keyset.");
109 }
110 } else {
111 LOG(2+verbosity, "Not adding.");
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 */
124int PowerSetGenerator::CountSetMembers(std::list<bond::ptr >::const_iterator SetFirst, std::list<bond::ptr >::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
125{
126 int SetDimension = 0;
127 for( std::list<bond::ptr >::const_iterator Binder = SetFirst;
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 */
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)
147{
148 int SetDimension = 0;
149 for( std::list<bond::ptr >::const_iterator Binder = SetFirst;
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];
171 LOG(2+verbosity, "Removing item nr. " << Removal << " from snake stack.");
172 FragmentSet->erase(Removal);
173 TouchedList[j] = -1;
174 }
175 std::stringstream output;
176 output << "Remaining local nr.s on snake stack are: ";
177 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
178 output << (*runner) << " ";
179 LOG(2, output.str());
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
193 * \param treatment whether to treat hydrogen special or not
194 * \return number of inserted fragments
195 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
196 */
197int PowerSetGenerator::operator()(KeySet &RestrictedKeySet, const enum HydrogenTreatment treatment)
198{
199 int Counter = FragmentSearch->FragmentCounter; // mark current value of counter
200
201 LOG(0, std::endl);
202 LOG(0, "Begin of PowerSetGenerator with order " << BondsPerSPList.getOrder() << " at Root " << *FragmentSearch->getRoot() << ".");
203
204 BondsPerSPList.SetSPList(FragmentSearch->getRoot());
205
206 // do a BFS search to fill the SP lists and label the found vertices
207 BondsPerSPList.FillSPListandLabelVertices(FragmentSearch->getRoot()->GetTrueFather()->getNr(), RestrictedKeySet, treatment);
208
209 // outputting all list for debugging
210 BondsPerSPList.OutputSPList();
211
212 // creating fragments with the found edge sets (may be done in reverse order, faster)
213 int SP = BondsPerSPList.CountNumbersInBondsList();
214 LOG(0, "Total number of edges is " << SP << ".");
215 {
216 // start with root (push on fragment stack)
217 LOG(0, "Starting fragment generation with " << *FragmentSearch->getRoot() << ", local nr is " << FragmentSearch->getRoot()->getNr() << ".");
218 FragmentSearch->FragmentSet->clear();
219 LOG(0, "Preparing subset for this root and calling generator.");
220
221 // prepare the subset and call the generator
222 std::vector<bond::ptr> BondsList;
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
227
228 SPFragmentGenerator(0, BondsList, BondsPerSPList.BondsPerSPCount[0], BondsPerSPList.getOrder());
229 }
230
231 // as FragmentSearch structure is used only once, we don't have to clean it anymore
232 // remove root from stack
233 LOG(0, "Removing root again from stack.");
234 FragmentSearch->FragmentSet->erase(FragmentSearch->getRoot()->getNr());
235
236 // free'ing the bonds lists
237 BondsPerSPList.ResetSPList();
238
239 // return list
240 LOG(0, "End of PowerSetGenerator.");
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 */
257void PowerSetGenerator::SPFragmentGenerator(int RootDistance, std::vector<bond::ptr > &BondsSet, int SetDimension, int SubOrder)
258{
259 Info info(__func__);
260 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
261 int TouchedIndex, SubSetDimension, Added;
262 int SpaceLeft;
263 int *TouchedList = new int[SubOrder + 1];
264 KeySetTestPair TestKeySetInsert;
265
266 const int NumCombinations = 1 << SetDimension;
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
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).");
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
278 LOG(1+verbosity, "Going through all combinations of the power set.");
279 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
280 // count the set bit of i
281 const int bits = countBits(i, SetDimension);
282
283 LOG(1+verbosity, "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << ".");
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
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
302 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
303 if ((SpaceLeft > 0) && (RootDistance < BondsPerSPList.getOrder())) {
304 LOG(1+verbosity, "There's still some space left on stack: " << SpaceLeft << ".");
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
307 const int SP = RootDistance+1; // this is the next level
308
309 // first count the members in the subset
310 SubSetDimension = CountSetMembers(BondsPerSPList.BondsPerSPList[SP].begin(), BondsPerSPList.BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
311
312 // then allocate and fill the list
313 std::vector<bond::ptr > BondsList;
314 BondsList.resize(SubSetDimension);
315 SubSetDimension = FillBondsList(BondsList, BondsPerSPList.BondsPerSPList[SP].begin(), BondsPerSPList.BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
316
317 // then iterate
318 LOG(2+verbosity, "Calling subset generator " << SP << " away from root " << *FragmentSearch->getRoot() << " with sub set dimension " << SubSetDimension << ".");
319 SPFragmentGenerator(SP, BondsList, SubSetDimension, SubOrder-bits);
320 }
321 } else {
322 LOG(1+verbosity, "No more space or no shortest path levels, not recursing.");
323 }
324
325 // --3-- remove all added items in this level from snake stack
326 LOG(1+verbosity, "Removing all items that were added on this SP level " << RootDistance << ".");
327 RemoveAllTouchedFromSnakeStack(verbosity, FragmentSearch->FragmentSet, TouchedList, TouchedIndex);
328 } else {
329 LOG(2+verbosity, "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set.");
330 }
331 }
332 delete[](TouchedList);
333 LOG(1+verbosity, "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->getRoot() << " and SubOrder is " << SubOrder << ".");
334};
Note: See TracBrowser for help on using the repository browser.