ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/oopse-1.0/libmdtools/OOPSEMinimizer.cpp
Revision: 1447
Committed: Fri Jul 30 21:01:35 2004 UTC (19 years, 11 months ago) by gezelter
File size: 16020 byte(s)
Log Message:
Initial import of OOPSE sources into cvs tree

File Contents

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