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

# User Rev Content
1 tim 1064 #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 tim 1074 preMove();
22 tim 1064 }
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 tim 1074 double lsTol;
522 tim 1064
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 tim 1074 lsTol = paramSet->getLineSearchTol();
538 tim 1064
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 tim 1074
605     if (b < lsTol){
606     if (bVerbose)
607     cout << "stepSize is less than line search tolerance" << endl;
608     break;
609     }
610 tim 1064 //}
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 *