ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/OOPSEMinimizer.cpp
Revision: 1248
Committed: Fri Jun 4 19:30:05 2004 UTC (20 years, 1 month ago) by tim
File size: 16296 byte(s)
Log Message:
constraint algorithm for minimization is working

File Contents

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

Properties

Name Value
svn:executable *