ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/OOPSEMinimizer.cpp
Revision: 1330
Committed: Fri Jul 16 16:29:44 2004 UTC (19 years, 11 months ago) by gezelter
File size: 16331 byte(s)
Log Message:
Minor changes

File Contents

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

Properties

Name Value
svn:executable *