ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/minimizers/Minimizer.cpp
Revision: 1744
Committed: Tue Jun 5 18:07:08 2012 UTC (12 years, 10 months ago) by gezelter
File size: 19081 byte(s)
Log Message:
Fixes for minimization

File Contents

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

Properties

Name Value
svn:executable *
svn:keywords Author Id Revision Date