ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/OOPSEMinimizer.cpp
Revision: 1064
Committed: Tue Feb 24 15:44:45 2004 UTC (20 years, 4 months ago) by tim
File size: 15771 byte(s)
Log Message:
Using inherit instead of compose to implement Minimizer
both versions are working

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

Properties

Name Value
svn:executable *