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