ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/OOPSEMinimizer.cpp
Revision: 1074
Committed: Mon Mar 1 20:01:50 2004 UTC (20 years, 4 months ago) by tim
File size: 15989 byte(s)
Log Message:
Adding zsub, a program which can be used to replace atom type for zconstraint into OOPSE

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 preMove();
22 }
23
24 OOPSEMinimizer::~OOPSEMinimizer(){
25 delete tStats;
26 delete dumpOut;
27 delete statOut;
28 delete paramSet;
29 }
30
31 void OOPSEMinimizer::calcEnergyGradient(vector<double>& x, vector<double>& grad,
32 double& energy, int& status){
33
34 DirectionalAtom* dAtom;
35 int index;
36 double force[3];
37 double dAtomGrad[6];
38 int shakeStatus;
39
40 setCoor(x);
41
42 if (nConstrained && bShake){
43 shakeStatus = shakeR();
44 }
45
46 calcForce(1, 1);
47
48 if (nConstrained && bShake){
49 shakeStatus |= shakeF();
50 }
51
52 x = getCoor();
53
54
55 index = 0;
56
57 for(int i = 0; i < nAtoms; i++){
58
59 if(atoms[i]->isDirectional()){
60 dAtom = (DirectionalAtom*) atoms[i];
61 dAtom->getGrad(dAtomGrad);
62
63 //gradient is equal to -f
64 grad[index++] = -dAtomGrad[0];
65 grad[index++] = -dAtomGrad[1];
66 grad[index++] = -dAtomGrad[2];
67 grad[index++] = -dAtomGrad[3];
68 grad[index++] = -dAtomGrad[4];
69 grad[index++] = -dAtomGrad[5];
70
71 }
72 else{
73 atoms[i]->getFrc(force);
74
75 grad[index++] = -force[0];
76 grad[index++] = -force[1];
77 grad[index++] = -force[2];
78
79 }
80
81 }
82
83 energy = tStats->getPotential();
84
85 status = shakeStatus;
86 }
87
88 /**
89 *
90 */
91
92 void OOPSEMinimizer::setCoor(vector<double>& x){
93
94 DirectionalAtom* dAtom;
95 int index;
96 double position[3];
97 double eulerAngle[3];
98
99
100 index = 0;
101
102 for(int i = 0; i < nAtoms; i++){
103
104 position[0] = x[index++];
105 position[1] = x[index++];
106 position[2] = x[index++];
107
108 atoms[i]->setPos(position);
109
110 if (atoms[i]->isDirectional()){
111 dAtom = (DirectionalAtom*) atoms[i];
112
113 eulerAngle[0] = x[index++];
114 eulerAngle[1] = x[index++];
115 eulerAngle[2] = x[index++];
116
117 dAtom->setEuler(eulerAngle[0], eulerAngle[1], eulerAngle[2]);
118
119 }
120
121 }
122
123 }
124
125 /**
126 *
127 */
128 vector<double> OOPSEMinimizer::getCoor(){
129
130 DirectionalAtom* dAtom;
131 int index;
132 double position[3];
133 double eulerAngle[3];
134 vector<double> x;
135
136 x.resize(getDim());
137
138 index = 0;
139
140 for(int i = 0; i < nAtoms; i++){
141 atoms[i]->getPos(position);
142
143 x[index++] = position[0];
144 x[index++] = position[1];
145 x[index++] = position[2];
146
147 if (atoms[i]->isDirectional()){
148 dAtom = (DirectionalAtom*) atoms[i];
149 dAtom->getEulerAngles(eulerAngle);
150
151 x[index++] = eulerAngle[0];
152 x[index++] = eulerAngle[1];
153 x[index++] = eulerAngle[2];
154
155 }
156
157 }
158
159 return x;
160
161 }
162
163 int OOPSEMinimizer::shakeR(){
164 int i, j;
165 int done;
166 double posA[3], posB[3];
167 double velA[3], velB[3];
168 double pab[3];
169 double rab[3];
170 int a, b, ax, ay, az, bx, by, bz;
171 double rma, rmb;
172 double dx, dy, dz;
173 double rpab;
174 double rabsq, pabsq, rpabsq;
175 double diffsq;
176 double gab;
177 int iteration;
178
179 for (i = 0; i < nAtoms; i++){
180 moving[i] = 0;
181 moved[i] = 1;
182 }
183
184 iteration = 0;
185 done = 0;
186 while (!done && (iteration < maxIteration)){
187 done = 1;
188 for (i = 0; i < nConstrained; i++){
189 a = constrainedA[i];
190 b = constrainedB[i];
191
192 ax = (a * 3) + 0;
193 ay = (a * 3) + 1;
194 az = (a * 3) + 2;
195
196 bx = (b * 3) + 0;
197 by = (b * 3) + 1;
198 bz = (b * 3) + 2;
199
200 if (moved[a] || moved[b]){
201 atoms[a]->getPos(posA);
202 atoms[b]->getPos(posB);
203
204 for (j = 0; j < 3; j++)
205 pab[j] = posA[j] - posB[j];
206
207 //periodic boundary condition
208
209 info->wrapVector(pab);
210
211 pabsq = pab[0] * pab[0] + pab[1] * pab[1] + pab[2] * pab[2];
212
213 rabsq = constrainedDsqr[i];
214 diffsq = rabsq - pabsq;
215
216 // the original rattle code from alan tidesley
217 if (fabs(diffsq) > (tol * rabsq * 2)){
218 rab[0] = oldPos[ax] - oldPos[bx];
219 rab[1] = oldPos[ay] - oldPos[by];
220 rab[2] = oldPos[az] - oldPos[bz];
221
222 info->wrapVector(rab);
223
224 rpab = rab[0] * pab[0] + rab[1] * pab[1] + rab[2] * pab[2];
225
226 rpabsq = rpab * rpab;
227
228
229 if (rpabsq < (rabsq * -diffsq)){
230 #ifdef IS_MPI
231 a = atoms[a]->getGlobalIndex();
232 b = atoms[b]->getGlobalIndex();
233 #endif //is_mpi
234 //cerr << "Waring: constraint failure" << endl;
235 gab = sqrt(rabsq/pabsq);
236 rab[0] = (posA[0] - posB[0])*gab;
237 rab[1]= (posA[1] - posB[1])*gab;
238 rab[2] = (posA[2] - posB[2])*gab;
239
240 info->wrapVector(rab);
241
242 rpab = rab[0] * pab[0] + rab[1] * pab[1] + rab[2] * pab[2];
243
244 }
245
246 //rma = 1.0 / atoms[a]->getMass();
247 //rmb = 1.0 / atoms[b]->getMass();
248 rma = 1.0;
249 rmb =1.0;
250
251 gab = diffsq / (2.0 * (rma + rmb) * rpab);
252
253 dx = rab[0] * gab;
254 dy = rab[1] * gab;
255 dz = rab[2] * gab;
256
257 posA[0] += rma * dx;
258 posA[1] += rma * dy;
259 posA[2] += rma * dz;
260
261 atoms[a]->setPos(posA);
262
263 posB[0] -= rmb * dx;
264 posB[1] -= rmb * dy;
265 posB[2] -= rmb * dz;
266
267 atoms[b]->setPos(posB);
268
269 moving[a] = 1;
270 moving[b] = 1;
271 done = 0;
272 }
273 }
274 }
275
276 for (i = 0; i < nAtoms; i++){
277 moved[i] = moving[i];
278 moving[i] = 0;
279 }
280
281 iteration++;
282 }
283
284 if (!done){
285 cerr << "Waring: can not constraint within maxIteration" << endl;
286 return -1;
287 }
288 else
289 return 1;
290 }
291
292
293 //remove constraint force along the bond direction
294 int OOPSEMinimizer::shakeF(){
295 int i, j;
296 int done;
297 double posA[3], posB[3];
298 double frcA[3], frcB[3];
299 double rab[3], fpab[3];
300 int a, b, ax, ay, az, bx, by, bz;
301 double rma, rmb;
302 double rvab;
303 double gab;
304 double rabsq;
305 double rfab;
306 int iteration;
307
308 for (i = 0; i < nAtoms; i++){
309 moving[i] = 0;
310 moved[i] = 1;
311 }
312
313 done = 0;
314 iteration = 0;
315 while (!done && (iteration < maxIteration)){
316 done = 1;
317
318 for (i = 0; i < nConstrained; i++){
319 a = constrainedA[i];
320 b = constrainedB[i];
321
322 ax = (a * 3) + 0;
323 ay = (a * 3) + 1;
324 az = (a * 3) + 2;
325
326 bx = (b * 3) + 0;
327 by = (b * 3) + 1;
328 bz = (b * 3) + 2;
329
330 if (moved[a] || moved[b]){
331
332 atoms[a]->getPos(posA);
333 atoms[b]->getPos(posB);
334
335 for (j = 0; j < 3; j++)
336 rab[j] = posA[j] - posB[j];
337
338 info->wrapVector(rab);
339
340 atoms[a]->getFrc(frcA);
341 atoms[b]->getFrc(frcB);
342
343 //rma = 1.0 / atoms[a]->getMass();
344 //rmb = 1.0 / atoms[b]->getMass();
345 rma = 1.0;
346 rmb = 1.0;
347
348
349 fpab[0] = frcA[0] * rma - frcB[0] * rmb;
350 fpab[1] = frcA[1] * rma - frcB[1] * rmb;
351 fpab[2] = frcA[2] * rma - frcB[2] * rmb;
352
353
354 gab=fpab[0] * fpab[0] + fpab[1] * fpab[1] + fpab[2] * fpab[2];
355
356 if (gab < 1.0)
357 gab = 1.0;
358
359 rabsq = rab[0] * rab[0] + rab[1] * rab[1] + rab[2] * rab[2];
360 rfab = rab[0] * fpab[0] + rab[1] * fpab[1] + rab[2] * fpab[2];
361
362 if (fabs(rfab) > sqrt(rabsq*gab) * 0.00001){
363
364 gab = -rfab /(rabsq*(rma + rmb));
365
366 frcA[0] = rab[0] * gab;
367 frcA[1] = rab[1] * gab;
368 frcA[2] = rab[2] * gab;
369
370 atoms[a]->addFrc(frcA);
371
372
373 frcB[0] = -rab[0] * gab;
374 frcB[1] = -rab[1] * gab;
375 frcB[2] = -rab[2] * gab;
376
377 atoms[b]->addFrc(frcB);
378
379 moving[a] = 1;
380 moving[b] = 1;
381 done = 0;
382 }
383 }
384 }
385
386 for (i = 0; i < nAtoms; i++){
387 moved[i] = moving[i];
388 moving[i] = 0;
389 }
390
391 iteration++;
392 }
393
394 if (!done){
395 cerr << "Waring: can not constraint within maxIteration" << endl;
396 return -1;
397 }
398 else
399 return 1;
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 < nAtoms; i++){
429 ndim += 3;
430 if (atoms[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. I
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 for (size_t i = 0; i < ndim; i++)
541 slopeA += curG[i]*direction[i];
542
543 initSlope = slopeA;
544
545 // if going uphill, use negative gradient as searching direction
546 if (slopeA > 0) {
547
548 if (bVerbose){
549 cout << "LineSearch Warning: initial searching direction is not a descent searching direction, "
550 << " use negative gradient instead. Therefore, finding a smaller vaule of function "
551 << " is guaranteed"
552 << endl;
553 }
554
555 for (size_t i = 0; i < ndim; i++)
556 direction[i] = -curG[i];
557
558 for (size_t i = 0; i < ndim; i++)
559 slopeA += curG[i]*direction[i];
560
561 initSlope = slopeA;
562 }
563
564 // Take a trial step
565 for(size_t i = 0; i < ndim; i++)
566 xc[i] = curX[i] + direction[i] * c;
567
568 calcG(xc, gc, fc, status);
569
570 if (status < 0){
571 if (bVerbose)
572 cerr << "Function Evaluation Error" << endl;
573 }
574
575 //calculate the derivative at c
576 slopeC = 0;
577 for (size_t i = 0; i < ndim; i++)
578 slopeC += gc[i]*direction[i];
579
580 // found a lower point
581 if (fc < fa) {
582 curX = xc;
583 curG = gc;
584 curF = fc;
585 return LS_SUCCEED;
586 }
587 else {
588
589 if (slopeC > 0)
590 stepSize *= 0.618034;
591 }
592
593 maxLSIter = paramSet->getLineSearchMaxIteration();
594
595 iter = 0;
596
597 do {
598 // Select a new trial point.
599 // If the derivatives at points a & c have different sign we use cubic interpolate
600 //if (slopeC > 0){
601 eta = 3 *(fa -fc) /(c - a) + slopeA + slopeC;
602 mu = sqrt(eta * eta - slopeA * slopeC);
603 b = a + (c - a) * (1 - (slopeC + mu - eta) /(slopeC - slopeA + 2 * mu));
604
605 if (b < lsTol){
606 if (bVerbose)
607 cout << "stepSize is less than line search tolerance" << endl;
608 break;
609 }
610 //}
611
612 // Take a trial step to this new point - new coords in xb
613 for(size_t i = 0; i < ndim; i++)
614 xb[i] = curX[i] + direction[i] * b;
615
616 //function evaluation
617 calcG(xb, gb, fb, status);
618
619 if (status < 0){
620 if (bVerbose)
621 cerr << "Function Evaluation Error" << endl;
622 }
623
624 //calculate the derivative at c
625 slopeB = 0;
626 for (size_t i = 0; i < ndim; i++)
627 slopeB += gb[i]*direction[i];
628
629 //Amijo Rule to stop the line search
630 if (fb <= curF + initSlope * ftol * b) {
631 curF = fb;
632 curX = xb;
633 curG = gb;
634 return LS_SUCCEED;
635 }
636
637 if (slopeB <0 && fb < fa) {
638 //replace a by b
639 fa = fb;
640 a = b;
641 slopeA = slopeB;
642
643 // swap coord a/b
644 std::swap(xa, xb);
645 std::swap(ga, gb);
646 }
647 else {
648 //replace c by b
649 fc = fb;
650 c = b;
651 slopeC = slopeB;
652
653 // swap coord b/c
654 std::swap(gb, gc);
655 std::swap(xb, xc);
656 }
657
658
659 iter++;
660 } while((fb > fa || fb > fc) && (iter < maxLSIter));
661
662 if(fb < curF || iter >= maxLSIter) {
663 //could not find a lower value, we might just go uphill.
664 return LS_ERROR;
665 }
666
667 //select the end point
668
669 if (fa <= fc) {
670 curX = xa;
671 curG = ga;
672 curF = fa;
673 }
674 else {
675 curX = xc;
676 curG = gc;
677 curF = fc;
678 }
679
680 return LS_SUCCEED;
681
682 }
683
684 void OOPSEMinimizer::minimize(){
685
686 int convgStatus;
687 int stepStatus;
688 int maxIter;
689 //int resetFrq;
690 //int nextResetIter;
691 int writeFrq;
692 int nextWriteIter;
693
694 if (bVerbose)
695 printMinimizerInfo();
696
697 init();
698
699 //resetFrq = paramSet->getResetFrq();
700 //nextResetIter = resetFrq;
701
702 writeFrq = paramSet->getWriteFrq();
703 nextWriteIter = writeFrq;
704
705 maxIter = paramSet->getMaxIteration();
706
707 for (curIter = 1; curIter <= maxIter; curIter++){
708
709 stepStatus = step();
710
711 if (stepStatus < 0){
712 saveResult();
713 minStatus = MIN_LSERROR;
714 cerr << "OOPSEMinimizer Error: line search error, please try a small stepsize" << endl;
715 return;
716 }
717
718 if (curIter == nextWriteIter){
719 nextWriteIter += writeFrq;
720 writeOut(curX, curIter);
721 }
722
723 //if (curIter == nextResetIter){
724 // reset();
725 // nextResetIter += resetFrq;
726 //}
727
728 convgStatus = checkConvg();
729
730 if (convgStatus > 0){
731 saveResult();
732 minStatus = MIN_CONVERGE;
733 return;
734 }
735
736 prepareStep();
737
738 }
739
740
741 if (bVerbose) {
742 cout << "OOPSEMinimizer Warning: "
743 << minimizerName << " algorithm did not converge within "
744 << maxIter << " iteration" << endl;
745 }
746 minStatus = MIN_MAXITER;
747 saveResult();
748
749 }

Properties

Name Value
svn:executable *