ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/OOPSEMinimizer.cpp
Revision: 1064
Committed: Tue Feb 24 15:44:45 2004 UTC (20 years, 4 months ago) by tim
File size: 15771 byte(s)
Log Message:
Using inherit instead of compose to implement Minimizer
both versions are working

File Contents

# Content
1 #include <math.h>
2 #include "OOPSEMinimizer.hpp"
3
4 OOPSEMinimizer::OOPSEMinimizer( SimInfo *theInfo, ForceFields* the_ff ,
5 MinimizerParameterSet * param)
6 :RealIntegrator(theInfo, the_ff), bVerbose(false), bShake(true){
7
8 atoms = info->atoms;
9
10 tStats = new Thermo(info);
11 dumpOut = new DumpWriter(info);
12 statOut = new StatWriter(info);
13
14 paramSet = param;
15
16 calcDim();
17
18 curX = getCoor();
19 curG.resize(ndim);
20
21 }
22
23 OOPSEMinimizer::~OOPSEMinimizer(){
24 delete tStats;
25 delete dumpOut;
26 delete statOut;
27 delete paramSet;
28 }
29
30 void OOPSEMinimizer::calcEnergyGradient(vector<double>& x, vector<double>& grad,
31 double& energy, int& status){
32
33 DirectionalAtom* dAtom;
34 int index;
35 double force[3];
36 double dAtomGrad[6];
37 int shakeStatus;
38
39 setCoor(x);
40
41 if (nConstrained && bShake){
42 shakeStatus = shakeR();
43 }
44
45 calcForce(1, 1);
46
47 if (nConstrained && bShake){
48 shakeStatus |= shakeF();
49 }
50
51 x = getCoor();
52
53
54 index = 0;
55
56 for(int i = 0; i < nAtoms; i++){
57
58 if(atoms[i]->isDirectional()){
59 dAtom = (DirectionalAtom*) atoms[i];
60 dAtom->getGrad(dAtomGrad);
61
62 //gradient is equal to -f
63 grad[index++] = -dAtomGrad[0];
64 grad[index++] = -dAtomGrad[1];
65 grad[index++] = -dAtomGrad[2];
66 grad[index++] = -dAtomGrad[3];
67 grad[index++] = -dAtomGrad[4];
68 grad[index++] = -dAtomGrad[5];
69
70 }
71 else{
72 atoms[i]->getFrc(force);
73
74 grad[index++] = -force[0];
75 grad[index++] = -force[1];
76 grad[index++] = -force[2];
77
78 }
79
80 }
81
82 energy = tStats->getPotential();
83
84 status = shakeStatus;
85 }
86
87 /**
88 *
89 */
90
91 void OOPSEMinimizer::setCoor(vector<double>& x){
92
93 DirectionalAtom* dAtom;
94 int index;
95 double position[3];
96 double eulerAngle[3];
97
98
99 index = 0;
100
101 for(int i = 0; i < nAtoms; i++){
102
103 position[0] = x[index++];
104 position[1] = x[index++];
105 position[2] = x[index++];
106
107 atoms[i]->setPos(position);
108
109 if (atoms[i]->isDirectional()){
110 dAtom = (DirectionalAtom*) atoms[i];
111
112 eulerAngle[0] = x[index++];
113 eulerAngle[1] = x[index++];
114 eulerAngle[2] = x[index++];
115
116 dAtom->setEuler(eulerAngle[0], eulerAngle[1], eulerAngle[2]);
117
118 }
119
120 }
121
122 }
123
124 /**
125 *
126 */
127 vector<double> OOPSEMinimizer::getCoor(){
128
129 DirectionalAtom* dAtom;
130 int index;
131 double position[3];
132 double eulerAngle[3];
133 vector<double> x;
134
135 x.resize(getDim());
136
137 index = 0;
138
139 for(int i = 0; i < nAtoms; i++){
140 atoms[i]->getPos(position);
141
142 x[index++] = position[0];
143 x[index++] = position[1];
144 x[index++] = position[2];
145
146 if (atoms[i]->isDirectional()){
147 dAtom = (DirectionalAtom*) atoms[i];
148 dAtom->getEulerAngles(eulerAngle);
149
150 x[index++] = eulerAngle[0];
151 x[index++] = eulerAngle[1];
152 x[index++] = eulerAngle[2];
153
154 }
155
156 }
157
158 return x;
159
160 }
161
162 int OOPSEMinimizer::shakeR(){
163 int i, j;
164 int done;
165 double posA[3], posB[3];
166 double velA[3], velB[3];
167 double pab[3];
168 double rab[3];
169 int a, b, ax, ay, az, bx, by, bz;
170 double rma, rmb;
171 double dx, dy, dz;
172 double rpab;
173 double rabsq, pabsq, rpabsq;
174 double diffsq;
175 double gab;
176 int iteration;
177
178 for (i = 0; i < nAtoms; i++){
179 moving[i] = 0;
180 moved[i] = 1;
181 }
182
183 iteration = 0;
184 done = 0;
185 while (!done && (iteration < maxIteration)){
186 done = 1;
187 for (i = 0; i < nConstrained; i++){
188 a = constrainedA[i];
189 b = constrainedB[i];
190
191 ax = (a * 3) + 0;
192 ay = (a * 3) + 1;
193 az = (a * 3) + 2;
194
195 bx = (b * 3) + 0;
196 by = (b * 3) + 1;
197 bz = (b * 3) + 2;
198
199 if (moved[a] || moved[b]){
200 atoms[a]->getPos(posA);
201 atoms[b]->getPos(posB);
202
203 for (j = 0; j < 3; j++)
204 pab[j] = posA[j] - posB[j];
205
206 //periodic boundary condition
207
208 info->wrapVector(pab);
209
210 pabsq = pab[0] * pab[0] + pab[1] * pab[1] + pab[2] * pab[2];
211
212 rabsq = constrainedDsqr[i];
213 diffsq = rabsq - pabsq;
214
215 // the original rattle code from alan tidesley
216 if (fabs(diffsq) > (tol * rabsq * 2)){
217 rab[0] = oldPos[ax] - oldPos[bx];
218 rab[1] = oldPos[ay] - oldPos[by];
219 rab[2] = oldPos[az] - oldPos[bz];
220
221 info->wrapVector(rab);
222
223 rpab = rab[0] * pab[0] + rab[1] * pab[1] + rab[2] * pab[2];
224
225 rpabsq = rpab * rpab;
226
227
228 if (rpabsq < (rabsq * -diffsq)){
229 #ifdef IS_MPI
230 a = atoms[a]->getGlobalIndex();
231 b = atoms[b]->getGlobalIndex();
232 #endif //is_mpi
233 //cerr << "Waring: constraint failure" << endl;
234 gab = sqrt(rabsq/pabsq);
235 rab[0] = (posA[0] - posB[0])*gab;
236 rab[1]= (posA[1] - posB[1])*gab;
237 rab[2] = (posA[2] - posB[2])*gab;
238
239 info->wrapVector(rab);
240
241 rpab = rab[0] * pab[0] + rab[1] * pab[1] + rab[2] * pab[2];
242
243 }
244
245 //rma = 1.0 / atoms[a]->getMass();
246 //rmb = 1.0 / atoms[b]->getMass();
247 rma = 1.0;
248 rmb =1.0;
249
250 gab = diffsq / (2.0 * (rma + rmb) * rpab);
251
252 dx = rab[0] * gab;
253 dy = rab[1] * gab;
254 dz = rab[2] * gab;
255
256 posA[0] += rma * dx;
257 posA[1] += rma * dy;
258 posA[2] += rma * dz;
259
260 atoms[a]->setPos(posA);
261
262 posB[0] -= rmb * dx;
263 posB[1] -= rmb * dy;
264 posB[2] -= rmb * dz;
265
266 atoms[b]->setPos(posB);
267
268 moving[a] = 1;
269 moving[b] = 1;
270 done = 0;
271 }
272 }
273 }
274
275 for (i = 0; i < nAtoms; i++){
276 moved[i] = moving[i];
277 moving[i] = 0;
278 }
279
280 iteration++;
281 }
282
283 if (!done){
284 cerr << "Waring: can not constraint within maxIteration" << endl;
285 return -1;
286 }
287 else
288 return 1;
289 }
290
291
292 //remove constraint force along the bond direction
293 int OOPSEMinimizer::shakeF(){
294 int i, j;
295 int done;
296 double posA[3], posB[3];
297 double frcA[3], frcB[3];
298 double rab[3], fpab[3];
299 int a, b, ax, ay, az, bx, by, bz;
300 double rma, rmb;
301 double rvab;
302 double gab;
303 double rabsq;
304 double rfab;
305 int iteration;
306
307 for (i = 0; i < nAtoms; i++){
308 moving[i] = 0;
309 moved[i] = 1;
310 }
311
312 done = 0;
313 iteration = 0;
314 while (!done && (iteration < maxIteration)){
315 done = 1;
316
317 for (i = 0; i < nConstrained; i++){
318 a = constrainedA[i];
319 b = constrainedB[i];
320
321 ax = (a * 3) + 0;
322 ay = (a * 3) + 1;
323 az = (a * 3) + 2;
324
325 bx = (b * 3) + 0;
326 by = (b * 3) + 1;
327 bz = (b * 3) + 2;
328
329 if (moved[a] || moved[b]){
330
331 atoms[a]->getPos(posA);
332 atoms[b]->getPos(posB);
333
334 for (j = 0; j < 3; j++)
335 rab[j] = posA[j] - posB[j];
336
337 info->wrapVector(rab);
338
339 atoms[a]->getFrc(frcA);
340 atoms[b]->getFrc(frcB);
341
342 //rma = 1.0 / atoms[a]->getMass();
343 //rmb = 1.0 / atoms[b]->getMass();
344 rma = 1.0;
345 rmb = 1.0;
346
347
348 fpab[0] = frcA[0] * rma - frcB[0] * rmb;
349 fpab[1] = frcA[1] * rma - frcB[1] * rmb;
350 fpab[2] = frcA[2] * rma - frcB[2] * rmb;
351
352
353 gab=fpab[0] * fpab[0] + fpab[1] * fpab[1] + fpab[2] * fpab[2];
354
355 if (gab < 1.0)
356 gab = 1.0;
357
358 rabsq = rab[0] * rab[0] + rab[1] * rab[1] + rab[2] * rab[2];
359 rfab = rab[0] * fpab[0] + rab[1] * fpab[1] + rab[2] * fpab[2];
360
361 if (fabs(rfab) > sqrt(rabsq*gab) * 0.00001){
362
363 gab = -rfab /(rabsq*(rma + rmb));
364
365 frcA[0] = rab[0] * gab;
366 frcA[1] = rab[1] * gab;
367 frcA[2] = rab[2] * gab;
368
369 atoms[a]->addFrc(frcA);
370
371
372 frcB[0] = -rab[0] * gab;
373 frcB[1] = -rab[1] * gab;
374 frcB[2] = -rab[2] * gab;
375
376 atoms[b]->addFrc(frcB);
377
378 moving[a] = 1;
379 moving[b] = 1;
380 done = 0;
381 }
382 }
383 }
384
385 for (i = 0; i < nAtoms; i++){
386 moved[i] = moving[i];
387 moving[i] = 0;
388 }
389
390 iteration++;
391 }
392
393 if (!done){
394 cerr << "Waring: can not constraint within maxIteration" << endl;
395 return -1;
396 }
397 else
398 return 1;
399 }
400
401 //calculate the value of object function
402 void OOPSEMinimizer::calcF(){
403 calcEnergyGradient(curX, curG, curF, egEvalStatus);
404 }
405
406 void OOPSEMinimizer::calcF(vector<double>& x, double&f, int& status){
407 vector<double> tempG;
408 tempG.resize(x.size());
409
410 calcEnergyGradient(x, tempG, f, status);
411 }
412
413 //calculate the gradient
414 void OOPSEMinimizer::calcG(){
415 calcEnergyGradient(curX, curG, curF, egEvalStatus);
416 }
417
418 void OOPSEMinimizer::calcG(vector<double>& x, vector<double>& g, double& f, int& status){
419 calcEnergyGradient(x, g, f, status);
420 }
421
422 void OOPSEMinimizer::calcDim(){
423 DirectionalAtom* dAtom;
424
425 ndim = 0;
426
427 for(int i = 0; i < nAtoms; i++){
428 ndim += 3;
429 if (atoms[i]->isDirectional())
430 ndim += 3;
431 }
432 }
433
434 void OOPSEMinimizer::setX(vector < double > & x){
435
436 if (x.size() != ndim && bVerbose){
437 //sprintf(painCave.errMsg,
438 // "OOPSEMinimizer Error: dimesion of x and curX does not match\n");
439 // painCave.isFatal = 1;
440 // simError();
441 }
442
443 curX = x;
444 }
445
446 void OOPSEMinimizer::setG(vector < double > & g){
447
448 if (g.size() != ndim && bVerbose){
449 //sprintf(painCave.errMsg,
450 // "OOPSEMinimizer Error: dimesion of g and curG does not match\n");
451 // painCave.isFatal = 1;
452 //simError();
453 }
454
455 curG = g;
456 }
457
458 void OOPSEMinimizer::writeOut(vector<double>& x, double iter){
459
460 setX(x);
461
462 calcG();
463
464 dumpOut->writeDump(iter);
465 statOut->writeStat(iter);
466 }
467
468
469 void OOPSEMinimizer::printMinimizerInfo(){
470 cout << "--------------------------------------------------------------------" << endl;
471 cout << minimizerName << endl;
472 cout << "minimization parameter set" << endl;
473 cout << "function tolerance = " << paramSet->getFTol() << endl;
474 cout << "gradient tolerance = " << paramSet->getGTol() << endl;
475 cout << "step tolerance = "<< paramSet->getFTol() << endl;
476 cout << "absolute gradient tolerance = " << endl;
477 cout << "max iteration = " << paramSet->getMaxIteration() << endl;
478 cout << "max line search iteration = " << paramSet->getLineSearchMaxIteration() <<endl;
479 cout << "shake algorithm = " << bShake << endl;
480 cout << "--------------------------------------------------------------------" << endl;
481
482 }
483
484 /**
485 * In thoery, we need to find the minimum along the search direction
486 * However, function evaluation is too expensive. I
487 * At the very begining of the problem, we check the search direction and make sure
488 * it is a descent direction
489 * we will compare the energy of two end points,
490 * if the right end point has lower energy, we just take it
491 *
492 *
493 *
494 */
495
496 int OOPSEMinimizer::doLineSearch(vector<double>& direction, double stepSize){
497 vector<double> xa;
498 vector<double> xb;
499 vector<double> xc;
500 vector<double> ga;
501 vector<double> gb;
502 vector<double> gc;
503 double fa;
504 double fb;
505 double fc;
506 double a;
507 double b;
508 double c;
509 int status;
510 double initSlope;
511 double slopeA;
512 double slopeB;
513 double slopeC;
514 bool foundLower;
515 int iter;
516 int maxLSIter;
517 double mu;
518 double eta;
519 double ftol;
520
521 xa.resize(ndim);
522 xb.resize(ndim);
523 xc.resize(ndim);
524
525 ga.resize(ndim);
526 gb.resize(ndim);
527 gc.resize(ndim);
528
529 a = 0.0;
530 fa = curF;
531 xa = curX;
532 ga = curG;
533 c = a + stepSize;
534 ftol = paramSet->getFTol();
535
536 //calculate the derivative at a = 0
537 for (size_t i = 0; i < ndim; i++)
538 slopeA += curG[i]*direction[i];
539
540 initSlope = slopeA;
541
542 // if going uphill, use negative gradient as searching direction
543 if (slopeA > 0) {
544
545 if (bVerbose){
546 cout << "LineSearch Warning: initial searching direction is not a descent searching direction, "
547 << " use negative gradient instead. Therefore, finding a smaller vaule of function "
548 << " is guaranteed"
549 << endl;
550 }
551
552 for (size_t i = 0; i < ndim; i++)
553 direction[i] = -curG[i];
554
555 for (size_t i = 0; i < ndim; i++)
556 slopeA += curG[i]*direction[i];
557
558 initSlope = slopeA;
559 }
560
561 // Take a trial step
562 for(size_t i = 0; i < ndim; i++)
563 xc[i] = curX[i] + direction[i] * c;
564
565 calcG(xc, gc, fc, status);
566
567 if (status < 0){
568 if (bVerbose)
569 cerr << "Function Evaluation Error" << endl;
570 }
571
572 //calculate the derivative at c
573 slopeC = 0;
574 for (size_t i = 0; i < ndim; i++)
575 slopeC += gc[i]*direction[i];
576
577 // found a lower point
578 if (fc < fa) {
579 curX = xc;
580 curG = gc;
581 curF = fc;
582 return LS_SUCCEED;
583 }
584 else {
585
586 if (slopeC > 0)
587 stepSize *= 0.618034;
588 }
589
590 maxLSIter = paramSet->getLineSearchMaxIteration();
591
592 iter = 0;
593
594 do {
595 // Select a new trial point.
596 // If the derivatives at points a & c have different sign we use cubic interpolate
597 //if (slopeC > 0){
598 eta = 3 *(fa -fc) /(c - a) + slopeA + slopeC;
599 mu = sqrt(eta * eta - slopeA * slopeC);
600 b = a + (c - a) * (1 - (slopeC + mu - eta) /(slopeC - slopeA + 2 * mu));
601 //}
602
603 // Take a trial step to this new point - new coords in xb
604 for(size_t i = 0; i < ndim; i++)
605 xb[i] = curX[i] + direction[i] * b;
606
607 //function evaluation
608 calcG(xb, gb, fb, status);
609
610 if (status < 0){
611 if (bVerbose)
612 cerr << "Function Evaluation Error" << endl;
613 }
614
615 //calculate the derivative at c
616 slopeB = 0;
617 for (size_t i = 0; i < ndim; i++)
618 slopeB += gb[i]*direction[i];
619
620 //Amijo Rule to stop the line search
621 if (fb <= curF + initSlope * ftol * b) {
622 curF = fb;
623 curX = xb;
624 curG = gb;
625 return LS_SUCCEED;
626 }
627
628 if (slopeB <0 && fb < fa) {
629 //replace a by b
630 fa = fb;
631 a = b;
632 slopeA = slopeB;
633
634 // swap coord a/b
635 std::swap(xa, xb);
636 std::swap(ga, gb);
637 }
638 else {
639 //replace c by b
640 fc = fb;
641 c = b;
642 slopeC = slopeB;
643
644 // swap coord b/c
645 std::swap(gb, gc);
646 std::swap(xb, xc);
647 }
648
649
650 iter++;
651 } while((fb > fa || fb > fc) && (iter < maxLSIter));
652
653 if(fb < curF || iter >= maxLSIter) {
654 //could not find a lower value, we might just go uphill.
655 return LS_ERROR;
656 }
657
658 //select the end point
659
660 if (fa <= fc) {
661 curX = xa;
662 curG = ga;
663 curF = fa;
664 }
665 else {
666 curX = xc;
667 curG = gc;
668 curF = fc;
669 }
670
671 return LS_SUCCEED;
672
673 }
674
675 void OOPSEMinimizer::minimize(){
676
677 int convgStatus;
678 int stepStatus;
679 int maxIter;
680 //int resetFrq;
681 //int nextResetIter;
682 int writeFrq;
683 int nextWriteIter;
684
685 if (bVerbose)
686 printMinimizerInfo();
687
688 init();
689
690 //resetFrq = paramSet->getResetFrq();
691 //nextResetIter = resetFrq;
692
693 writeFrq = paramSet->getWriteFrq();
694 nextWriteIter = writeFrq;
695
696 maxIter = paramSet->getMaxIteration();
697
698 for (curIter = 1; curIter <= maxIter; curIter++){
699
700 stepStatus = step();
701
702 if (stepStatus < 0){
703 saveResult();
704 minStatus = MIN_LSERROR;
705 cerr << "OOPSEMinimizer Error: line search error, please try a small stepsize" << endl;
706 return;
707 }
708
709 if (curIter == nextWriteIter){
710 nextWriteIter += writeFrq;
711 writeOut(curX, curIter);
712 }
713
714 //if (curIter == nextResetIter){
715 // reset();
716 // nextResetIter += resetFrq;
717 //}
718
719 convgStatus = checkConvg();
720
721 if (convgStatus > 0){
722 saveResult();
723 minStatus = MIN_CONVERGE;
724 return;
725 }
726
727 prepareStep();
728
729 }
730
731
732 if (bVerbose) {
733 cout << "OOPSEMinimizer Warning: "
734 << minimizerName << " algorithm did not converge within "
735 << maxIter << " iteration" << endl;
736 }
737 minStatus = MIN_MAXITER;
738 saveResult();
739
740 }

Properties

Name Value
svn:executable *