source: src/Dynamics/MinimiseConstrainedPotential.cpp@ 751d7f1

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 751d7f1 was 41a467, checked in by Frederik Heber <heber@…>, 13 years ago

LARGE: config class is now just a tiny container.

  • this was loooooobg overdue. Config.cpp contained remnants from parsing pcp files and much else. Also fragmentation depended on it. Since refactoring of MoleculeListClass and the fragmentation, we don't need it anymore.
  • helper functions ParseForParameters(), LoadMolecule() extracted into new module PcpParser_helper.
  • config class now just contains 4 variables that are generally required (especially IsAngstroem) and they should probably remain with the world.
  • removed some places where config.hpp was no unnecessarily included.
  • Moved ConfigFileBuffer.* over to subfolder src/Parser/ where it rather belongs (associated with PcpParser).
  • Property mode set to 100644
File size: 17.6 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 * MinimiseConstrainedPotential.cpp
10 *
11 * Created on: Feb 23, 2011
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 <gsl/gsl_matrix.h>
23#include <gsl/gsl_vector.h>
24#include <gsl/gsl_linalg.h>
25
26#include "atom.hpp"
27#include "Element/element.hpp"
28#include "CodePatterns/enumeration.hpp"
29#include "CodePatterns/Info.hpp"
30#include "CodePatterns/Verbose.hpp"
31#include "CodePatterns/Log.hpp"
32#include "Fragmentation/ForceMatrix.hpp"
33#include "Helpers/helpers.hpp"
34#include "molecule.hpp"
35#include "LinearAlgebra/Plane.hpp"
36#include "World.hpp"
37
38#include "Dynamics/MinimiseConstrainedPotential.hpp"
39
40
41MinimiseConstrainedPotential::MinimiseConstrainedPotential(
42 molecule::atomSet &_atoms,
43 std::map<atom*, atom *> &_PermutationMap) :
44 atoms(_atoms),
45 PermutationMap(_PermutationMap)
46{}
47
48MinimiseConstrainedPotential::~MinimiseConstrainedPotential()
49{}
50
51double MinimiseConstrainedPotential::operator()(int _startstep, int _endstep, bool IsAngstroem)
52{
53 double Potential, OldPotential, OlderPotential;
54 int round;
55 atom *Sprinter = NULL;
56 DistanceMap::iterator Rider, Strider;
57
58 // set to zero
59 PermutationMap.clear();
60 DoubleList.clear();
61 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
62 DistanceList[*iter].clear();
63 }
64 DistanceList.clear();
65 DistanceIterators.clear();
66 DistanceIterators.clear();
67
68 /// Minimise the potential
69 // set Lagrange multiplier constants
70 PenaltyConstants[0] = 10.;
71 PenaltyConstants[1] = 1.;
72 PenaltyConstants[2] = 1e+7; // just a huge penalty
73 // generate the distance list
74 LOG(1, "Allocating, initializting and filling the distance list ... ");
75 FillDistanceList();
76
77 // create the initial PermutationMap (source -> target)
78 CreateInitialLists();
79
80 // make the PermutationMap injective by checking whether we have a non-zero constants[2] term in it
81 LOG(1, "Making the PermutationMap injective ... ");
82 MakeInjectivePermutation();
83 DoubleList.clear();
84
85 // argument minimise the constrained potential in this injective PermutationMap
86 LOG(1, "Argument minimising the PermutationMap.");
87 OldPotential = 1e+10;
88 round = 0;
89 do {
90 LOG(2, "Starting round " << ++round << ", at current potential " << OldPotential << " ... ");
91 OlderPotential = OldPotential;
92 molecule::atomSet::const_iterator iter;
93 do {
94 iter = atoms.begin();
95 for (; iter != atoms.end(); ++iter) {
96 CalculateDoubleList();
97 PrintPermutationMap();
98 Sprinter = DistanceIterators[(*iter)]->second; // store initial partner
99 Strider = DistanceIterators[(*iter)]; //remember old iterator
100 DistanceIterators[(*iter)] = StepList[(*iter)];
101 if (DistanceIterators[(*iter)] == DistanceList[(*iter)].end()) {// stop, before we run through the list and still on
102 DistanceIterators[(*iter)] == DistanceList[(*iter)].begin();
103 break;
104 }
105 //LOG(2, "Current Walker: " << *(*iter) << " with old/next candidate " << *Sprinter << "/" << *DistanceIterators[(*iter)]->second << ".");
106 // find source of the new target
107 molecule::atomSet::const_iterator runner = atoms.begin();
108 for (; runner != atoms.end(); ++runner) { // find the source whose toes we might be stepping on (Walker's new target should be in use by another already)
109 if (PermutationMap[(*runner)] == DistanceIterators[(*iter)]->second) {
110 //LOG(2, "Found the corresponding owner " << *(*runner) << " to " << *PermutationMap[(*runner)] << ".");
111 break;
112 }
113 }
114 if (runner != atoms.end()) { // we found the other source
115 // then look in its distance list for Sprinter
116 Rider = DistanceList[(*runner)].begin();
117 for (; Rider != DistanceList[(*runner)].end(); Rider++)
118 if (Rider->second == Sprinter)
119 break;
120 if (Rider != DistanceList[(*runner)].end()) { // if we have found one
121 //LOG(2, "Current Other: " << *(*runner) << " with old/next candidate " << *PermutationMap[(*runner)] << "/" << *Rider->second << ".");
122 // exchange both
123 PermutationMap[(*iter)] = DistanceIterators[(*iter)]->second; // put next farther distance into PermutationMap
124 PermutationMap[(*runner)] = Sprinter; // and hand the old target to its respective owner
125 CalculateDoubleList();
126 PrintPermutationMap();
127 // calculate the new potential
128 //LOG(2, "Checking new potential ...");
129 Potential = ConstrainedPotential();
130 if (Potential > OldPotential) { // we made everything worse! Undo ...
131 //LOG(3, "Nay, made the potential worse: " << Potential << " vs. " << OldPotential << "!");
132 //LOG(3, "Setting " << *(*runner) << "'s source to " << *DistanceIterators[(*runner)]->second << ".");
133 // Undo for Runner (note, we haven't moved the iteration yet, we may use this)
134 PermutationMap[(*runner)] = DistanceIterators[(*runner)]->second;
135 // Undo for Walker
136 DistanceIterators[(*iter)] = Strider; // take next farther distance target
137 //LOG(3, "Setting " << *(*iter) << "'s source to " << *DistanceIterators[(*iter)]->second << ".");
138 PermutationMap[(*iter)] = DistanceIterators[(*iter)]->second;
139 } else {
140 DistanceIterators[(*runner)] = Rider; // if successful also move the pointer in the iterator list
141 LOG(3, "Found a better permutation, new potential is " << Potential << " vs." << OldPotential << ".");
142 OldPotential = Potential;
143 }
144 if (Potential > PenaltyConstants[2]) {
145 ELOG(1, "The two-step permutation procedure did not maintain injectivity!");
146 exit(255);
147 }
148 } else {
149 ELOG(1, **runner << " was not the owner of " << *Sprinter << "!");
150 exit(255);
151 }
152 } else {
153 PermutationMap[(*iter)] = DistanceIterators[(*iter)]->second; // new target has no source!
154 }
155 StepList[(*iter)]++; // take next farther distance target
156 }
157 } while (++iter != atoms.end());
158 } while ((OlderPotential - OldPotential) > 1e-3);
159 LOG(1, "done.");
160
161
162 return ConstrainedPotential();
163};
164
165void MinimiseConstrainedPotential::FillDistanceList()
166{
167 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
168 for (molecule::atomSet::const_iterator runner = atoms.begin(); runner != atoms.end(); ++runner) {
169 DistanceList[(*iter)].insert( DistancePair((*iter)->getPositionAtStep(startstep).distance((*runner)->getPositionAtStep(endstep)), (*runner)) );
170 }
171 }
172};
173
174void MinimiseConstrainedPotential::CreateInitialLists()
175{
176 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
177 StepList[(*iter)] = DistanceList[(*iter)].begin(); // stores the step to the next iterator that could be a possible next target
178 PermutationMap[(*iter)] = DistanceList[(*iter)].begin()->second; // always pick target with the smallest distance
179 DoubleList[DistanceList[(*iter)].begin()->second]++; // increase this target's source count (>1? not injective)
180 DistanceIterators[(*iter)] = DistanceList[(*iter)].begin(); // and remember which one we picked
181 LOG(2, **iter << " starts with distance " << DistanceList[(*iter)].begin()->first << ".");
182 }
183};
184
185void MinimiseConstrainedPotential::MakeInjectivePermutation()
186{
187 molecule::atomSet::const_iterator iter = atoms.begin();
188 DistanceMap::iterator NewBase;
189 double Potential = fabs(ConstrainedPotential());
190
191 if (atoms.empty()) {
192 ELOG(1, "Molecule is empty.");
193 return;
194 }
195 while ((Potential) > PenaltyConstants[2]) {
196 CalculateDoubleList();
197 PrintPermutationMap();
198 iter++;
199 if (iter == atoms.end()) // round-robin at the end
200 iter = atoms.begin();
201 if (DoubleList[DistanceIterators[(*iter)]->second] <= 1) // no need to make those injective that aren't
202 continue;
203 // now, try finding a new one
204 Potential = TryNextNearestNeighbourForInjectivePermutation((*iter), Potential);
205 }
206 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
207 // now each single entry in the DoubleList should be <=1
208 if (DoubleList[*iter] > 1) {
209 ELOG(0, "Failed to create an injective PermutationMap!");
210 performCriticalExit();
211 }
212 }
213 LOG(1, "done.");
214};
215
216unsigned int MinimiseConstrainedPotential::CalculateDoubleList()
217{
218 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter)
219 DoubleList[*iter] = 0;
220 unsigned int doubles = 0;
221 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter)
222 DoubleList[ PermutationMap[*iter] ]++;
223 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter)
224 if (DoubleList[*iter] > 1)
225 doubles++;
226 if (doubles >0)
227 LOG(2, "Found " << doubles << " Doubles.");
228 return doubles;
229};
230
231void MinimiseConstrainedPotential::PrintPermutationMap() const
232{
233 stringstream zeile1, zeile2;
234 int doubles = 0;
235 zeile1 << "PermutationMap: ";
236 zeile2 << " ";
237 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
238 zeile1 << (*iter)->getName() << " ";
239 zeile2 << (PermutationMap[*iter])->getName() << " ";
240 }
241 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
242 std::map<atom *, unsigned int>::const_iterator value_iter = DoubleList.find(*iter);
243 if (value_iter->second > (unsigned int)1)
244 doubles++;
245 }
246 if (doubles >0)
247 LOG(2, "Found " << doubles << " Doubles.");
248// LOG(2, zeile1.str() << endl << zeile2.str());
249};
250
251double MinimiseConstrainedPotential::ConstrainedPotential()
252{
253 double tmp = 0.;
254 double result = 0.;
255 // go through every atom
256 atom *Runner = NULL;
257 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
258 // first term: distance to target
259 Runner = PermutationMap[(*iter)]; // find target point
260 tmp = ((*iter)->getPositionAtStep(startstep).distance(Runner->getPositionAtStep(endstep)));
261 tmp *= IsAngstroem ? 1. : 1./AtomicLengthToAngstroem;
262 result += PenaltyConstants[0] * tmp;
263 //LOG(4, "Adding " << tmp*constants[0] << ".");
264
265 // second term: sum of distances to other trajectories
266 result += SumDistanceOfTrajectories((*iter));
267
268 // third term: penalty for equal targets
269 result += PenalizeEqualTargets((*iter));
270 }
271
272 return result;
273};
274
275double MinimiseConstrainedPotential::TryNextNearestNeighbourForInjectivePermutation(atom *Walker, double &OldPotential)
276{
277 double Potential = 0;
278 DistanceMap::iterator NewBase = DistanceIterators[Walker]; // store old base
279 do {
280 NewBase++; // take next further distance in distance to targets list that's a target of no one
281 } while ((DoubleList[NewBase->second] != 0) && (NewBase != DistanceList[Walker].end()));
282 if (NewBase != DistanceList[Walker].end()) {
283 PermutationMap[Walker] = NewBase->second;
284 Potential = fabs(ConstrainedPotential());
285 if (Potential > OldPotential) { // undo
286 PermutationMap[Walker] = DistanceIterators[Walker]->second;
287 } else { // do
288 DoubleList[DistanceIterators[Walker]->second]--; // decrease the old entry in the doubles list
289 DoubleList[NewBase->second]++; // increase the old entry in the doubles list
290 DistanceIterators[Walker] = NewBase;
291 OldPotential = Potential;
292 LOG(3, "Found a new permutation, new potential is " << OldPotential << ".");
293 }
294 }
295 return Potential;
296};
297
298double MinimiseConstrainedPotential::PenalizeEqualTargets(atom *Walker)
299{
300 double result = 0.;
301 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
302 if ((PermutationMap[Walker] == PermutationMap[(*iter)]) && (Walker < (*iter))) {
303// atom *Sprinter = PermutationMap[Walker->nr];
304// if (DoLog(0)) {
305// std::stringstream output;
306// output << *Walker << " and " << *(*iter) << " are heading to the same target at ";
307// output << Sprinter->getPosition(endstep);
308// output << ", penalting.";
309// LOG(0, output.str());
310// }
311 result += PenaltyConstants[2];
312 //LOG(4, "INFO: Adding " << constants[2] << ".");
313 }
314 }
315 return result;
316};
317
318double MinimiseConstrainedPotential::SumDistanceOfTrajectories(atom *Walker)
319{
320 gsl_matrix *A = gsl_matrix_alloc(NDIM,NDIM);
321 gsl_vector *x = gsl_vector_alloc(NDIM);
322 atom *Sprinter = NULL;
323 Vector trajectory1, trajectory2, normal, TestVector;
324 double Norm1, Norm2, tmp, result = 0.;
325
326 for (molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
327 if ((*iter) == Walker) // hence, we only go up to the Walker, not beyond (similar to i=0; i<j; i++)
328 break;
329 // determine normalized trajectories direction vector (n1, n2)
330 Sprinter = PermutationMap[Walker]; // find first target point
331 trajectory1 = Sprinter->getPositionAtStep(endstep) - Walker->getPositionAtStep(startstep);
332 trajectory1.Normalize();
333 Norm1 = trajectory1.Norm();
334 Sprinter = PermutationMap[(*iter)]; // find second target point
335 trajectory2 = Sprinter->getPositionAtStep(endstep) - (*iter)->getPositionAtStep(startstep);
336 trajectory2.Normalize();
337 Norm2 = trajectory1.Norm();
338 // check whether either is zero()
339 if ((Norm1 < MYEPSILON) && (Norm2 < MYEPSILON)) {
340 tmp = Walker->getPositionAtStep(startstep).distance((*iter)->getPositionAtStep(startstep));
341 } else if (Norm1 < MYEPSILON) {
342 Sprinter = PermutationMap[Walker]; // find first target point
343 trajectory1 = Sprinter->getPositionAtStep(endstep) - (*iter)->getPositionAtStep(startstep);
344 trajectory2 *= trajectory1.ScalarProduct(trajectory2); // trajectory2 is scaled to unity, hence we don't need to divide by anything
345 trajectory1 -= trajectory2; // project the part in norm direction away
346 tmp = trajectory1.Norm(); // remaining norm is distance
347 } else if (Norm2 < MYEPSILON) {
348 Sprinter = PermutationMap[(*iter)]; // find second target point
349 trajectory2 = Sprinter->getPositionAtStep(endstep) - Walker->getPositionAtStep(startstep); // copy second offset
350 trajectory1 *= trajectory2.ScalarProduct(trajectory1); // trajectory1 is scaled to unity, hence we don't need to divide by anything
351 trajectory2 -= trajectory1; // project the part in norm direction away
352 tmp = trajectory2.Norm(); // remaining norm is distance
353 } else if ((fabs(trajectory1.ScalarProduct(trajectory2)/Norm1/Norm2) - 1.) < MYEPSILON) { // check whether they're linear dependent
354// std::stringstream output;
355// output << "Both trajectories of " << *Walker << " and " << *Runner << " are linear dependent: ";
356// output << trajectory1 << " and " << trajectory2;
357// LOG(3, output.str());
358 tmp = Walker->getPositionAtStep(startstep).distance((*iter)->getPositionAtStep(startstep));
359// LOG(0, " with distance " << tmp << ".");
360 } else { // determine distance by finding minimum distance
361// std::stringstream output;
362// output "Both trajectories of " << *Walker << " and " << *(*iter) << " are linear independent -- ";
363// output "First Trajectory: " << trajectory1 << ". Second Trajectory: " << trajectory2);
364// LOG(3, output.str());
365 // determine normal vector for both
366 normal = Plane(trajectory1, trajectory2,0).getNormal();
367 // print all vectors for debugging
368// LOG(3, "INFO: Normal vector in between: " << normal);
369 // setup matrix
370 for (int i=NDIM;i--;) {
371 gsl_matrix_set(A, 0, i, trajectory1[i]);
372 gsl_matrix_set(A, 1, i, trajectory2[i]);
373 gsl_matrix_set(A, 2, i, normal[i]);
374 gsl_vector_set(x,i, (Walker->getPositionAtStep(startstep)[i] - (*iter)->getPositionAtStep(startstep)[i]));
375 }
376 // solve the linear system by Householder transformations
377 gsl_linalg_HH_svx(A, x);
378 // distance from last component
379 tmp = gsl_vector_get(x,2);
380// LOG(0, " with distance " << tmp << ".");
381 // test whether we really have the intersection (by checking on c_1 and c_2)
382 trajectory1.Scale(gsl_vector_get(x,0));
383 trajectory2.Scale(gsl_vector_get(x,1));
384 normal.Scale(gsl_vector_get(x,2));
385 TestVector = (*iter)->getPositionAtStep(startstep) + trajectory2 + normal
386 - (Walker->getPositionAtStep(startstep) + trajectory1);
387 if (TestVector.Norm() < MYEPSILON) {
388// LOG(2, "Test: ok.\tDistance of " << tmp << " is correct.");
389 } else {
390// LOG(2, "Test: failed.\tIntersection is off by " << TestVector << ".");
391 }
392 }
393 // add up
394 tmp *= IsAngstroem ? 1. : 1./AtomicLengthToAngstroem;
395 if (fabs(tmp) > MYEPSILON) {
396 result += PenaltyConstants[1] * 1./tmp;
397 //LOG(4, "Adding " << 1./tmp*constants[1] << ".");
398 }
399 }
400 return result;
401};
402
403void MinimiseConstrainedPotential::EvaluateConstrainedForces(ForceMatrix *Force)
404{
405 double constant = 10.;
406
407 /// evaluate forces (only the distance to target dependent part) with the final PermutationMap
408 LOG(1, "Calculating forces and adding onto ForceMatrix ... ");
409 for(molecule::atomSet::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
410 atom *Sprinter = PermutationMap[(*iter)];
411 // set forces
412 for (int i=NDIM;i++;)
413 Force->Matrix[0][(*iter)->getNr()][5+i] += 2.*constant*sqrt((*iter)->getPositionAtStep(startstep).distance(Sprinter->getPositionAtStep(endstep)));
414 }
415 LOG(1, "done.");
416};
417
Note: See TracBrowser for help on using the repository browser.