ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/OOPSEMinimizer.cpp
Revision: 1144
Committed: Sat May 1 18:52:38 2004 UTC (20 years, 2 months ago) by tim
File size: 16191 byte(s)
Log Message:
C++ pass groupList to fortran

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

Properties

Name Value
svn:executable *