ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/branches/new_design/OOPSE-3.0/src/minimizers/OOPSEMinimizer.cpp
Revision: 1884
Committed: Tue Dec 14 19:08:44 2004 UTC (19 years, 7 months ago) by tim
File size: 19284 byte(s)
Log Message:
more fix in MPI version

File Contents

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

Properties

Name Value
svn:executable *