File: steepestDescent.C

package info (click to toggle)
ball 1.5.0%2Bgit20180813.37fc53c-6
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 239,888 kB
  • sloc: cpp: 326,149; ansic: 4,208; python: 2,303; yacc: 1,778; lex: 1,099; xml: 958; sh: 322; makefile: 95
file content (324 lines) | stat: -rw-r--r-- 8,154 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: steepestDescent.C,v 1.27.26.5 2007/05/18 10:58:39 aleru Exp $
//

#include <BALL/MOLMEC/MINIMIZATION/steepestDescent.h>
#include <BALL/MOLMEC/COMMON/forceField.h>
#include <BALL/MOLMEC/COMMON/snapShotManager.h>

#include <limits>

//#define BALL_DEBUG
#undef BALL_DEBUG

using namespace std;

namespace BALL
{
	
	// Default constructor
	 SteepestDescentMinimizer::SteepestDescentMinimizer()
		:	EnergyMinimizer(),
			line_search_()
	{
		line_search_.setMinimizer(*this);
	}
	
	// Copy constructor 
	SteepestDescentMinimizer::SteepestDescentMinimizer 
		(const SteepestDescentMinimizer & minimizer)
		: EnergyMinimizer(minimizer),
			line_search_(minimizer.line_search_)
	{
		line_search_.setMinimizer(*this);
	}
	
