source: src/Fragmentation/Exporters/SaturationDistanceMaximizer.cpp@ e9e86f

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

Added SaturationDistanceMaximizer to determine best alphas for SaturatedBonds.

  • also added simple unit tests that ascertains that with just degree 1 bonds nothing happens.
  • Property mode set to 100644
File size: 10.0 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2014 Frederik Heber. 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 * SaturationDistanceMaximizer.cpp
25 *
26 * Created on: Jul 27, 2014
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 "SaturationDistanceMaximizer.hpp"
38
39#include <cmath>
40#include <gsl/gsl_multimin.h>
41#include <gsl/gsl_vector.h>
42
43#include "CodePatterns/Log.hpp"
44
45double
46func(const gsl_vector *x, void *adata)
47{
48 // get the object whose functions we call
49 SaturationDistanceMaximizer::Advocate *maximizer =
50 static_cast<SaturationDistanceMaximizer::Advocate *>(adata);
51 // set alphas
52 maximizer->setAlphas(x);
53 // calculate function value and return
54 return maximizer->calculatePenality();
55}
56
57void
58jacf(const gsl_vector *x, void *adata, gsl_vector *g)
59{
60 // get the object whose functions we call
61 SaturationDistanceMaximizer::Advocate *maximizer =
62 static_cast<SaturationDistanceMaximizer::Advocate *>(adata);
63 // set alphas
64 maximizer->setAlphas(x);
65 // calculate function gradient and return
66 std::vector<double> gradient = maximizer->calculatePenalityGradient();
67 for (unsigned int i=0;i<gradient.size();++i)
68 gsl_vector_set(g,i,gradient[i]);
69}
70
71void
72funcjacf(const gsl_vector *x, void *adata, double *f, gsl_vector *g)
73{
74 // get the object whose functions we call
75 SaturationDistanceMaximizer::Advocate *maximizer =
76 static_cast<SaturationDistanceMaximizer::Advocate *>(adata);
77 // set alphas
78 maximizer->setAlphas(x);
79 // calculate function value and return
80 *f = maximizer->calculatePenality();
81 std::vector<double> gradient = maximizer->calculatePenalityGradient();
82 for (unsigned int i=0;i<gradient.size();++i)
83 gsl_vector_set(g,i,gradient[i]);
84}
85
86std::vector<double> SaturationDistanceMaximizer::getAlphas() const
87{
88 std::vector<double> alphas;
89 PositionContainers_t::iterator containeriter = PositionContainers.begin();
90 for (unsigned int i=0; i<PositionContainers.size(); ++i, ++containeriter)
91 alphas.push_back( (*containeriter)->alpha );
92 return alphas;
93}
94
95void SaturationDistanceMaximizer::setAlphas(const gsl_vector *x)
96{
97 PositionContainers_t::iterator containeriter = PositionContainers.begin();
98 for (unsigned int i=0; i<PositionContainers.size(); ++i, ++containeriter)
99 (*containeriter)->alpha = gsl_vector_get(x,i);
100}
101
102void SaturationDistanceMaximizer::operator()()
103{
104 // some control constants
105 const double tolerance = 1e-6;
106 const unsigned int MAXITERATIONS = 100;
107
108 const gsl_multimin_fdfminimizer_type *T;
109 gsl_multimin_fdfminimizer *s;
110
111 gsl_vector *x;
112 gsl_multimin_function_fdf my_func;
113
114 const unsigned int N = PositionContainers.size();
115 my_func.n = N;
116 my_func.f = &func;
117 my_func.df = &jacf;
118 my_func.fdf = &funcjacf;
119 my_func.params = getAdvocate();
120
121 // allocate argument and set to zero
122 x = gsl_vector_alloc(N);
123 for (unsigned int i=0;i<N;++i)
124 gsl_vector_set(x, i, 0.);
125
126 // set minimizer and allocate workspace
127 T = gsl_multimin_fdfminimizer_vector_bfgs;
128 s = gsl_multimin_fdfminimizer_alloc (T, N);
129
130 // initialize minimizer
131 gsl_multimin_fdfminimizer_set(s, &my_func, x, 0.1, tolerance); /* tolerance */
132
133 size_t iter = 0;
134 int status = 0;
135 do {
136 ++iter;
137 status = gsl_multimin_fdfminimizer_iterate(s);
138
139 if (status)
140 break;
141
142 status = gsl_multimin_test_gradient(s->gradient, tolerance);
143
144 } while ((status = GSL_CONTINUE) && (iter < MAXITERATIONS));
145
146 // set to solution
147 setAlphas(s->x);
148
149 // print solution
150 if (DoLog(4)) {
151 std::stringstream sstream;
152 sstream << "DEBUG: Minimal alphas are ";
153 for (unsigned int i=0;i<N;++i)
154 sstream << gsl_vector_get(s->x,i) << ((i!= N-1) ? "," : "");
155 LOG(4, sstream.str());
156 }
157
158 // free memory
159 gsl_multimin_fdfminimizer_free(s);
160 gsl_vector_free(x);
161}
162
163SaturationDistanceMaximizer::Advocate* SaturationDistanceMaximizer::getAdvocate()
164{
165 return new Advocate(*this);
166}
167
168SaturationDistanceMaximizer::position_bins_t
169SaturationDistanceMaximizer::getAllPositionBins() const
170{
171 position_bins_t position_bins;
172 position_bins.reserve(PositionContainers.size());
173 for (PositionContainers_t::const_iterator containeriter = PositionContainers.begin();
174 containeriter != PositionContainers.end(); ++containeriter)
175 position_bins.push_back( (*containeriter)->getPositions() );
176
177 return position_bins;
178}
179
180double SaturationDistanceMaximizer::calculatePenality() const
181{
182 double penalty = 0.;
183
184 LOG(6, "DEBUG: Current alphas are " << getAlphas());
185
186 // gather all positions
187 position_bins_t position_bins = getAllPositionBins();
188
189 // go through both bins (but with i<j)
190 for (position_bins_t::const_iterator firstbiniter = position_bins.begin();
191 firstbiniter != position_bins.end(); ++firstbiniter) {
192 for (position_bins_t::const_iterator secondbiniter = firstbiniter;
193 secondbiniter != position_bins.end(); ++secondbiniter) {
194 if (firstbiniter == secondbiniter)
195 continue;
196
197 // then in each bin take each position
198 for (SaturatedBond::positions_t::const_iterator firstpositioniter = firstbiniter->begin();
199 firstpositioniter != firstbiniter->end(); ++firstpositioniter) {
200 for (SaturatedBond::positions_t::const_iterator secondpositioniter = secondbiniter->begin();
201 secondpositioniter != secondbiniter->end(); ++secondpositioniter) {
202 // Both iters are from different bins, can never be the same.
203 // We do not penalize over positions from same bin as their positions
204 // are fixed.
205
206 // We penalize by one over the squared distance
207 penalty += 1./(firstpositioniter->DistanceSquared(*secondpositioniter));
208 }
209 }
210 }
211 }
212
213 LOG(4, "DEBUG: Penalty is " << penalty);
214
215 return penalty;
216}
217
218#ifdef HAVE_INLINE
219inline
220#else
221static
222#endif
223size_t calculateHydrogenNo(
224 const SaturatedBond::positions_t::const_iterator &_start,
225 const SaturatedBond::positions_t::const_iterator &_current)
226{
227 const size_t HydrogenNo = std::distance(_start, _current);
228 ASSERT( (HydrogenNo >= 0) && (HydrogenNo <= 2),
229 "calculatePenalityGradient() - hydrogen no not in [0,2].");
230 return HydrogenNo;
231}
232
233std::vector<double> SaturationDistanceMaximizer::calculatePenalityGradient() const
234{
235 // gather all positions
236 const position_bins_t position_bins = getAllPositionBins();
237 LOG(6, "DEBUG: Current alphas are " << getAlphas());
238
239 std::vector<double> gradient(position_bins.size(), 0.);
240
241 std::vector<double>::iterator biniter = gradient.begin();
242 PositionContainers_t::const_iterator bonditer = PositionContainers.begin();
243 position_bins_t::const_iterator firstbiniter = position_bins.begin();
244 // go through each bond/gradient component/alpha
245 for(; biniter != gradient.end(); ++biniter, ++bonditer, ++firstbiniter) {
246 LOG(5, "DEBUG: Current bond is " << **bonditer << ", current bin is #"
247 << std::distance(gradient.begin(), biniter) << ", set of positions are "
248 << *firstbiniter);
249 // skip bin if it belongs to a degree-1 bond (no alpha dependency here)
250 if ((*bonditer)->saturated_bond.getDegree() == 1) {
251 LOG(6, "DEBUG: Skipping due to degree 1.");
252 continue;
253 }
254
255 // in the bin go through each position
256 for (SaturatedBond::positions_t::const_iterator firstpositioniter = firstbiniter->begin();
257 firstpositioniter != firstbiniter->end(); ++firstpositioniter) {
258 LOG(6, "DEBUG: Current position is " << *firstpositioniter);
259
260 // count the hydrogen we are looking at: Each is placed at a different position!
261 const size_t HydrogenNo =
262 calculateHydrogenNo(firstbiniter->begin(), firstpositioniter);
263 const double alpha = (*bonditer)->alpha
264 + (double)HydrogenNo * 2.*M_PI/(double)(*bonditer)->saturated_bond.getDegree();
265 LOG(6, "DEBUG: HydrogenNo is " << HydrogenNo << ", alpha is " << alpha);
266
267 // and go through each other bin
268 for (position_bins_t::const_iterator secondbiniter = position_bins.begin();
269 secondbiniter != position_bins.end(); ++secondbiniter) {
270 // distance between hydrogens in same bin is not affected by the angle
271// if (firstbiniter == secondbiniter)
272// continue;
273
274 // in the other bin go through each position
275 for (SaturatedBond::positions_t::const_iterator secondpositioniter = secondbiniter->begin();
276 secondpositioniter != secondbiniter->end(); ++secondpositioniter) {
277 if (firstpositioniter == secondpositioniter) {
278 LOG(7, "DEBUG: Skipping due to same positions.");
279 continue;
280 }
281 LOG(7, "DEBUG: Second position is " << *secondpositioniter);
282
283 // iters are from different bins, can never be the same
284 const Vector distance = *firstpositioniter - *secondpositioniter;
285 const double temp = -2./pow(distance.NormSquared(), 2);
286 const Vector tempVector =
287 (-sin(alpha)*(*bonditer)->vector_a)
288 +(cos(alpha)*(*bonditer)->vector_b);
289 const double result = temp * (distance.ScalarProduct(tempVector));
290 *biniter += 2.*result; //for x_i and x_j
291 LOG(7, "DEBUG: Total is " << result << ", temp is " << temp << ", tempVector is " << tempVector
292 << ", and bondVector is " << distance << ": bin = " << *biniter);
293 }
294 }
295 }
296 }
297
298 LOG(4, "DEBUG: Gradient of penalty is " << gradient);
299
300 return gradient;
301}
302
Note: See TracBrowser for help on using the repository browser.