	// Constructor initialized with a force field
	SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField& force_field)
		:	EnergyMinimizer(),
			line_search_()
	{
		line_search_.setMinimizer(*this);

		valid_ = setup(force_field);
		
		if (!valid_)
		{
			Log.error() << "SteepestDescentMinimizer: setup failed! " << std::endl;
		}
	}
	
	// Constructor initialized with a force field and a snapshot  manager 
	SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField& force_field, SnapShotManager* ssm)
		:	EnergyMinimizer(),
			line_search_()
	{
		line_search_.setMinimizer(*this);

		valid_ = setup (force_field, ssm);
		
		if (!valid_)
		{
			Log.error() << "SteepestDescentMinimizer: setup failed! " << std::endl;
		}
	}
	
	// Constructor initialized with a force field and a set of options
	SteepestDescentMinimizer::SteepestDescentMinimizer
		(ForceField& force_field, const Options& new_options)
		:	EnergyMinimizer(),
			line_search_()
	{
		line_search_.setMinimizer(*this);

		options = new_options;
		valid_  = setup (force_field, new_options);
		
		if (!valid_)
		{
			Log.error() << "SteepestDescentMinimizer: setup failed! " << endl;
		}
	}
	
	// Constructor initialized with a force field, a snapshot manager, and a set of options
	SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField& force_field,
																										 SnapShotManager* ssm,
																										 const Options& new_options)
		:	EnergyMinimizer(),
			line_search_()
	{
		line_search_.setMinimizer(*this);

		options = new_options;
		valid_  = setup(force_field, ssm, new_options);
		
		if (!valid_)
		{
			Log.error() << "SteepestDescentMinimizer: setup failed! " << std::endl;
		}
	}
	
	// Destructor
	SteepestDescentMinimizer::~SteepestDescentMinimizer()
	{
	}
	
	// Assignment operator
	const SteepestDescentMinimizer& SteepestDescentMinimizer::operator=
			(const SteepestDescentMinimizer& minimizer)
	{
		if (&minimizer != this)
		{
			EnergyMinimizer::operator=(minimizer);
			line_search_      = minimizer.line_search_;
			line_search_.setMinimizer(*this);
		}
		return *this;
	}
	
	// virtual function for the specific setup of derived classes
	bool SteepestDescentMinimizer::specificSetup()
	{
		// Make sure the force field is assigned and valid!
		if (force_field_ == 0 || !force_field_->isValid())
		{
			return false;
		}
		
		// Invalidate the initial gradient in order to ensure
		// its re-evaluation at the start of minimize().
		initial_grad_.invalidate();
		
		return true;
	}
	
	/*  The minimizer optimizes the energy of the system
	*/
	bool SteepestDescentMinimizer::minimize(Size iterations, bool resume)
	{
		aborted_ = false;
		
		// Check for validity of minimizer and force field
		if (!isValid() || getForceField() == 0 || !getForceField()->isValid())
		{
			Log.error() << "SteepestDescentMinimizer: minimizer is not initialized correctly!" << std::endl;
			aborted_ = true;
			return false;
		}
		
		// Make sure we have something worth moving.
		if (getForceField()->getNumberOfMovableAtoms() == 0)
		{
			return true;
		}
		
		// Some aliases
		AtomVector& atoms(const_cast<AtomVector&>(getForceField()->getAtoms()));
		
		// If the run is to be continued, don't reset the iteration counter and the initial step size
		if (!resume)
		{
			// reset the number of iterations for a restart
			setNumberOfIterations(0);
			same_energy_counter_ = 0;
			initial_grad_.invalidate();
			current_grad_.invalidate();
			
			// Obviously, we don't have "old" energies yet, so we initialize it a with 
			// sensible value. We don't need "old" gradients.
			old_energy_ = std::numeric_limits<float>::max();
		}
		Size max_iterations = std::min(getNumberOfIterations() + iterations, getMaxNumberOfIterations());
		
		// Save the current atom positions
		atoms.savePositions();
		bool converged = false;	
		while (!converged && (getNumberOfIterations() < max_iterations))
		{
			// Try to take a new step
			double stp = findStep();
			
			// Check whether we were successful.
			if (stp > 0.0)
			{
				// Use this step as new reference step if findStep was successful
				atoms.savePositions();
			}
			
			// Store the energy, there's no need to store the old gradient
			old_energy_ = initial_energy_;
			
			// Store the current gradient and energy
			storeGradientEnergy();
			
			#ifdef BALL_DEBUG
				Log.info() << "SDM::minimize: end of main: current grad RMS = " << current_grad_.rms << std::endl;
			#endif
			
			// Check for convergence.
			converged = isConverged() || (stp == 0.);
			
			// Increment iteration counter, take snapshots, print energy,
			// update pair lists, and check the same-energy counter
			finishIteration();
			
			if ((!converged) && (stp < 0.))
			{
				// Nasty case: No convergence and the step computation failed.
				// We must give up:-(
				aborted_ = true;
				return false;
			}
			if (Maths::isNan(force_field_->getEnergy()))
			{
				aborted_ = true;
				return false;
			}
			
			if (Maths::isNan(getGradient().rbegin()->x) ||
					Maths::isNan(getGradient().rbegin()->y) ||
					Maths::isNan(getGradient().rbegin()->z)) 
			{
				aborted_ = true;
				return false;
			}
			
			if (abort_by_energy_enabled_)
			{
				if (force_field_->getEnergy() > abort_energy_) 
				{
					aborted_ = true;
					return false;
				}
			}
		}
		
		return converged;
	}
	
	double SteepestDescentMinimizer::findStep()
	{
		// Compute the new direction
		updateDirection();
		
		double step = 0.;
		bool result = line_search_.minimize(step);
		
		if (!result)
		{
			// Something went wrong.
			
			// Some aliases
			AtomVector& atoms(const_cast<AtomVector&>(getForceField()->getAtoms()));
			
			// Just in case: force field update (to update the pair list)
			atoms.resetPositions();
			force_field_->update();
			
			// Compute the initial energy and the initial forces
			initial_energy_ = force_field_->updateEnergy();
			force_field_->updateForces();
			initial_grad_.set(force_field_->getAtoms());
			
			direction_ = initial_grad_;
			direction_.negate();
			direction_.normalize();
			
			Size iter = 0;
			while ((!result) && (iter < 12))
			{
				// No need to assure the maximum displacement here since our
				// line search pays attention to this constraint.
				
				result = line_search_.minimize(step);
			
				if (!result)
				{
					Size n = getForceField()->getNumberOfMovableAtoms();
					for(Size i = 0; i < n; ++i)
					{
						direction_[i] *= 0.5;
					}
					direction_.norm     *= 0.5;
					direction_.rms      *= 0.5;
					direction_.inv_norm *= 2.;
					atoms.resetPositions();
				}
				else
				{
					return step;
				}
				++iter;
			}
			// If we are here something went wrong
			// Not even such scaled steepest descent steps can manage
			// the line search to exit successfully?
			// We must be at a local minimizer...
			step_ = 0.;
		}
		return step;
	}
	
	void SteepestDescentMinimizer::updateDirection()
	{
		// If we do not have a valid gradient, recalculate the gradient, the energy,
		// and the search direction
		if (!initial_grad_.isValid())
		{
			// Compute the initial energy and the initial forces
			updateEnergy();
			updateForces();
			
			// Store them for later use
			storeGradientEnergy();
		}
		
		// The direction is the normalized negative gradient
		direction_ = initial_grad_;
		direction_.negate();
		direction_.normalize();
	}
	
} // namespace BALL